фрагмента Сохранение состояния активности Android с использованием состояния Save Instance




сохранение состояния activity (18)

Добавление LiveData (компонентов архитектуры Android) в ваш проект

добавить следующую зависимость

implementation "android.arch.lifecycle:extensions:1.1.0"

LiveData берет наблюдателя и уведомляет его об изменениях данных только тогда, когда он находится в состоянии «НАЧАЛО» или «ВОЗОБНОВЛЕНО». Преимущество LiveData заключается в том, что когда ваша деятельность переходит в любое состояние, отличное от НАЧАЛА РАБОТЫ или ВОЗВРАЩАЕТСЯ, он не будет вызывать метод onChanged на наблюдателе .

private TextView mTextView;
private MutableLiveData<String> mMutableLiveData;

@Override
protected void onCreate(Bundle savedInstanceState) {
    mTextView = (TextView) findViewById(R.id.textView);
    mMutableLiveData = new MutableLiveData<>();
    mMutableLiveData.observe(this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String s) {
            mTextView.setText(s);
        }
    });

}

https://code.i-harness.com

Я работал на платформе Android SDK, и немного неясно, как сохранить состояние приложения. Поэтому, учитывая эту небольшую переоснащение примера «Hello, Android»:

package com.android.hello;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

  private TextView mTextView = null;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mTextView = new TextView(this);

    if (savedInstanceState == null) {
       mTextView.setText("Welcome to HelloAndroid!");
    } else {
       mTextView.setText("Welcome back.");
    }

    setContentView(mTextView);
  }
}

Я думал, что этого будет достаточно для простейшего случая, но он всегда отвечает первым сообщением, независимо от того, как я перемещаюсь от приложения.

Я уверен, что решение так же просто, как переопределить onPause или что-то в этом роде, но я onPause в документации в течение 30 минут или около того и не нашел ничего очевидного.


Вам необходимо переопределить onSaveInstanceState(Bundle savedInstanceState) и записать значения состояния приложения, которые вы хотите изменить на параметр Bundle следующим образом:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.
  savedInstanceState.putBoolean("MyBoolean", true);
  savedInstanceState.putDouble("myDouble", 1.9);
  savedInstanceState.putInt("MyInt", 1);
  savedInstanceState.putString("MyString", "Welcome back to Android");
  // etc.
}

Bundle - это по существу способ хранения карты NVP («Name-Value Pair»), и она будет передана в onCreate() а также onRestoreInstanceState() где вы извлечете такие значения:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.
  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
  double myDouble = savedInstanceState.getDouble("myDouble");
  int myInt = savedInstanceState.getInt("MyInt");
  String myString = savedInstanceState.getString("MyString");
}

Обычно вы использовали эту технику для хранения значений экземпляра для вашего приложения (выбор, несохраненный текст и т. Д.).


Кажется, я нашел ответ. Позвольте мне рассказать, что я сделал простыми словами:

Предположим, у меня есть два вида деятельности, activity1 и activity2, и я перемещаюсь с activity1 на activity2 (я сделал некоторые работы в activity2) и снова вернулся к активности 1, нажав на кнопку в Activity1. Теперь на этом этапе я хотел вернуться к активности2, и я хочу увидеть свою активность2 в том же состоянии, когда я последний раз оставил activity2.

В приведенном выше сценарии я сделал то, что в манифесте я внес некоторые изменения следующим образом:

<activity android:name=".activity2"
          android:alwaysRetainTaskState="true"      
          android:launchMode="singleInstance">
</activity>

И в активности1 на событии нажатия кнопки я сделал вот так:

Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.setClassName(this,"com.mainscreen.activity2");
startActivity(intent);

И в activity2 при нажатии кнопки мыши я сделал следующее:

Intent intent=new Intent();
intent.setClassName(this,"com.mainscreen.activity1");
startActivity(intent);

Теперь произойдет то, что любые изменения, которые мы внесли в Activity2, не будут потеряны, и мы можем рассматривать activity2 в том же состоянии, что и раньше.

Я считаю, что это ответ, и это отлично работает для меня. Поправьте меня, если я ошибаюсь.


Мой коллега написал статью, объясняющую состояние приложения на устройствах Android, включая пояснения о жизненном SharedPreferences активности и информации о состоянии, сохранении информации о состоянии и сохранении в State Bundle и SharedPreferences и взгляните сюда .

В статье рассматриваются три подхода:

Хранить данные локального varible / UI для времени жизни приложения (т.е. временно) с использованием пакета State State State Bundle

[Code sample – Store State in State Bundle]
@Override
public void onSaveInstanceState(Bundle savedInstanceState) 
{
  // Store UI state to the savedInstanceState.
  // This bundle will be passed to onCreate on next call.  EditText txtName = (EditText)findViewById(R.id.txtName);
  String strName = txtName.getText().toString();

  EditText txtEmail = (EditText)findViewById(R.id.txtEmail);
  String strEmail = txtEmail.getText().toString();

  CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC);
  boolean blnTandC = chkTandC.isChecked();

  savedInstanceState.putString(“Name”, strName);
  savedInstanceState.putString(“Email”, strEmail);
  savedInstanceState.putBoolean(“TandC”, blnTandC);

  super.onSaveInstanceState(savedInstanceState);
}

Хранить данные локального переменного / пользовательского интерфейса между экземплярами приложения (т.е. постоянно) с использованием общих настроек

[Code sample – Store State in SharedPreferences]
@Override
protected void onPause() 
{
  super.onPause();

  // Store values between instances here
  SharedPreferences preferences = getPreferences(MODE_PRIVATE);
  SharedPreferences.Editor editor = preferences.edit();  // Put the values from the UI
  EditText txtName = (EditText)findViewById(R.id.txtName);
  String strName = txtName.getText().toString();

  EditText txtEmail = (EditText)findViewById(R.id.txtEmail);
  String strEmail = txtEmail.getText().toString();

  CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC);
  boolean blnTandC = chkTandC.isChecked();

  editor.putString(“Name”, strName); // value to store
  editor.putString(“Email”, strEmail); // value to store
  editor.putBoolean(“TandC”, blnTandC); // value to store    
  // Commit to storage
  editor.commit();
}

Сохранение экземпляров объектов в памяти между действиями в течение жизненного цикла приложения с использованием экземпляра остаточной неконфигурации

[Code sample – store object instance]
private cMyClassType moInstanceOfAClass;// Store the instance of an object
@Override
public Object onRetainNonConfigurationInstance() 
{
  if (moInstanceOfAClass != null) // Check that the object exists
      return(moInstanceOfAClass);
  return super.onRetainNonConfigurationInstance();
}

Обратите внимание, что НЕ безопасно использовать onSaveInstanceState и onRestoreInstanceState для постоянных данных в соответствии с документацией о состояниях деятельности в developer.android.com/reference/android/app/Activity.html .

В документе говорится (в разделе «Жизненный цикл активности»):

Обратите внимание, что важно сохранить постоянные данные в onPause() вместо onSaveInstanceState(Bundle) потому что позже не является частью обратных вызовов жизненного цикла, поэтому не будет вызываться в каждой ситуации, как описано в ее документации.

Другими словами, поместите код сохранения / восстановления для постоянных данных в onPause() и onResume() !

EDIT : для дальнейшего уточнения, вот документация onSaveInstanceState() :

Этот метод вызывается до того, как активность может быть убита, так что, когда она вернется через некоторое время в будущем, она сможет восстановить свое состояние. Например, если активность B запускается перед активностью A, и в какой-то момент активность A убивается для восстановления ресурсов, активность A будет иметь возможность сохранить текущее состояние своего пользовательского интерфейса с помощью этого метода, чтобы при возврате пользователя к активности A состояние пользовательского интерфейса может быть восстановлено через onCreate(Bundle) или onRestoreInstanceState(Bundle) .


Сохранение состояния в лучшем случае является kludge, насколько мне известно. Если вам нужно сохранить постоянные данные, просто используйте базу данных SQLite . Android делает его очень простым.

Что-то вроде этого:

import java.util.Date;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class dataHelper {

    private static final String DATABASE_NAME = "autoMate.db";
    private static final int DATABASE_VERSION = 1;

    private Context context;
    private SQLiteDatabase db;
    private OpenHelper oh ;

    public dataHelper(Context context) {
        this.context = context;
        this.oh = new OpenHelper(this.context);
        this.db = oh.getWritableDatabase();
    }

    public void close()
    {
        db.close();
        oh.close();
        db = null;
        oh = null;
        SQLiteDatabase.releaseMemory();
    }


    public void setCode(String codeName, Object codeValue, String codeDataType)
    {
        Cursor codeRow = db.rawQuery("SELECT * FROM code WHERE codeName = '"+  codeName + "'", null);
        String cv = "" ;

        if (codeDataType.toLowerCase().trim().equals("long") == true)
        {
            cv = String.valueOf(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("int") == true)
        {
            cv = String.valueOf(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("date") == true)
        {
            cv = String.valueOf(((Date)codeValue).getTime());
        }
        else if (codeDataType.toLowerCase().trim().equals("boolean") == true)
        {
            String.valueOf(codeValue);
        }
        else
        {
            cv = String.valueOf(codeValue);
        }

        if(codeRow.getCount() > 0) //exists-- update
        {
            db.execSQL("update code set codeValue = '" + cv +
                "' where codeName = '" + codeName + "'");
        }
        else // does not exist, insert
        {
            db.execSQL("INSERT INTO code (codeName, codeValue, codeDataType) VALUES(" +
                    "'" + codeName + "'," +
                    "'" + cv + "'," +
                    "'" + codeDataType + "')" );
        }
    }

    public Object getCode(String codeName, Object defaultValue)
    {
        //Check to see if it already exists
        String codeValue = "";
        String codeDataType = "";
        boolean found = false;
        Cursor codeRow  = db.rawQuery("SELECT * FROM code WHERE codeName = '"+  codeName + "'", null);
        if (codeRow.moveToFirst())
        {
            codeValue = codeRow.getString(codeRow.getColumnIndex("codeValue"));
            codeDataType = codeRow.getString(codeRow.getColumnIndex("codeDataType"));
            found = true;
        }

        if (found == false)
        {
            return defaultValue;
        }
        else if (codeDataType.toLowerCase().trim().equals("long") == true)
        {
            if (codeValue.equals("") == true)
            {
                return (long)0;
            }
            return Long.parseLong(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("int") == true)
        {
            if (codeValue.equals("") == true)
            {
                return (int)0;
            }
            return Integer.parseInt(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("date") == true)
        {
            if (codeValue.equals("") == true)
            {
                return null;
            }
            return new Date(Long.parseLong(codeValue));
        }
        else if (codeDataType.toLowerCase().trim().equals("boolean") == true)
        {
            if (codeValue.equals("") == true)
            {
                return false;
            }
            return Boolean.parseBoolean(codeValue);
        }
        else
        {
            return (String)codeValue;
        }
    }


    private static class OpenHelper extends SQLiteOpenHelper {

        OpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE IF  NOT EXISTS code" +
            "(id INTEGER PRIMARY KEY, codeName TEXT, codeValue TEXT, codeDataType TEXT)");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}

После этого простой вызов

dataHelper dh = new dataHelper(getBaseContext());
String status = (String) dh.getCode("appState", "safetyDisabled");
Date serviceStart = (Date) dh.getCode("serviceStartTime", null);
dh.close();
dh = null;

onSaveInstanceState() для временных данных (восстановлен в onCreate() / onRestoreInstanceState() ), onPause() для постоянных данных (восстановлен в onResume() ). Из технических ресурсов Android:

onSaveInstanceState () вызывается Android, если действие остановлено и может быть убито до его возобновления! Это означает, что он должен хранить любое состояние, необходимое для повторной инициализации в том же состоянии, когда операция перезапускается. Это аналог метода onCreate (), и фактически пакет savedInstanceState Bundle, переданный в onCreate (), представляет собой тот же Bundle, который вы создаете как outState в методе onSaveInstanceState ().

onPause () и onResume () также являются бесплатными методами. onPause () всегда вызывается, когда действие завершается, даже если мы спровоцировали это (например, с вызовом finish ()). Мы будем использовать это, чтобы сохранить текущую заметку в базе данных. Хорошая практика заключается в том, чтобы освободить любые ресурсы, которые могут быть выпущены во время onPause (), а также для уменьшения количества ресурсов в пассивном состоянии.


onSaveInstanceState вызывается, когда система нуждается в памяти и убивает приложение. Он не вызывается, когда пользователь просто закрывает приложение. Поэтому я думаю, что состояние приложения также должно быть сохранено в onPause Оно должно быть сохранено в некоторых постоянных хранилищах, таких как Preferences или Sqlite


Воспроизводство активности

Существует несколько сценариев, в которых ваша деятельность уничтожается из-за обычного поведения приложения, например, когда пользователь нажимает кнопку «Назад», или ваша активность сигнализирует о своем собственном разрушении, вызывая finish() . Система также может уничтожить вашу деятельность, если она в настоящее время остановлена ​​и не использовалась в течение длительного времени, или для работы переднего плана требуется больше ресурсов, поэтому система должна отключить фоновые процессы для восстановления памяти.

Когда ваша activity уничтожается, потому что пользователь нажимает «Назад» или activity заканчивается, концепция системы этого экземпляра Activity исчезает навсегда, потому что поведение указывает, что действие больше не требуется. Однако, если система уничтожает активность из-за системных ограничений (а не обычного поведения приложения), то, хотя фактический экземпляр Activity отсутствует, система помнит, что она существовала так, что если пользователь переходит к ней, система создает новый экземпляр действия с использованием набора сохраненных данных, который описывает состояние активности при ее destroyed . Сохраненные данные, которые система использует для восстановления предыдущего состояния, называются «состоянием экземпляра» и представляют собой набор пар ключ-значение, хранящихся в объекте Bundle.

Чтобы сохранить дополнительные данные о состоянии активности, вы должны переопределить метод обратного вызова onSaveInstanceState (). Система вызывает этот метод, когда пользователь покидает вашу активность и передает ему объект Bundle, который будет сохранен в случае неожиданного уничтожения вашей активности. Если система должна воссоздать экземпляр активности позже, он передает тот же объект Bundle как onRestoreInstanceState() и onCreate() .

Когда система начинает останавливать вашу деятельность, она вызываетSaveInstanceState onSaveInstanceState() (1), поэтому вы можете указать дополнительные данные состояния, которые вы хотите сохранить, в случае, если экземпляр Activity должен быть воссоздан. Если активность уничтожена и один и тот же экземпляр должен быть воссоздан, система передает данные состояния, определенные в (1), как onCreate() (2), так и onRestoreInstanceState() (3).

Сохранить состояние своей Activity

По мере того как ваше действие начинает останавливаться, система вызывает onSaveInstanceState() поэтому ваша активность может сохранять информацию о состоянии с помощью набора пар ключ-значение. Реализация этого метода по умолчанию сохраняет информацию о состоянии иерархии представлений активности, например, текст в EditText или позиции прокрутки ListView .

Чтобы сохранить дополнительную информацию о состоянии вашей деятельности, вы должны реализовать onSaveInstanceState() и добавить пары ключ-значение в объект Bundle. Например:

  static final String STATE_SCORE = "playerScore";
  static final String STATE_LEVEL = "playerLevel";

  @Override
  public void onSaveInstanceState(Bundle savedInstanceState) {
  // Save the user's current game state
  savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
  savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

  // Always call the superclass so it can save the view hierarchy state
  super.onSaveInstanceState(savedInstanceState);
}

Внимание! Всегда вызывайте реализацию суперкласса onSaveInstanceState() поэтому реализация по умолчанию может сохранять состояние иерархии представлений.

Восстановить состояние своей Activity

Когда ваша деятельность воссоздается после того, как она была ранее уничтожена, вы можете восстановить сохраненное состояние из пакета, который система передает вашу активность. Оба onCreate() обратного вызова onCreate() и onRestoreInstanceState() получают тот же Bundle который содержит информацию о состоянии экземпляра.

Поскольку метод onCreate() вызывается, создает ли система новый экземпляр вашей активности или воссоздает предыдущий, вы должны проверить, не является ли пул состояний пустым, прежде чем пытаться его прочитать. Если он равен нулю, то система создает новый экземпляр действия вместо восстановления предыдущего, который был уничтожен.

Например, вот как вы можете восстановить некоторые данные состояния в onCreate() :

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState); // Always call the superclass first

 // Check whether we're recreating a previously destroyed instance
 if (savedInstanceState != null) {
    // Restore value of members from saved state
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
 } else {
    // Probably initialize members with default values for a new instance
 }

 }

Вместо восстановления состояния во время onCreate() вы можете выбрать реализацию onRestoreInstanceState() , которую система вызывает после onStart() . Система вызывает onRestoreInstanceState() только в том случае, если есть восстановленное состояние, поэтому вам не нужно проверять, является ли Bundle равным null:

  public void onRestoreInstanceState(Bundle savedInstanceState) {
  // Always call the superclass so it can restore the view hierarchy
  super.onRestoreInstanceState(savedInstanceState);

  // Restore state members from saved instance
  mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
  mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Есть два способа реализовать это изменение.

  1. используя onSaveInstanceState()и onRestoreInstanceState().
  2. В манифесте android:configChanges="orientation|screenSize".

Я действительно не рекомендую использовать второй метод. Поскольку в одном из моих опытов он вызывал половину экрана устройства черным при повороте от портрета к пейзажу и наоборот.

Используя первый метод, упомянутый выше, мы можем сохранять данные при изменении ориентации или изменении конфигурации. Я знаю способ хранения данных любого типа в объекте состояния savedInstance.

Пример. Рассмотрим случай, если вы хотите сохранить объект Json. создать класс модели с геттерами и сеттерами.

class MyModel extends Serializable{
JSONObject obj;

setJsonObject(JsonObject obj)
{
this.obj=obj;
}

JSONObject getJsonObject()
return this.obj;
} 
}

Теперь в вашей деятельности в методе onCreate и onSaveInstanceState выполните следующее. Он будет выглядеть примерно так:

@override
onCreate(Bundle savedInstaceState){
MyModel data= (MyModel)savedInstaceState.getSerializable("yourkey")
JSONObject obj=data.getJsonObject();
//Here you have retained JSONObject and can use.
}


@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Obj is some json object 
MyModel dataToSave= new MyModel();
dataToSave.setJsonObject(obj);
oustate.putSerializable("yourkey",dataToSave); 

}

Код Котлина:

спасти:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState.apply {
        putInt("intKey", 1)
        putString("stringKey", "String Value")
        putParcelable("parcelableKey", parcelableObject)
    })
}

а затем в onCreate()илиonRestoreInstanceState()

    val restoredInt = savedInstanceState?.getInt("intKey") ?: 1 //default int
    val restoredString = savedInstanceState?.getString("stringKey") ?: "default string"
    val restoredParcelable = savedInstanceState?.getParcelable<ParcelableClass>("parcelableKey") ?: ParcelableClass() //default parcelable

Добавьте значения по умолчанию, если вы не хотите иметь опцию


Между тем я вообще вообще не использую

Bundle savedInstanceState & Co

живой цикл для большинства видов деятельности слишком сложный и не нужен. И google заявляет о себе, он даже не является надежным.

Мой способ - немедленно сохранить изменения в настройках

 SharedPreferences p;
 p.edit().put(..).commit()

в некотором смысле SharedPreferences работают аналогично Bundles. И естественно, и сначала такие ценности должны быть красными от предпочтений.

В случае сложных данных вы можете использовать Sqlite вместо использования настроек.

При применении этой концепции активность просто продолжает использовать последнее сохраненное состояние, независимо от того, была ли она открыта с перезагрузкой или повторным открытием из-за заднего стека.


Вот комментарий от ответа Стива Мозли ( ToolmakerSteve ), который ставит все в перспективе (в целом onSaveInstanceState vs onPause, стоимость восточного и западного саги)

@VVK - Я частично не согласен. Некоторые способы выхода из приложения не запускают onSaveInstanceState (oSIS). Это ограничивает полезность ОСШ. Его стоит поддерживать для минимальных ресурсов ОС, но если приложение хочет вернуть пользователя в состояние, в котором они находились, вне зависимости от того, как приложение было выведено, вместо этого необходимо использовать подход с постоянным хранилищем. Я использую onCreate для проверки пакета, и если он отсутствует, проверьте целостность хранилища. Это централизует принятие решений. Я могу восстановиться после сбоя, или выйти из задней кнопки или пользовательского пункта меню «Выход», или вернуться к пользователю экрана через несколько дней. - ToolmakerSteve Сен 19 '15 в 10:38


Моя проблема заключалась в том, что я нуждался в постоянстве только в течение срока действия приложения (то есть одного выполнения, включая запуск других под-действий в одном приложении и поворот устройства и т. Д.). Я пробовал различные комбинации вышеупомянутых ответов, но не получал того, что хотел во всех ситуациях. В конце концов, что работало для меня, было получить ссылку на savedInstanceState во время onCreate:

mySavedInstanceState=savedInstanceState;

и использовать это, чтобы получить содержимое моей переменной, когда мне это нужно, в соответствии с:

if (mySavedInstanceState !=null) {
   boolean myVariable = mySavedInstanceState.getBoolean("MyVariable");
}

Я использую onSaveInstanceStateи, onRestoreInstanceStateкак было предложено выше, но, я думаю, я мог бы или в качестве альтернативы использовать мой метод для сохранения переменной при ее изменении (например, при использовании putBoolean)


Ответ на исходный вопрос напрямую. savedInstancestate имеет значение null, потому что ваша активность никогда не воссоздается.

Ваша деятельность будет воссоздана только с помощью пакета состояний, когда:

  • Изменения конфигурации, такие как изменение ориентации или языка телефона, для которого может потребоваться создание нового экземпляра активности.
  • Вы вернетесь в приложение из фона после того, как ОС уничтожила действие.

Android будет уничтожать фоновые действия, когда под давлением памяти или после того, как они были в фоновом режиме в течение длительного периода времени.

При тестировании вашего приветственного примера мира есть несколько способов уйти и вернуться к Activity.

  • Когда вы нажмете кнопку «Назад», действие завершено. Повторное запуск приложения - это новый экземпляр. Вы не возобновляете с фона вообще.
  • Когда вы нажимаете кнопку «домой» или используете переключатель задач, «Активность» переходит в фоновый режим. При переходе назад к приложению onCreate будет вызываться только в том случае, если действие должно быть уничтожено.

В большинстве случаев, если вы просто нажимаете кнопку «домой», а затем снова запускаете приложение, активность не нужно будет воссоздавать. Он уже существует в памяти, поэтому onCreate () не будет вызываться.

В разделе Настройки -> Параметры разработчика есть опция «Не выполнять действия». Когда это будет включено, Android всегда будет уничтожать действия и воссоздавать их, когда они будут созданы. Это отличный вариант оставить включенным при разработке, поскольку он имитирует худший сценарий. (Устройство с низкой памятью постоянно перерабатывает ваши действия).

Другие ответы ценны тем, что они учат вас правильным способам хранения состояния, но я не чувствовал, что они действительно ответили. ПОЧЕМУ ваш код работал не так, как вы ожидали.


Простое решение этой проблемы - использование Icepick

Сначала настройте библиотеку в app/build.gradle

repositories {
  maven {url "https://clojars.org/repo/"}
}
dependencies {
  compile 'frankiesardo:icepick:3.2.0'
  provided 'frankiesardo:icepick-processor:3.2.0'
}

Теперь давайте посмотрим нижеприведенный пример, как сохранить состояние в Activity

public class ExampleActivity extends Activity {
  @State String username; // This will be automatically saved and restored

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState);
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState);
  }
}

Он работает для операций, фрагментов или любого объекта, который должен сериализовать свое состояние на Bundle (например, ViewPresenters)

Icepick также может генерировать код состояния экземпляра для пользовательских представлений:

class CustomView extends View {
  @State int selectedPosition; // This will be automatically saved and restored

  @Override public Parcelable onSaveInstanceState() {
    return Icepick.saveInstanceState(this, super.onSaveInstanceState());
  }

  @Override public void onRestoreInstanceState(Parcelable state) {
    super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state));
  }

  // You can put the calls to Icepick into a BaseCustomView and inherit from it
  // All Views extending this CustomView automatically have state saved/restored
}

Хотя принятый ответ верен, существует более быстрый и простой способ сохранения состояния активности на Android с помощью библиотеки Icepick . Icepick - это обработчик аннотации, который заботится обо всех шаблонах, используемых для сохранения и восстановления состояния.

Делать что-то подобное с Icepick:

class MainActivity extends Activity {
  @State String username; // These will be automatically saved and restored
  @State String password;
  @State int age;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState);
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState);
  }
}

То же самое, что и при этом:

class MainActivity extends Activity {
  String username;
  String password;
  int age;

  @Override
  public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("MyString", username);
    savedInstanceState.putString("MyPassword", password);
    savedInstanceState.putInt("MyAge", age); 
    /* remember you would need to actually initialize these variables before putting it in the
    Bundle */
  }

  @Override
  public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    username = savedInstanceState.getString("MyString");
    password = savedInstanceState.getString("MyPassword");
    age = savedInstanceState.getInt("MyAge");
  }
}

Icepick будет работать с любым объектом, который сохраняет свое состояние с помощью Bundle.


Чтобы получить данные состояния активности onCreate(), сначала необходимо сохранить данные в файле savedInstanceState путем переопределения SaveInstanceState(Bundle savedInstanceState)метода.

Когда вы вызываете SaveInstanceState(Bundle savedInstanceState)метод уничтожения активности, вы сохраняете данные, которые хотите сохранить. И вы получите то же самое, onCreate()когда перезагрузка активности. (SavedInstanceState не будет пустым, поскольку вы сохранили некоторые данные в нем до того, как действие будет уничтожено)







application-state