异常情况下Activity的生命周期
内存不足、系统参数改变(比如:屏幕旋转)、各种国产管家卫士(百度卫士、360卫士、腾讯管家)的一键清理都会让Activity被杀死,这种杀死和让Activity正常销毁的生命周期不同,根据 When are onSaveInstanceState() and onRestoreInstanceState() called, exactly? 中的回答:
- onSaveInstanceState Prior to Honeycomb, activities were not considered killable until after they had been paused, meaning that onSaveInstanceState() was called immediately before onPause(). Beginning with Honeycomb, however, Activities are considered to be killable only after they have been stopped, meaning that
onSaveInstanceState() will now be called before onStop() instead of immediately before onPause().- onRestoreInstanceState This method is called between onStart() and onPostCreate(Bundle) when the activity is being re-initialized from a previously saved state
绘制出在 Android 3.0 以上系统的Activity异常销毁生命周期流程图:
onSaveInstanceState和onRestoreInstanceState方法只有在Activity被异常杀死的时候才会被调用,那Activity状态的保存与恢复和自定义控件的状态保存与恢复之间是什么关系呢?
onSaveInstanceState
当Activity被异常销毁时,Activity的onSaveInstanceState会被调用
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
mWindow.saveHierarchyState()方法又会调用Window的saveHierarchyState()方法,PhoneWindow是Windown的唯一实现类,所以具体实现是PhoneWindow的saveHierarchyState():
@Override
public Bundle saveHierarchyState() {
Bundle outState = new Bundle();
if (mContentParent == null) {
return outState;
}
SparseArray<Parcelable> states = new SparseArray<Parcelable>();
mContentParent.saveHierarchyState(states);
outState.putSparseParcelableArray(VIEWS_TAG, states);
// Save the focused view ID.
final View focusedView = mContentParent.findFocus();
if (focusedView != null && focusedView.getId() != View.NO_ID) {
outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
}
// save the panels
SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
savePanelState(panelStates);
if (panelStates.size() > 0) {
outState.putSparseParcelableArray(PANELS_TAG, panelStates);
}
if (mDecorContentParent != null) {
SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
}
return outState;
}
该方法调用了 mContentParent.saveHierarchyState(states);来保存状态,mContentParent是一个ViewGroup,但是ViewGroup里面没有实现saveHierarchyState,所以会先调用它的父类View的saveHierarchyState:
public void saveHierarchyState(SparseArray<Parcelable> container) {
dispatchSaveInstanceState(container);
}
mContentParent是一个ViewGroup,而ViewGroup里重写了dispatchSaveInstanceState,所以会调用ViewGroup的dispatchSaveInstanceState:
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
View c = children[i];
if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
c.dispatchSaveInstanceState(container);
}
}
}
在setContentView的时候会把我们自己写的布局加载到mContentParent,所以遍历的是我们自己写的所有View,我们再看一下View里面的dispatchSaveInstanceState:
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);
}
}
}
- 调用onSaveInstanceState()获取保存的状态
- 通过PFLAG_SAVE_STATE_CALLED来保证我门在自定义控件中重写onSaveInstanceState的时候,要通过调用super.onSaveInstanceState来调用View的onSaveInstanceState
- 根据View的id来保存状态,所以对于需要保存状态的View要调用setId来设置一个id
onRestoreInstanceState(Bundle savedInstanceState)
当Activity被你重新创建时,如果Activity是被异常销毁的,那么会调用 Activity的onRestoreInstanceState:
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}
先取得销毁时在onSaveInstanceState里面保存的数据,然后会调用Window的restoreHierarchyState,具体实现方法:
@Override
public void restoreHierarchyState(Bundle savedInstanceState) {
if (mContentParent == null) {
return;
}
SparseArray<Parcelable> savedStates
= savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
if (savedStates != null) {
mContentParent.restoreHierarchyState(savedStates);
}
// restore the focused view
int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
if (focusedViewId != View.NO_ID) {
View needsFocus = mContentParent.findViewById(focusedViewId);
if (needsFocus != null) {
needsFocus.requestFocus();
} else {
Log.w(TAG,
"Previously focused view reported id " + focusedViewId
+ " during save, but can't be found during restore.");
}
}
// Restore the panels.
SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
if (panelStates != null) {
restorePanelState(panelStates);
}
if (mDecorContentParent != null) {
SparseArray<Parcelable> actionBarStates =
savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
if (actionBarStates != null) {
doPendingInvalidatePanelMenu();
mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
} else {
Log.w(TAG, "Missing saved instance states for action bar views! " +
"State will not be restored.");
}
}
}
mContentParent.restoreHierarchyState(savedStates);会调用View的restoreHierarchyState:
public void restoreHierarchyState(SparseArray<Parcelable> container) {
dispatchRestoreInstanceState(container);
}
又会调用ViewGroup的dispatchRestoreInstanceState:
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
super.dispatchRestoreInstanceState(container);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
View c = children[i];
if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
c.dispatchRestoreInstanceState(container);
}
}
}
通过调用super.dispatchRestoreInstanceState(container);先获取自己保存的状态,
然后遍历调用子view的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);
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onRestoreInstanceState()");
}
}
}
}
根据resId先取得当前View的state,然后调用View自己的onRestoreInstanceState,如果自定义控件就会重写onRestoreInstanceState,这里又通过检查PFLAG_SAVE_STATE_CALLED的状态,让用户通过super.onRestoreInstanceState强制调用父类View的onRestoreInstanceState:
@CallSuper
protected void onRestoreInstanceState(Parcelable state) {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (state != null && !(state instanceof AbsSavedState)) {
throw new IllegalArgumentException("Wrong state class, expecting View State but "
+ "received " + state.getClass().toString() + " instead. This usually happens "
+ "when two views of different type have the same id in the same hierarchy. "
+ "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "
+ "other views do not use the same id.");
}
if (state != null && state instanceof BaseSavedState) {
mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved;
}
}
实现一个具有状态保存与恢复功能的自定义控件
代码可以去我的Github查看:自带清空功能的编辑框