savedInstanceState及onRestoreInstanceState
老样子,想了解该方法是干啥的,就先看源码吧~
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
Read the fucking source code~
/**
* Called to retrieve per-instance state from an activity before being killed
* so that the state can be restored in {@link #onCreate} or
* {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
* will be passed to both).
*
* <p>This method is called before an activity may be killed so that when it
* comes back some time in the future it can restore its state. For example,
* if activity B is launched in front of activity A, and at some point activity
* A is killed to reclaim resources, activity A will have a chance to save the
* current state of its user interface via this method so that when the user
* returns to activity A, the state of the user interface can be restored
* via {@link #onCreate} or {@link #onRestoreInstanceState}.
*
* <p>Do not confuse this method with activity lifecycle callbacks such as
* {@link #onPause}, which is always called when an activity is being placed
* in the background or on its way to destruction, or {@link #onStop} which
* is called before destruction. One example of when {@link #onPause} and
* {@link #onStop} is called and not this method is when a user navigates back
* from activity B to activity A: there is no need to call {@link #onSaveInstanceState}
* on B because that particular instance will never be restored, so the
* system avoids calling it. An example when {@link #onPause} is called and
* not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:
* the system may avoid calling {@link #onSaveInstanceState} on activity A if it isn't
* killed during the lifetime of B since the state of the user interface of
* A will stay intact.
*
* <p>The default implementation takes care of most of the UI per-instance
* state for you by calling {@link android.view.View#onSaveInstanceState()} on each
* view in the hierarchy that has an id, and by saving the id of the currently
* focused view (all of which is restored by the default implementation of
* {@link #onRestoreInstanceState}). If you override this method to save additional
* information not captured by each individual view, you will likely want to
* call through to the default implementation, otherwise be prepared to save
* all of the state of each view yourself.
*
* <p>If called, this method will occur before {@link #onStop}. There are
* no guarantees about whether it will occur before or after {@link #onPause}.
*
* @param outState Bundle in which to place your saved state.
*
* @see #onCreate
* @see #onRestoreInstanceState
* @see #onPause
*/
第一段说在从该activity被销毁之前获取其实例状态,以便于在onCreate或onRestoreInstanceState中通过存储在Bundle的数据得以恢复。
第二段说此方法在一个activity可能会被销毁之前被调用以便将来恢复该activity的状态。例如,当一个activityB位于activityA栈顶时,在某一时刻activityA因为内存不足被系统回收,activityA有机会在被销毁之前保存其当前状态,以便当用户返回到activityA时,销毁之前的界面数据可以得到恢复。
第三段说不要将此方法与activity生命周期中的onPause阶段的方法混淆,onPause通常是在一个activity被切换到后台或者被销毁的过程中调用,并且是在onStop之前被调用。
举个栗子,用户正常点击返回键从activityB返回到activityA时对activityB的销毁动作只会调用activityB的onPause和onStop而不会调用其onSaveInstanceState方法。因为系统知道activityB不会再被恢复了,所以没必要再执行onSaveInstanceState方法了。(记笔记啦,考点哦~)
另一个例子,当activityB处于activityA栈顶时,如果activityA一直没有被销毁,则系统也不会调用activityA的onSaveInstanceState方法。(记笔记啦,考点哦~)
第四段说该方法的默认实现方式侧重于通过在大多数、各层级的view的onSaveInstanceState方法中保存当前获取焦点的view的id,并且依旧通过onRestoreInstanceState方法恢复各层的view状态。如果你重写此方法来保存额外的信息而没有在每一个view中采用,你可以通过默认的实现方式,不然你就得对各个view重写方法逐个保存了。
第五段说如果有可能的话,该方法会在onStop之前被调用。但无法确定与onPause被调用的顺序。(记笔记啦,考点哦~)
所有保存的状态数据都将存储在Bundle中,而Bundle支持的类型就是该方法支持的存储数据类型。
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
Read the fucking source code~
/**
* This method is called after {@link #onStart} when the activity is
* being re-initialized from a previously saved state, given here in
* <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate}
* 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 {@link #onSaveInstanceState}.
*
* <p>This method is called between {@link #onStart} and
* {@link #onPostCreate}.
*
* @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
*
* @see #onCreate
* @see #onPostCreate
* @see #onResume
* @see #onSaveInstanceState
*/
第一段说此方法在当前activity被恢复成之前已保存的状态时调用,且是在onStart之后调用的。已保存的数据是通过savedInstanceState方法保存的。大多数实现方式是在onCreate恢复状态的。但是有时在完成初始化操作后或通过子类判断选择默认实现方式的情况下更方便调用onRestoreInstanceState方法恢复状态。此方法的默认实现是对所有之前已通过onSaveInstanceState保存状态的view进行恢复。
该方法是在onStart和onPostCreate之间被调用的。(onPostCreate是activity完全被启动后执行的动作,是系统对其完成初始化的标志)
两个方法的注释已经翻译完毕,大致的作用应该清楚了吧。下面说说通常如何使用它们吧~
案例就采用另一篇博客的吧~
activityA切换横屏时重绘一次activity,执行的生命周期阶段是:
D/ActivityA: onPause
D/ActivityA: onSaveInstanceState
D/ActivityA: onStop
D/ActivityA: onDestroy
D/ActivityA: ————————————————
D/ActivityA: onCreate
D/ActivityA: onStart
D/ActivityA: onRestoreInstanceState
D/ActivityA: onResume
这里activity切换横屏时被销毁之前执行了onSaveInstanceState,并且在重绘后执行了onRestoreInstanceState方法。所以在这两个方法里做activity状态的保存和恢复工作是最常用的。
activityA中部分代码如下:
...
public class ActivityA extends Activity {
private final static String TAG = "ActivityA";
private Button jumpToBt;
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (null != savedInstanceState) {
Log.d("onCreate", savedInstanceState.getString("save_something"));
}
initview();
}
...
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("save_something", "终于见到你啦,达令!");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d("onRestoreInstanceState", savedInstanceState.getString("save_something"));
}
...
}
当切换横屏时,执行结果如下:
D/ActivityA: onPause
D/ActivityA: onStop
D/ActivityA: onDestroy
D/ActivityA: ————————————————
D/onCreate: 终于见到你啦,达令!
D/ActivityA: onStart
D/onRestoreInstanceState: 终于见到你啦,达令!
D/ActivityA: onResume
可以见到当在onSaveInstanceState方法里数据保存后,activity重绘时会从onCreate和onRestoreInstanceState的Bundle中获取已保存的状态信息。表象的区别是onCreate里需要对Bundle做非空判断,而onRestoreInstanceState若被执行必不为null,并且谷歌推荐使用onRestoreInstanceState。
另外,在EditText的输入框中输入数据后,切换横屏重绘activity时,即使什么都没做,也会保证重绘后activity的EditText里的数据依旧。这是view内部也含有onSaveInstanceState和onRestoreInstanceState的保存恢复机制。
关于保存和恢复view层次结构,系统的工作流程是这样的:首先activity被意外终止时,activity会调用onSaveInstanceState去保存数据,然后activity会委托Window去保存数据,接着Window再委托它上面的顶级容器去保存数据。顶层容器是一个ViewGroup,一般来说它可能是DecorView。最后顶层容器再去一一通知它的子元素来保存数据,这样整个数据保存过程就完成了。可以发现,这是一种典型的委托思想,上层委托下层,父容器委托子元素去处理一件事情,这种思想在Android中很多应用,比如View的绘制过程、事件分发等都是采用类似的思想。至于数据恢复过程也是类似。
对于view源码解析和进一步实例验证,后续会补充的~