OnSaveInstanceState() и onRestoreInstanceState()

Я пытаюсь сохранить и восстановить состояние Activity с помощью методов onSaveInstanceState() и onRestoreInstanceState().

Проблема заключается в том, что он никогда не входит в метод onRestoreInstanceState(). Может ли кто-нибудь объяснить мне, почему это?

Ответ 1

Обычно вы восстанавливаете свое состояние в onCreate(). Можно восстановить его и в onRestoreInstanceState(), но не очень часто. (onRestoreInstanceState() вызывается после onStart(), тогда как onCreate() вызывается до onStart().

Используйте методы put для хранения значений в onSaveInstanceState():

protected void onSaveInstanceState(Bundle icicle) {
  super.onSaveInstanceState(icicle);
  icicle.putLong("param", value);
}

И восстановите значения в onCreate():

public void onCreate(Bundle icicle) {
  if (icicle != null){
    value = icicle.getLong("param");
  }
}

Вам не нужно сохранять состояния представления, поскольку они сохраняются автоматически, вызывая super.onSaveInstanceState(icicle);.

Ответ 2

onRestoreInstanceState() называется только при воссоздании активности после того, как ОС убила. Такая ситуация возникает, когда:

  • ориентация устройства изменяется (ваша деятельность разрушена и воссоздана)
  • есть еще одна активность перед вами, и в какой-то момент ОС убивает вашу активность, чтобы освободить память (например). В следующий раз, когда вы начнете свою деятельность, будет вызываться onRestoreInstanceState().

В отличие от этого: если вы находитесь в своей деятельности и нажали кнопку Back на устройстве, ваша деятельность будет завершена() ed (т.е. подумайте об этом как о выходе из настольного приложения), и при следующем запуске приложения оно будет запущено "свежий", т.е. без сохранения состояния, потому что вы намеренно вышли из него, когда вы нажмете Back.

Другим источником путаницы является то, что когда приложение теряет фокус на другое приложение, вызываемое onSaveInstanceState(), но когда вы переходите к своему приложению onRestoreInstanceState(), вы не можете его вызывать. Это случай, описанный в исходном вопросе, т.е. Если ваша активность НЕ была убита в период, когда другая активность была впереди onRestoreInstanceState(), не будет вызываться, потому что ваша активность в значительной степени "живая".

В целом, как указано в документации для onRestoreInstanceState():

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

Как я его прочитал: нет причин переопределять onRestoreInstanceState(), если вы не подклассифицируете Activity, и ожидается, что кто-то подклассифицирует ваш подкласс.

Ответ 3

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

Ответ 4

Я думаю, что эта тема была довольно старой. Я просто упоминаю еще один случай, что onSaveInstanceState() также будет вызываться, когда вы вызываете Activity.moveTaskToBack(boolean nonRootActivity).

Ответ 5

Главное, что если вы не храните в onSaveInstanceState(), то onRestoreInstanceState() не будет вызываться. Это основное различие между restoreInstanceState() и onCreate(). Убедитесь, что вы действительно что-то храните. Скорее всего, это ваша проблема.

Ответ 6

Я обнаружил, что onSaveInstanceState всегда вызывается, когда на передний план выходит другое действие. И так onStop.

Однако, onRestoreInstanceState вызывается только тогда, когда были вызваны onCreate и onStart. И, onCreate и onStart не всегда вызывались.

Итак, похоже, что Android не всегда удаляет информацию о состоянии, даже если Activity перемещается в фоновый режим. Тем не менее, он призывает методы жизненного цикла сохранять состояние только для того, чтобы быть в безопасности. Таким образом, если состояние не удалено, то Android не вызывает методы жизненного цикла для восстановления состояния, поскольку они не нужны.

Рисунок 2 описывает это.

Ответ 7

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

Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("bundle", theBundledData);
startActivity(intent);

Активность A должна была вернуть это значение в действие B. Вы должны получить намерение в методе ActivityC onCreate.

Intent intent = getIntent();
Bundle intentBundle;
if (intent != null)
    intentBundle = intent.getBundleExtra("bundle");
// Do something with the data.

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

Ответ 8

Если вы обрабатываете изменения ориентации активности с помощью android:configChanges="orientation|screenSize" и onConfigurationChanged(Configuration newConfig), onRestoreInstanceState() не будет вызываться.

Ответ 9

Не обязательно, чтобы onRestoreInstanceState всегда вызывался после onSaveInstanceState.

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

Ответ 10

В моем случае, onRestoreInstanceState был вызван, когда активность была восстановлена ​​после изменения ориентации устройства. onCreate(Bundle) был вызван первым, но у пучка не было ключа/значений, заданных с помощью onSaveInstanceState(Bundle).

Сразу после этого onRestoreInstanceState(Bundle) был вызван с пакетом, который имел правильный ключ/значения.

Ответ 11

Я просто столкнулся с этим и заметил, что в документации есть мой ответ:

"Эта функция никогда не будет вызываться с нулевым состоянием."

https://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)

В моем случае мне было интересно, почему onRestoreInstanceState не вызывается при первоначальной инстанцировании. Это также означает, что если вы ничего не храните, он не будет вызываться, когда вы переходите к восстановлению вашего представления.

Ответ 12

Я могу сделать это (извините, С# не java, но это не проблема...):

private int iValue = 1234567890;

function void MyTest()
{
Intent oIntent = new Intent (this, typeof(Camera2Activity));
Bundle oBundle = new Bundle();
oBundle.PutInt("MYVALUE", iValue); //=> 1234567890
oIntent.PutExtras (oBundle);
iRequestCode = 1111;
StartActivityForResult (oIntent, 1111);
}

И В ВАШЕЙ ДЕЯТЕЛЬНОСТИ ДЛЯ РЕЗУЛЬТАТОВ

private int iValue = 0;

protected override void OnCreate(Bundle bundle)
{
Bundle oBundle =  Intent.Extras;
if (oBundle != null)
{
iValue = oBundle.GetInt("MYVALUE", 0);
//=>1234567890
}
}

private void FinishActivity(bool bResult)
{
Intent oIntent = new Intent();
Bundle oBundle = new Bundle();
oBundle.PutInt("MYVALUE", iValue);//=>1234567890
oIntent.PutExtras(oBundle);
if (bResult)
    {
    SetResult (Result.Ok, oIntent);
    }
else
    SetResult(Result.Canceled, oIntent);
GC.Collect();
Finish();

}

НАКОНЕЦ

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
base.OnActivityResult (iRequestCode, oResultCode, oIntent);
iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}