onSaveInstanceState () и onRestoreInstanceState ()


138

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

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


1
@Nitin: спасибо, что поделились ссылкой ... это прояснило для меня несколько вещей +1
Талиадон

2
@NitinBansal ссылка мертвая.
ashishdhiman2007

Ответы:


191

Обычно вы восстанавливаете свое состояние в 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");
  }
}

2
проблема в том, что я использую startActivity для возврата к действию A. При возврате к действию B объект имеет значение null icicle.
BlaBRA 05

5
Если я правильно понимаю, это то, что вы делаете: из B вы вызываете startActivity (A). Затем из A вы вызываете finish (), чтобы вернуться в B. Верно? В этом случае ваше первое действие, B, не будет уничтожено, и ни onCreate (), ни onRestoreInstanceState () не будут вызваны. Эти методы вызываются только при необходимости, то есть когда действие было уничтожено и должно быть воссоздано системой.
Роберт

4
Я должен добавить, что ваше первое действие B может быть уничтожено из-за нехватки памяти. Это запустит onCreate и onRestoreInstanceState.
Роберт

1
erikb, да, действие B будет возобновлено, или в случае, если ОС восстановила его, воссоздаст и затем возобновит.
Роберт,


149

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

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

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

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

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

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

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


3
да, это кажется правильным, но это отстой. imo его также следует запускать при возврате к действию из другого действия. Есть много ситуаций, когда вам это нужно.
omni

4
@masi уже есть другие методы, вызываемые в Activity, когда пользователь возвращается к нему (из другого действия). OnSave / RestoreInstanceState () используется для другой конкретной цели, вот и все.
superjos

8

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


4

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

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

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

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

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


3

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


1
onRestoreInstanceState () будет вызываться, даже если вы ничего не храните в OnSaveInstanceState ()
abh22ishek

3

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

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

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

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


2

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


1

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


1

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

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


1

Из документации Восстановление состояния пользовательского интерфейса активности с использованием сохраненного состояния экземпляра указано как:

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

введите описание изображения здесь

введите описание изображения здесь

ИМО, это более понятный способ, чем проверка на onCreate, и он лучше соответствует принципу единой ответственности.


0

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

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


0

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

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

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

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


0

Я могу это сделать (извините, это C # не 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
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.