onSaveInstanceState () та onRestoreInstanceState ()


138

Я намагаюся зберегти та відновити стан Activityвикористовуваного методу onSaveInstanceState()та onRestoreInstanceState().

Проблема в тому, що він ніколи не входить в onRestoreInstanceState()метод. Хтось може мені пояснити, чому це?


1
@Nitin: дякую за те, що поділився посиланням ... це очистило для мене кілька речей +1
Taliadon

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 об'єктом є нульова бурулька.
BlaBRA

5
Якщо я правильно розумію, це ви робите: З B ви викликаєте startActivity (A). Тоді з A ви зателефонуєте до кінця (), щоб повернутися до 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, це також слід запускати при поверненні до діяльності з іншої діяльності. є безліч ситуацій, коли це вам потрібно.
masi

4
@masi вже існують інші методи, які викликаються на Активність, коли користувач повертається до нього (з іншої діяльності). OnSave / RestoreInstanceState () використовується для іншої конкретної мети, саме так.
superjos

8

Стан, в якому ви зберігаєте onSaveInstanceState(), пізніше буде доступним при onCreate()виклику методу. Тому використовуйте onCreate(і його Bundleпараметр) для відновлення стану вашої діяльності.


4

Як вирішення, ви можете зберігати пакет із даними, які ви хочете підтримувати, у намірі, який ви використовуєте для запуску діяльності А.

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

Діяльність A повинна буде повернути це назад у Activity 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 завжди викликається, коли на перший план виходить інша діяльність. Так і є наСтопі.

Однак onRestoreInstanceState викликався лише тоді, коли були також викликані onCreate і onStart. І, onCreate і onStart НЕ завжди викликалися.

Тому здається, що Android не завжди видаляє інформацію про стан, навіть якщо активність рухається на другий план. Однак він закликає методи життєвого циклу для збереження стану просто бути безпечними. Таким чином, якщо стан не видалено, 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 (). Система викликаєReRerereInstanceState (), тільки якщо є збережений стан для відновлення, тому вам не потрібно перевіряти, чи пакет недійсний :

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

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

IMO, це більш зрозумілий спосіб, ніж перевірка цього на 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

Я можу зробити так (вибачте, що це # не 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.