onSaveInstanceState()和onRestoreInstanceState()
我正在尝试使用方法onSaveInstanceState()
和onRestoreInstanceState()
来保存和恢复Activity
的状态。
问题是它永远不会进入onRestoreInstanceState()
方法。 任何人都可以向我解释为什么这是?
通常你在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()
后重新创build活动时被调用。 这样的情况发生在:
- 设备的方向改变(你的活动被破坏和重新创build)
- 在你面前还有另一个活动,在某些时候,操作系统会杀死你的活动,以释放内存(例如)。 下一次当你开始你的活动时,将调用
onRestoreInstanceState()
。
相比之下,如果您正在进行活动,并且您在设备上点击了“ Back
button,则您的活动已完成(即将其视为正在退出桌面应用程序),并且下次启动应用程序时,它将开始“新鲜”没有保存的状态,因为你打Back
时故意退出它。
其他的混乱之处是,当一个应用程序失去焦点到另一个应用程序onSaveInstanceState()
被调用,但是当你回到你的应用程序onRestoreInstanceState()
可能不会被调用。 这是原始问题中描述的情况,也就是说,如果您的活动在其他活动在前面的时间内没有被杀死,那么onRestoreInstanceState()
将不会被调用,因为您的活动非常“活跃”。
总之,正如onRestoreInstanceState()
的文档中所述:
大多数实现只是简单地使用onCreate(Bundle)来恢复它们的状态,但是在完成所有的初始化或者允许子类决定是否使用你的默认实现之后,这样做有时候会很方便。 此方法的默认实现会执行之前由onSaveInstanceState(Bundle)冻结的任何视图状态的还原。
当我读到:没有理由重写onRestoreInstanceState()
除非你是子类化的Activity
,并期望有人会onRestoreInstanceState()
你的子类。
您在onSaveInstanceState()
保存的状态稍后会在onCreate()
方法调用时使用。 所以使用onCreate
(及其Bundle
参数)来恢复你的活动状态。
主要的是,如果你不存储onSaveInstanceState()
那么onRestoreInstanceState()
将不会被调用。 这是restoreInstanceState()
和onCreate()
之间的主要区别。 确保你真的存储了一些东西。 这很可能是你的问题。
我发现onSaveInstanceState总是在另一个Activity到达前台时被调用。 onStop也是如此。
但是,onRestoreInstanceState仅在onCreate和onStart也被调用时才被调用。 而且,onCreate和onStart并不总是被调用。
所以,即使Activity移动到后台,Android似乎并不总是删除状态信息。 但是,它调用生命周期方法来保存状态才是安全的。 因此,如果状态没有被删除,那么Android不会调用生命周期方法来恢复状态,因为它们不是必需的。
图2描述了这一点。
作为一种解决方法,您可以在您用来启动活动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.
另一个想法是创build一个存储库类来存储活动状态,并让您的每个活动引用该类(可能使用单例结构)。虽然这样做可能比它的价值更麻烦。
我认为这个线程是相当古老的。 我只是提到另一种情况,即onSaveInstanceState()
也将被调用,是当你调用Activity.moveTaskToBack(boolean nonRootActivity)
。
如果使用android:configChanges="orientation|screenSize"
和onConfigurationChanged(Configuration newConfig)
处理活动的方向更改,则不会调用onRestoreInstanceState()
。
在onSaveInstanceState之后总是调用onRestoreInstanceState并不是必须的。
请注意:当循环活动(未处理方向时)时,总是会调用onRestoreInstanceState,或者打开活动,然后打开其他应用程序,以便操作系统从内存中清除活动实例。
在我的情况下,在更改设备方向后重build活动时调用onRestoreInstanceState
。 首先调用onCreate(Bundle)
,但是bundle没有使用onSaveInstanceState(Bundle)
设置的键/值。
onRestoreInstanceState(Bundle)
, onRestoreInstanceState(Bundle)
被调用了一个包含正确键/值的包。
我刚碰到这个,并注意到文档有我的答案:
“这个函数永远不会被调用为null状态。”
在我的情况,我想知道为什么onRestoreInstanceState没有被初始实例化调用。 这也意味着如果你不存储任何东西,当你重新构build你的视图的时候不会被调用。
我可以这样做(对不起,这是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 }