onSaveInstanceState()和onRestoreInstanceState()


138

我想保存和恢复的状态,Activity使用方法onSaveInstanceState()onRestoreInstanceState()

问题在于它永远不会进入onRestoreInstanceState()方法。谁能向我解释为什么?


1
@Nitin:感谢您分享链接...为我清除了一些内容+1
Taliadon 2013年

2
@NitinBansal链接已死。
ashishdhiman2007

Answers:


190

通常,您在中恢复状态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调用finish()返回B。在这种情况下,您的第一个活动B不会被销毁,并且onCreate()或onRestoreInstanceState()都不会被调用。仅在需要时(即活动已被破坏并且需要由系统重新创建时)才调用这些方法。
罗伯特2010年

4
我应该补充一点,由于内存不足,您的第一个活动B可能会被破坏。这将触发onCreate和onRestoreInstanceState。
罗伯特2010年

1
erikb,是的,将恢复活动B,或者如果OS回收了活动B,则将其重新创建然后恢复。
罗伯特


149

onRestoreInstanceState()仅在 OS 杀死活动后重新创建活动时才调用。在以下情况下会发生这种情况:

  • 设备的方向发生变化(您的活动被破坏并重新创建)。
  • 在您的面前还有另一项活动,并且操作系统有时会杀死您的活动以释放内存(例如)。下次启动活动时,将调用onRestoreInstanceState()。

相比之下:如果您正在活动中,并且Back在设备上单击了按钮,则活动已完成(即认为它正在退出桌面应用程序),而下次启动应用程序时,它将“新鲜”启动,即没有保存状态,因为您在点击时有意退出了状态Back

造成混淆的另一个原因是,当一个应用失去对另一个应用的关注时,onSaveInstanceState()将调用该方法,但是当您导航回该应用时,onRestoreInstanceState()可能不会被调用。这是原始问题中描述的情况,即,如果您的活动在“其他活动”之前没有被杀死,onRestoreInstanceState()则不会被调用,因为您的活动非常“活跃”。

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

大多数实现将只使用onCreate(Bundle)来恢复其状态,但是在完成所有初始化或允许子类决定是否使用默认实现之后,有时在这里这样做很方便。此方法的默认实现将还原以前由onSaveInstanceState(Bundle)冻结的任何视图状态。

如我所读:onRestoreInstanceState()除非您是子类化Activity,否则没有任何理由要重写,并且应该有人会子类化您的子类。


3
是的,这似乎是正确的,但是很糟糕。imo从另一个活动返回活动时也应运行它。在很多情况下,您需要这样做。
masi 2012年

4
@masi当用户从另一个活动返回活动时,已经在活动上调用了其他方法。onSave / RestoreInstanceStateState()用于其他特定目的。
superjos 2012年


4

作为解决方法,您可以将捆绑包和要维护的数据存储在用于启动活动A的Intent中。

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.

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


3

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


1
即使您不将任何内容存储在OnSaveInstanceState()中,也会调用onRestoreInstanceState()
abh22ishek 2015年

3

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

但是,仅当还调用了onCreate和onStart时才调用onRestoreInstanceState。而且,并非总是调用onCreate和onStart。

因此,即使Activity移至后台,Android似乎也不会总是删除状态信息。但是,为了安全起见,它调用了生命周期方法来保存状态。因此,如果未删除状态,则Android不会调用生命周期方法来还原状态,因为不需要它们。

图2对此进行了描述。


2

我认为这个线程已经很老了。我只提到另一种情况,onSaveInstanceState()也称为“当您致电” Activity.moveTaskToBack(boolean nonRootActivity)


1

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


1

不必总是在onSaveInstanceState之后调用onRestoreInstanceState。

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


1

在文档“使用保存的实例状态还原活动UI状态”中,其表示为:

您可以选择实现onRestoreInstanceState(),而不是在onCreate()期间恢复状态,系统在onStart()方法之后调用该方法。仅当存在要还原的保存状态时,系统才调用onRestoreInstanceState(),因此您无需检查 Bundle 是否为null

在此处输入图片说明

在此处输入图片说明

IMO,这是比在onCreate上进行检查更清晰的方法,并且更适合单一职责原则。


0

在我的情况下,onRestoreInstanceState在更改设备方向后重建活动时称为。onCreate(Bundle)首先被调用,但该捆绑包没有我设置的键/值onSaveInstanceState(Bundle)

之后,onRestoreInstanceState(Bundle)使用具有正确键/值的捆绑包进行了调用。



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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.