onSaveInstanceState() 和 onRestoreInstanceState()

Posted

技术标签:

【中文标题】onSaveInstanceState() 和 onRestoreInstanceState()【英文标题】:onSaveInstanceState () and onRestoreInstanceState () 【发布时间】:2011-05-05 00:21:10 【问题描述】:

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

问题是它永远不会进入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");
  

【讨论】:

问题是我使用startActivity返回活动A,返回活动B时,对象为null icicle。 如果我理解正确,这就是你正在做的事情:从 B 你调用 startActivity(A)。然后从 A 调用 finish() 以返回 B。对吗?在这种情况下,您的第一个活动 B 不会被销毁,并且 onCreate() 和 onRestoreInstanceState() 都不会被调用。这些方法仅在需要时调用,即当活动已被销毁并需要由系统重新创建时。 我应该补充一点,您的第一个活动 B 可能由于内存不足而被破坏。这将触发 onCreate 和 onRestoreInstanceState。 erikb,是的,活动 B 将被恢复,或者如果操作系统回收它,重新创建然后恢复。 Oh, this is why【参考方案2】:

onRestoreInstanceState() 仅在被操作系统杀死后重新创建活动时调用。这种情况发生在:

设备方向发生变化(您的活动被销毁并重新创建)。 您面前还有另一个活动,操作系统有时会终止您的活动以释放内存(例如)。下次您开始活动时,将调用 onRestoreInstanceState()。

相反:如果您在 Activity 中并点击设备上的 Back 按钮,您的 Activity 将完成()(即认为它是退出桌面应用程序),并且下次启动应用程序时它会启动“新鲜”,即没有保存状态,因为您在点击Back 时有意退出。

其他混淆来源是,当一个应用失去焦点到另一个应用时,onSaveInstanceState() 会被调用,但当您导航回您的应用时,onRestoreInstanceState() 可能不会被调用。这是原始问题中描述的情况,即如果您的活动在其他活动在前面的期间没有被杀死,onRestoreInstanceState() 将不会被调用,因为您的活动几乎是“活动的”。

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

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

正如我所读:没有理由重写onRestoreInstanceState(),除非您将Activity 子类化,并且预计有人会将您的子类子类化。

【讨论】:

是的,这似乎是对的,但它很糟糕。 imo 它也应该在从另一个活动返回到活动时运行。有很多情况需要这个。 @masi 当用户返回到它(从另一个活动)时,已经在 Activity 上调用了其他方法。 onSave/RestoreInstanceState() 用于另一个特定目的,就是这样。【参考方案3】:

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

【讨论】:

【参考方案4】:

作为一种解决方法,您可以在用于启动活动 A 的 Intent 中存储一个包含您想要维护的数据的包。

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

Activity A 必须将此传递回 Activity B。您将在 Activity B 的 onCreate 方法中检索 Intent。

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

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

【讨论】:

【参考方案5】:

从Restore activity UI state using saved instance state 的文档中可以看出:

您可以选择在 onCreate() 期间恢复状态,而不是恢复状态 实现onRestoreInstanceState(),系统在 onStart() 方法。系统仅在以下情况下调用 onRestoreInstanceState() 有一个保存状态可以恢复,所以你不需要检查是否 Bundle 为空

IMO,这比在 onCreate 中检查更清晰,更符合单一责任原则。

【讨论】:

【参考方案6】:

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

【讨论】:

onRestoreInstanceState() 将被调用,即使您没有在 OnSaveInstanceState() 中存储任何内容【参考方案7】:

我发现当另一个 Activity 进入前台时总是会调用 onSaveInstanceState。 onStop 也是如此。

但是,只有在同时调用了 onCreate 和 onStart 时才调用 onRestoreInstanceState。而且,onCreate 和 onStart 并不总是被调用。

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

Figure 2 对此进行了描述。

【讨论】:

【参考方案8】:

我认为这个线程很老了。我只是提到另一种情况,即onSaveInstanceState() 也将被调用,即当您调用Activity.moveTaskToBack(boolean nonRootActivity) 时。

【讨论】:

【参考方案9】:

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

【讨论】:

【参考方案10】:

onRestoreInstanceState 不一定总是在 onSaveInstanceState 之后调用。

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

【讨论】:

【参考方案11】:

在我的例子中,onRestoreInstanceState 在更改设备方向后重建活动时被调用。 onCreate(Bundle) 被首先调用,但捆绑包没有我使用 onSaveInstanceState(Bundle) 设置的键/值。

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

【讨论】:

【参考方案12】:

我刚刚遇到这个问题,并注意到文档中有我的答案:

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

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

就我而言,我想知道为什么在初始实例化时没有调用 onRestoreInstanceState。这也意味着如果你不存储任何东西,当你去重建你的视图时它不会被调用。

【讨论】:

【参考方案13】:

我可以这样做(对不起,它是 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()的主要内容,如果未能解决你的问题,请参考以下文章

究竟何时调用 onSaveInstanceState() 和 onRestoreInstanceState()?

onSaveInstanceState和onRestoreInstanceState

onActivityResult 中的操作和“错误在 onSaveInstanceState 之后无法执行此操作”

onSaveInstanceState和onRestoreInstanceState触发的时机

有关 onSaveInstanceState() 那点事

使用 onSaveInstanceState() 和 ViewModel 保存活动的状态