Android InstanceState
Android 开发中我们常用 Activity,对 Activity 的生命周期也是了如指掌,然而我们往往会忽略两个方法, onSaveInstanceState()
和 onRestoreInstanceState()
,在开发过程中很少用到,但在有时候掌握其用法会帮我们起到比较好的效果。
基本作用
Activity 的 onSaveInstanceState()
和 onRestoreInstanceState()
并不是生命周期方法,它们不同于 onCreate()、onPause() 等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按 Home 键)由系统销毁一个 Activity 时, onSaveInstanceState()
会被调用。但是当用户主动去销毁一个 Activity 时,例如在应用中按返回键, onSaveInstanceState()
就不会被调用。因为在这种情况下,用户的行为决定了不需要保存 Activity 的状态。通常 onSaveInstanceState()
只适合用于保存一些临时性的状态,而 onPause() 适合用于数据的持久化保存。
在 activity 被杀掉之前调用保存每个实例的状态,以保证该状态可以在 onCreate(Bundle)
或者 onRestoreInstanceState(Bundle)
(传入的 Bundle 参数是由 onSaveInstanceState 封装好的) 中恢复。这个方法在一个 activity 被杀死前调用,当该 activity 在将来某个时刻回来时可以恢复其先前状态。
例如,如果 activity B 启用后位于 activity A 的前端,在某个时刻 activity A 因为系统回收资源的问题要被杀掉,A 通过 onSaveInstanceState 将有机会保存其用户界面状态,使得将来用户返回到 activity A 时能通过 onCreate(Bundle)
或者 onRestoreInstanceState(Bundle)
恢复界面的状态。
onSaveInstanceState() 什么时候调用
从这句话可以知道,当某个 activity 变得"容易"被系统销毁时,该 activity 的 onSaveInstanceState()
就会被执行,除非该 activity 是被用户主动销毁的,例如当用户按 BACK 键的时候。
注意上面的双引号,何为"容易"?意思就是说该 activity 还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个 activity 的所有生命周期的 onXXX 方法,包括 onSaveInstanceState() 和 onRestoreInstanceState()
方法,我们可以清楚地知道当某个 activity(假定为 activity A)显示在当前 task 的最上层时,其 onSaveInstanceState() 方法会在什么时候被执行,有这么几种情况:
- 当用户按下 HOME 键时
这是显而易见的,系统不知道你按下 HOME 后要运行多少其他的程序,自然也不知道 activity A 是否会被销毁,因此系统会调用 onSaveInstanceState()
,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
- 长按 HOME 键,选择运行其他的程序时
- 按下电源按键(关闭屏幕显示)时
- 从 activity A 中启动一个新的 activity 时
- 屏幕方向切换时,例如从竖屏切换到横屏时
在屏幕切换之前,系统会销毁 activity A,在屏幕切换之后系统又会自动地创建 activity A,所以 onSaveInstanceState() 一定会被执行,且也一定会执行 onRestoreInstanceState()。
总而言之, onSaveInstanceState()
的调用遵循一个重要原则,即当系统存在“未经你许可”时销毁了我们的 activity 的可能时,则 onSaveInstanceState()
会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。如果调用,调用将发生在 onPause()
或 onStop()
方法之前。(虽然测试时发现多数在 onPause()
前)
onRestoreInstanceState() 什么时候调用
onRestoreInstanceState()
被调用的前提是,activity A 确实
被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示 activity A 的时候,用户按下 HOME 键回到主界面,然后用户紧接着又返回到 activity A,这种情况下 activity A 一般不会因为内存的原因被系统销毁,故 activity A 的 onRestoreInstanceState
方法不会被执行 此也说明上二者,大多数情况下不成对被使用。
onRestoreInstanceState()
在 onStart()
和 onPostCreate(Bundle)
之间调用。
onSaveInstanceState()
方法的默认实现
如果我们没有覆写 onSaveInstanceState()
方法,此方法的默认实现会自动保存 activity 中的某些状态数据,比如 activity 中各种 UI 控件的状态.。android 应用框架中定义的几乎所有 UI 控件都恰当的实现了 onSaveInstanceState()
方法,因此当 activity 被摧毁和重建时,这些 UI 控件会自动保存和恢复状态数据。
比如 EditText 控件会自动保存和恢复输入的数据,而 CheckBox 控件会自动保存和恢复选中状态.开发者只需要为这些控件指定一个唯一的 ID(通过设置 android:id
属性即可),剩余的事情就可以自动完成了.如果没有为控件指定 ID,则这个控件就不会进行自动的数据保存和恢复操作。
由上所述,如果我们需要覆写 onSaveInstanceState()
方法,一般会在第一行代码中调用该方法的默认实现: super.onSaveInstanceState(outState)
。
是否需要重写 onSaveInstanceState()
方法
既然该方法的默认实现可以自动的保存 UI 控件的状态数据,那什么时候需要覆写该方法呢?
如果需要保存额外的数据时,就需要覆写 onSaveInstanceState()
方法。大家需要注意的是: onSaveInstanceState()
方法只适合保存瞬态数据,比如 UI 控件的状态,成员变量的值等,而不应该用来保存持久化数据,持久化数据应该当用户离开当前的 activity 时,在 onPause() 中保存(比如将数据保存到数据库或文件中)。说到这里,还要说一点的就是在 onPause()
中不适合用来保存比较费时的数据,所以这点要理解。
由于 onSaveInstanceState()
方法方法不一定会被调用,因此不适合在该方法中保存持久化数据,例如向数据库中插入记录等. 保存持久化数据的操作应该放在 onPause() 中。若是永久性值,则在 onPause() 中保存;若大量,则另开线程吧,别阻塞 UI 线程。
示例
我一般不习惯调用 onRestoreInstanceState 方法,而比较习惯在 onCreate
方法直接处理。
public class MainActivity extends Activity {
private String message = "";
private EditText text = null;
private Button button = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (EditText) findViewById(R.id.editText1);
button = (Button) findViewById(R.id.btnSave);
if (savedInstanceState != null)
message = savedInstanceState.getString("message");
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "保存", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResume(){
super.onResume();
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("message", text.getText().toString());
}
}
以上示例直接在 onCreate 方法中判断 savedInstanceState
是否为空,和直接在 onRestoreInstanceState
方法中处理作用一样。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: git submodule 的使用
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论