onSaveInstanceState() 和 onRestoreInstanceState()

发布于 2024-12-09 16:24:14 字数 197 浏览 0 评论 0原文

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

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

I'm trying to save and restore the state of an Activity using the methods onSaveInstanceState() and onRestoreInstanceState().

The problem is that it never enters the onRestoreInstanceState() method. Can anyone explain to me why this is?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

倦话 2024-12-16 16:24:14

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

Usually you restore your state in onCreate(). It is possible to restore it in onRestoreInstanceState() as well, but not very common. (onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart().

Use the put methods to store values in onSaveInstanceState():

protected void onSaveInstanceState(Bundle icicle) {
  super.onSaveInstanceState(icicle);
  icicle.putLong("param", value);
}

And restore the values in onCreate():

public void onCreate(Bundle icicle) {
  if (icicle != null){
    value = icicle.getLong("param");
  }
}
余生共白头 2024-12-16 16:24:14

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

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

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

另一个令人困惑的原因是,当一个应用程序失去焦点到另一个应用程序时,onSaveInstanceState() 会被调用,但当您导航回您的应用程序时,onRestoreInstanceState() 可能不会被调用。这是原始问题中描述的情况,即,如果您的活动在其他活动处于前面的期间没有被终止,则不会调用 onRestoreInstanceState() ,因为您的活动几乎是“活动的”。

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

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

据我阅读:没有理由重写 onRestoreInstanceState() 除非您子类化 Activity 并且预计有人会子类化您的子类。

onRestoreInstanceState() is called only when recreating activity after it was killed by the OS. Such situation happen when:

  • orientation of the device changes (your activity is destroyed and recreated).
  • there is another activity in front of yours and at some point the OS kills your activity in order to free memory (for example). Next time when you start your activity onRestoreInstanceState() will be called.

In contrast: if you are in your activity and you hit Back button on the device, your activity is finish()ed (i.e. think of it as exiting desktop application) and next time you start your app it is started "fresh", i.e. without saved state because you intentionally exited it when you hit Back.

Other source of confusion is that when an app loses focus to another app onSaveInstanceState() is called but when you navigate back to your app onRestoreInstanceState() may not be called. This is the case described in the original question, i.e. if your activity was NOT killed during the period when other activity was in front onRestoreInstanceState() will NOT be called because your activity is pretty much "alive".

All in all, as stated in the documentation for onRestoreInstanceState():

Most implementations will simply use onCreate(Bundle) to restore their
state, but it is sometimes convenient to do it here after all of the
initialization has been done or to allow subclasses to decide whether
to use your default implementation. The default implementation of this
method performs a restore of any view state that had previously been
frozen by onSaveInstanceState(Bundle).

As I read it: There is no reason to override onRestoreInstanceState() unless you are subclassing Activity and it is expected that someone will subclass your subclass.

听闻余生 2024-12-16 16:24:14

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

The state you save at onSaveInstanceState() is later available at onCreate() method invocation. So use onCreate (and its Bundle parameter) to restore state of your activity.

淑女气质 2024-12-16 16:24:14

从文档 使用保存的实例状态恢复 Activity UI 状态 如下所示:

您可以选择在 onCreate() 期间恢复状态,而不是
实现 onRestoreInstanceState(),系统在恢复后调用该方法
onStart() 方法。仅当以下情况时系统才会调用 onRestoreInstanceState()
有一个已保存的状态需要恢复,因此您不需要检查是否
捆绑包为空

在此处输入图像描述

在此处输入图像描述

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

From the documentation Restore activity UI state using saved instance state it is stated as:

Instead of restoring the state during onCreate() you may choose to
implement onRestoreInstanceState(), which the system calls after the
onStart() method. The system calls onRestoreInstanceState() only if
there is a saved state to restore, so you do not need to check whether
the Bundle is null:

enter image description here

enter image description here

IMO, this is more clear way than checking this at onCreate, and better fits with single responsiblity principle.

留蓝 2024-12-16 16:24:14

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

The main thing is that if you don't store in onSaveInstanceState() then onRestoreInstanceState() will not be called. This is the main difference between restoreInstanceState() and onCreate(). Make sure you really store something. Most likely this is your problem.

李白 2024-12-16 16:24:14

作为解决方法,您可以将包含要维护的数据的包存储在用于启动活动 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.

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

As a workaround, you could store a bundle with the data you want to maintain in the Intent you use to start activity A.

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

Activity A would have to pass this back to Activity B. You would retrieve the intent in Activity B's onCreate method.

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

Another idea is to create a repository class to store activity state and have each of your activities reference that class (possible using a singleton structure.) Though, doing so is probably more trouble than it's worth.

凉宸 2024-12-16 16:24:14

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

但是,只有当 onCreate 和 onStart 也被调用时,onRestoreInstanceState 才会被调用。并且,onCreate 和 onStart 并不总是被调用。

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

图 2 对此进行了描述。

I found that onSaveInstanceState is always called when another Activity comes to the foreground. And so is onStop.

However, onRestoreInstanceState was called only when onCreate and onStart were also called. And, onCreate and onStart were NOT always called.

So it seems like Android doesn't always delete the state information even if the Activity moves to the background. However, it calls the lifecycle methods to save state just to be safe. Thus, if the state is not deleted, then Android doesn't call the lifecycle methods to restore state as they are not needed.

Figure 2 describes this.

椒妓 2024-12-16 16:24:14

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

I think this thread was quite old. I just mention another case, that onSaveInstanceState() will also be called, is when you call Activity.moveTaskToBack(boolean nonRootActivity).

倾城月光淡如水﹏ 2024-12-16 16:24:14

如果您使用 android:configChanges="orientation|screenSize"onConfigurationChanged(Configuration newConfig) 处理 Activity 的方向更改,则 onRestoreInstanceState() 将不会称为。

If you are handling activity's orientation changes with android:configChanges="orientation|screenSize" and onConfigurationChanged(Configuration newConfig), onRestoreInstanceState() will not be called.

定格我的天空 2024-12-16 16:24:14

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

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

It is not necessary that onRestoreInstanceState will always be called after onSaveInstanceState.

Note that :
onRestoreInstanceState will always be called, when activity is rotated (when orientation is not handled) or open your activity and then open other apps so that your activity instance is cleared from memory by OS.

一萌ing 2024-12-16 16:24:14

就我而言,当更改设备方向后重建活动时,会调用 onRestoreInstanceState 。首先调用了 onCreate(Bundle),但该包没有我使用 onSaveInstanceState(Bundle) 设置的键/值。

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

In my case, onRestoreInstanceState was called when the activity was reconstructed after changing the device orientation. onCreate(Bundle) was called first, but the bundle didn't have the key/values I set with onSaveInstanceState(Bundle).

Right after, onRestoreInstanceState(Bundle) was called with a bundle that had the correct key/values.

三五鸿雁 2024-12-16 16:24:14

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

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

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

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

I just ran into this and was noticing that the documentation had my answer:

"This function will never be called with a null state."

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

In my case, I was wondering why the onRestoreInstanceState wasn't being called on initial instantiation. This also means that if you don't store anything, it'll not be called when you go to reconstruct your view.

孤独难免 2024-12-16 16:24:14

我可以这样做(抱歉,它是 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
}

I can do like that (sorry it's c# not java but it's not a problem...) :

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);
}

AND IN YOUR ACTIVITY FOR RESULT

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();
}

FINALLY

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文