onSaveInstanceState () и onRestoreInstanceState ()
Я пытаюсь спасти и восстановить состояние Activity
используя методы onSaveInstanceState()
а также onRestoreInstanceState()
,
Проблема в том, что он никогда не входит в onRestoreInstanceState()
метод. Может кто-нибудь объяснить мне, почему это?
12 ответов
Обычно вы восстанавливаете свое состояние в 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);.
onRestoreInstanceState()
вызывается только при воссоздании активности после того, как она была убита ОС. Такая ситуация случается, когда:
- меняется ориентация устройства (ваша активность уничтожается и воссоздается)
- перед вами другое действие, и в какой-то момент ОС убивает ваше действие, чтобы освободить память (например). В следующий раз, когда вы начнете свою деятельность
onRestoreInstanceState()
будет называться.
Напротив: если вы в своей деятельности, и вы нажали Back
Кнопка на устройстве, ваша активность завершена ()ed (то есть думать о том, что она выходит из настольного приложения) и в следующий раз, когда вы запускаете приложение, оно запускается "свежим", то есть без сохраненного состояния, потому что вы намеренно вышли из него, когда вы нажмете Back
,
Другой источник путаницы заключается в том, что когда приложение теряет фокус на другое приложение onSaveInstanceState()
называется, но когда вы вернетесь к своему приложению onRestoreInstanceState()
может не называться. Это тот случай, который описан в первоначальном вопросе, то есть, если ваша деятельность НЕ была убита в тот период, когда другие действия были в начале onRestoreInstanceState()
НЕ будет вызван, потому что ваша деятельность в значительной степени "живая".
В целом, как указано в документации для onRestoreInstanceState()
:
Большинство реализаций просто используют onCreate(Bundle) для восстановления своего состояния, но иногда бывает удобно сделать это здесь после того, как была выполнена вся инициализация, или чтобы подклассы могли решить, использовать ли реализацию по умолчанию. Реализация этого метода по умолчанию выполняет восстановление любого состояния представления, которое ранее было заморожено с помощью onSaveInstanceState(Bundle).
Как я читаю: нет причин для переопределения onRestoreInstanceState()
если вы не подкласс Activity
и ожидается, что кто-то будет подкласс вашего подкласса.
Состояние, в котором вы сохраняете onSaveInstanceState()
позже доступен на onCreate()
вызов метода. Так что используйте onCreate
(И его Bundle
параметр), чтобы восстановить состояние вашей активности.
Из документации Восстановление состояния пользовательского интерфейса активности с использованием сохраненного состояния экземпляра указано как:
Вместо восстановления состояния во время onCreate() вы можете выбрать реализацию onRestoreInstanceState(), которую система вызывает после метода onStart(). Система вызывает onRestoreInstanceState() только в том случае, если есть сохраненное состояние для восстановления, поэтому вам не нужно проверять, является ли Bundle нулевым:
ИМО, это более понятный способ, чем проверка на onCreate, и он лучше соответствует принципу единой ответственности.
В качестве обходного пути вы можете сохранить пакет с данными, которые вы хотите сохранить, в Intent, который вы используете для запуска действия 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.
Другая идея состоит в том, чтобы создать класс репозитория для хранения состояния активности и сделать так, чтобы каждое из ваших действий ссылалось на этот класс (возможно, с использованием одноэлементной структуры). Хотя это, вероятно, доставляет больше хлопот, чем оно того стоит.
Главное, что если вы не храните в onSaveInstanceState()
затем onRestoreInstanceState()
не будет называться. Это главное различие между restoreInstanceState()
а также onCreate()
, Убедитесь, что вы действительно что-то храните. Скорее всего это ваша проблема.
Я обнаружил, что onSaveInstanceState всегда вызывается, когда другая активность выходит на передний план. И так же на стоп.
Однако onRestoreInstanceState вызывался только тогда, когда также вызывались onCreate и onStart. И onCreate и onStart НЕ всегда вызывались.
Поэтому кажется, что Android не всегда удаляет информацию о состоянии, даже если действие переходит в фоновый режим. Тем не менее, он вызывает методы жизненного цикла для сохранения состояния просто для безопасности. Таким образом, если состояние не удаляется, то Android не вызывает методы жизненного цикла для восстановления состояния, поскольку они не нужны.
Рисунок 2 описывает это.
Я думаю, что эта тема была довольно старой. Я просто упомянул еще один случай, onSaveInstanceState()
также будет называться, когда вы звоните Activity.moveTaskToBack(boolean nonRootActivity)
,
Нет необходимости, чтобы onRestoreInstanceState всегда вызывался после onSaveInstanceState.
Обратите внимание, что: onRestoreInstanceState всегда будет вызываться, когда действие поворачивается (когда ориентация не обрабатывается) или когда вы открываете свое действие, а затем открываете другие приложения, чтобы ваш экземпляр активности был удален из памяти ОС.
Если вы обрабатываете изменения ориентации действия с android:configChanges="orientation|screenSize"
а также onConfigurationChanged(Configuration newConfig)
, onRestoreInstanceState()
не будет называться.
В моем случае, onRestoreInstanceState
был вызван, когда деятельность была восстановлена после изменения ориентации устройства. onCreate(Bundle)
был вызван первым, но в комплекте не было ключа / значений, которые я установил onSaveInstanceState(Bundle)
,
Сразу после, onRestoreInstanceState(Bundle)
был вызван с пакетом, который имел правильный ключ / значения.
Я просто столкнулся с этим и заметил, что в документации был мой ответ:
"Эта функция никогда не будет вызываться с нулевым состоянием".
https://developer.android.com/reference/android/view/View.html
В моем случае мне было интересно, почему onRestoreInstanceState не вызывается при первоначальном создании. Это также означает, что если вы ничего не сохраняете, он не будет вызываться при восстановлении вашего представления.
Я могу сделать так (извините, это 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
}