OnSaveInstanceState()和 onRestoreInstanceState()

我试图使用 onSaveInstanceState()onRestoreInstanceState()方法来保存和恢复 Activity的状态。

问题是它从来没有进入 onRestoreInstanceState()方法。有人能解释一下为什么吗?

177421 次浏览

onSaveInstanceState()中保存的状态稍后在 onCreate()方法调用中可用。因此,使用 onCreate(及其 Bundle参数)来恢复活动的状态。

通常在 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");
}
}

onRestoreInstanceState()在被操作系统称为 被杀了之后被称为 只有在重建的时候活性。这种情况发生在:

  • 设备的方向改变(您的活动被销毁并重新创建)。
  • 在你面前还有另一个活动,在某个时刻,操作系统会杀死你的活动以释放内存(例如)。下次启动活动 onRestoreInstanceState ()时将被调用。

相比之下: 如果你在你的活动中,你点击设备上的 Back按钮,你的活动完成()(即认为它是退出桌面应用程序) ,下次你启动你的应用程序是“新鲜的”,即没有保存状态,因为你故意退出时,你点击 Back

另一个困惑的来源是,当一个应用程序失去焦点,另一个应用程序 onSaveInstanceState()被调用,但当您导航回到您的应用程序 onRestoreInstanceState()可能不会被调用。这是最初的问题中描述的情况,也就是说,如果你的活动在其他活动在前面的时期没有被杀死,那么 onRestoreInstanceState()将不会被调用,因为你的活动几乎是“活的”。

总而言之,正如 onRestoreInstanceState()的文档所述:

大多数实现将简单地使用 onCreate (Bundle)来恢复它们的 但是有时候在这里做比较方便 初始化已经完成或允许子类决定是否 使用默认实现 方法执行任何视图状态的还原 被 onSaveInstanceState (Bundle)冻结。

正如我读到的: 没有理由覆盖 onRestoreInstanceState(),除非你正在子类化 Activity,并且预计有人将子类化你的子类。

我觉得这条线很旧了。我刚才提到的另外一个例子,onSaveInstanceState()也会被调用,就是你调用 Activity.moveTaskToBack(boolean nonRootActivity)的时候。

主要的事情是,如果你不存储在 onSaveInstanceState()然后 onRestoreInstanceState()将不会被调用。这是 restoreInstanceState()onCreate()之间的主要区别。确保你真的存了东西。这很可能是你的问题。

在我的示例中,在更改设备方向后重新构建活动时调用 onRestoreInstanceState。首先调用了 onCreate(Bundle),但是包没有我用 onSaveInstanceState(Bundle)设置的键/值。

紧接着,使用具有正确键/值的 bundle 调用 onRestoreInstanceState(Bundle)

我发现,当另一个 Activity 出现在前台时,onSaveInstanceState 总是被调用,onStop 也是如此。

但是,只有在调用 onCreate 和 onStart 时才调用 onRestoreInstanceState。

所以看起来 Android 并不总是删除状态信息,即使活动移动到后台。但是,为了安全起见,它调用生命周期方法来保存状态。因此,如果状态没有被删除,那么 Android 不会调用生命周期方法来恢复状态,因为它们并不需要。

图2 描述了这一点。

作为一种解决方案,您可以将要维护的数据存储在用于启动活动 A 的意图中。

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

活动 A 必须将其传递回活动 B。您将在活动 B 的 onCreate 方法中检索意图。

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

另一个想法是创建一个存储库类来存储活动状态,并让每个活动引用该类(可以使用单例结构)不过,这样做可能会带来更多的麻烦,而不是它的价值。

如果您使用 android:configChanges="orientation|screenSize"onConfigurationChanged(Configuration newConfig)处理活动的方向变化,则不会调用 onRestoreInstanceState()

我碰巧看到这个,注意到文件上有我的答案:

“此函数将永远不会以空状态调用。”

Https://developer.android.com/reference/android/view/view.html#onrestoreinstancestate (android. os. Parcelable)

在我的例子中,我想知道为什么在初始化时没有调用 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
}

不需要总是在 onSaveInstanceState 之后调用 onRestoreInstanceState。

请注意: OnRestoreInstanceState 将始终被调用,当活动被旋转(当方向未被处理)或打开您的活动,然后打开其他应用程序,以便您的活动实例被操作系统从内存中清除。

从文件 使用保存的实例状态还原活动 UI 状态可以看出:

您可以选择不在 onCreate ()期间恢复状态 实现 onRestoreInstanceState () ,系统在 OnStart ()方法。系统仅在以下情况下调用 onRestoreInstanceState () 有一个保存的状态还原,所以你不需要检查 The Bundle is null :

enter image description here

enter image description here

IMO,这比在 onCreate 上检查这个更清楚,更符合单一责任原则。