接触Activity的时候有一个知识总是感觉用的地方不是特别多,但它也是Activity生命周期的一部分,那就是Activity的状态保存与恢复了,在生命周期中回调的方法是onSaveInstanceState和onRestoreInstanceState。那么什么时候我们需要用到它呢?
从字面意义上可判断场景如下:
1.关闭Activity(例如按下back键)
2.转向后台运行时(例如有电话打来、按下Home键等)
3.界面跳转
4.运行时配置发生变更(例如横竖屏切换)
... ...
Activity的生命周期方法处理入口在ActivityThread中,查看如下源码:
ActivityThread{
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
r.state = new Bundle();
r.state.setAllowFds(false);
if (r.isPersistable()) {
r.persistentState = new PersistableBundle();
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
}
}
}
Instrumentation{
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
activity.performSaveInstanceState(outState);
}
}
Activity{
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
}
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
}
}
PhoneWindow{
public Bundle saveHierarchyState() {
mContentParent.saveHierarchyState(states);
}
}
View{
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
// Log.i("View", "Freezing #" + Integer.toHexString(mID)
// + ": " + state);
container.put(mID, state);
}
}
}
protected Parcelable onSaveInstanceState() {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (mStartActivityRequestWho != null) {
BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
return state;
}
return BaseSavedState.EMPTY_STATE;
}
}
我们看到ActivityThread的callCallActivityOnSaveInstanceState方法会保存状态,往下看直到Activity的onSaveInstanceState,出现了我们熟悉的方法,这里源码中保存了PhoneWindow中所有View的状态,然后将WINDOW_HIERARCHY_TAG作为键保存到了bundle中。如果我们想在Activity中保存某些数据可以利用
outState存储。
mWindow.saveHierarchyState()最终会调用View的dispatchSaveInstanceState方法,如果设置了View的ID那么就会保存到SparseArray中,并且以mStartActivityRequestWho为标识符保存在BaseSavedState中,为了onRestoreInstanceState使用。
同理看下onRestoreInstanceState源码:
ActivityThread{
mInstrumentation.callActivityOnRestoreInstanceState
}
Instrumentation{
callActivityOnRestoreInstanceState{
activity.performRestoreInstanceState()
}
}
Activity{
final void performRestoreInstanceState(Bundle savedInstanceState) {
onRestoreInstanceState(savedInstanceState);
restoreManagedDialogs(savedInstanceState);
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}
}
PhoneWindow{
public void restoreHierarchyState(Bundle savedInstanceState) {
SparseArray<Parcelable> savedStates = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
if (savedStates != null) {
mContentParent.restoreHierarchyState(savedStates);
}
}
}
View{
public void restoreHierarchyState(SparseArray<Parcelable> container) {
dispatchRestoreInstanceState(container);
}
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID) {
Parcelable state = container.get(mID);
if (state != null) {
// Log.i("View", "Restoreing #" + Integer.toHexString(mID)
// + ": " + state);
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
onRestoreInstanceState(state);
}
}
}
protected void onRestoreInstanceState(Parcelable state) {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (state != null && !(state instanceof AbsSavedState)) {
throw IllegalArgumentException(... ...)
}
if (state != null && state instanceof BaseSavedState) {
mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved;
}
}
}
这些跟onSaveInstanceState方法相对应,注意一点是dispatchRestoreInstanceState方法中的state为空就不会调用onRestoreInstanceState,所以必须定义View一个ID才能恢复状态。
注意:
1.当我们自定义View的时候,如果有保存恢复状态的需求,重写这两个方法,并且super.onRestoreInstanceState(savedInstanceState);是一定要写的。
2.当我们在写Activity的时候,由于系统是自动保存视图层次结构的状态信息,也就说EditText等控件状态是默认保存的,只要我们给它设置一个ID,横竖屏切换状态也会保留之前的数据。
3.恢复数据:我们可以通过onCreate的参数bundle是否为空来判断是否保存了数据信息;或者通过回调方法onRestoreInstanceState恢复。
从字面意义上可判断场景如下:
1.关闭Activity(例如按下back键)
2.转向后台运行时(例如有电话打来、按下Home键等)
3.界面跳转
4.运行时配置发生变更(例如横竖屏切换)
... ...
Activity的生命周期方法处理入口在ActivityThread中,查看如下源码:
ActivityThread{
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
r.state = new Bundle();
r.state.setAllowFds(false);
if (r.isPersistable()) {
r.persistentState = new PersistableBundle();
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
}
}
}
Instrumentation{
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
activity.performSaveInstanceState(outState);
}
}
Activity{
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
}
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
}
}
PhoneWindow{
public Bundle saveHierarchyState() {
mContentParent.saveHierarchyState(states);
}
}
View{
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
// Log.i("View", "Freezing #" + Integer.toHexString(mID)
// + ": " + state);
container.put(mID, state);
}
}
}
protected Parcelable onSaveInstanceState() {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (mStartActivityRequestWho != null) {
BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
return state;
}
return BaseSavedState.EMPTY_STATE;
}
}
我们看到ActivityThread的callCallActivityOnSaveInstanceState方法会保存状态,往下看直到Activity的onSaveInstanceState,出现了我们熟悉的方法,这里源码中保存了PhoneWindow中所有View的状态,然后将WINDOW_HIERARCHY_TAG作为键保存到了bundle中。如果我们想在Activity中保存某些数据可以利用
outState存储。
mWindow.saveHierarchyState()最终会调用View的dispatchSaveInstanceState方法,如果设置了View的ID那么就会保存到SparseArray中,并且以mStartActivityRequestWho为标识符保存在BaseSavedState中,为了onRestoreInstanceState使用。
同理看下onRestoreInstanceState源码:
ActivityThread{
mInstrumentation.callActivityOnRestoreInstanceState
}
Instrumentation{
callActivityOnRestoreInstanceState{
activity.performRestoreInstanceState()
}
}
Activity{
final void performRestoreInstanceState(Bundle savedInstanceState) {
onRestoreInstanceState(savedInstanceState);
restoreManagedDialogs(savedInstanceState);
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}
}
PhoneWindow{
public void restoreHierarchyState(Bundle savedInstanceState) {
SparseArray<Parcelable> savedStates = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
if (savedStates != null) {
mContentParent.restoreHierarchyState(savedStates);
}
}
}
View{
public void restoreHierarchyState(SparseArray<Parcelable> container) {
dispatchRestoreInstanceState(container);
}
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID) {
Parcelable state = container.get(mID);
if (state != null) {
// Log.i("View", "Restoreing #" + Integer.toHexString(mID)
// + ": " + state);
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
onRestoreInstanceState(state);
}
}
}
protected void onRestoreInstanceState(Parcelable state) {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (state != null && !(state instanceof AbsSavedState)) {
throw IllegalArgumentException(... ...)
}
if (state != null && state instanceof BaseSavedState) {
mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved;
}
}
}
这些跟onSaveInstanceState方法相对应,注意一点是dispatchRestoreInstanceState方法中的state为空就不会调用onRestoreInstanceState,所以必须定义View一个ID才能恢复状态。
注意:
1.当我们自定义View的时候,如果有保存恢复状态的需求,重写这两个方法,并且super.onRestoreInstanceState(savedInstanceState);是一定要写的。
2.当我们在写Activity的时候,由于系统是自动保存视图层次结构的状态信息,也就说EditText等控件状态是默认保存的,只要我们给它设置一个ID,横竖屏切换状态也会保留之前的数据。
3.恢复数据:我们可以通过onCreate的参数bundle是否为空来判断是否保存了数据信息;或者通过回调方法onRestoreInstanceState恢复。