在Android中,当我们的Acitivity 被系统干掉的时候,会给我们一次保存数据的机会,我们通过可以通过这个机会来将需要的数据保存下来,然后在用户从新打开APP的时候,把这个数据恢复。
先来看一下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);
}
代码非常的简单,保存了3个对象的状态,分别是mWindow, mFragments和 Application 对象
mWindow的实际实现对象是PhoneWindow, 我们进入到 saveHierarchyState() 方法看看
/** {@inheritDoc} */
@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 的状态, 这个mContentParent 实际上就是在DecorView中 id 为 content的 ViewGroup, 我们setContetnView中添加的View就是放在了它的下面。mContentParent 是FrameLayout, 最终类型就是ViewGroup。先看看ViewGroup的父类 View怎么实现 saveHierarchyState .saveHierarchyState 调用了 dispatchSaveInstanceState,而这个方法是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);
}
}
}
实际上就是把onSaveInstanceState 放的返回值 保存了起来,在这里我们可以看到,这里是根据mID 也就是我们在布局文件为View指定的id来保存状态的,同时因为 SparseArray 是一个key ,value的键值对集合,所以这里,如果指定了相同的key,前面的key对应的view状态会被后来的覆盖掉,所以要尽量避免key的重复。
再来看 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);
}
}
}
ViewGroup 首先调用了View的dispatchSaveInstanceState 方法来保存自身的状态,然后调用了其子View 的dispatchSaveInstanceState 方法来保存 子view的 状态。这样最终的ViewTree的状态就被保存下来了。
Activity 把View的状态都存下来了之后,再开始存Fragment的状态
Fragment状态的保存实在FragmentManager的saveAllState()方法来完成的,在这个方法当中调用了
saveFragmentBasicState()方法,
Bundle saveFragmentBasicState(Fragment f) {
Bundle result = null;
if (mStateBundle == null) {
mStateBundle = new Bundle();
}
f.performSaveInstanceState(mStateBundle);
if (!mStateBundle.isEmpty()) {
result = mStateBundle;
mStateBundle = null;
}
if (f.mView != null) {
saveFragmentViewState(f);
}
if (f.mSavedViewState != null) {
if (result == null) {
result = new Bundle();
}
result.putSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
}
if (!f.mUserVisibleHint) {
if (result == null) {
result = new Bundle();
}
// Only add this if it's not the default value
result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
}
return result;
}
performSaveInstanceState 的代码如下
void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
if (mChildFragmentManager != null) {
Parcelable p = mChildFragmentManager.saveAllState();
if (p != null) {
outState.putParcelable(Activity.FRAGMENTS_TAG, p);
}
}
}
performSaveInstanceState onSaveInstanceState 方法,在这个方法里面我们可以保存自己想要保存的信息,之后又开始调用FragmentManamager 的 saveAllState()方法,就是递归调用了。跳出这个方法,接着看 saveFragmentViewState()
void saveFragmentViewState(Fragment f) {
if (f.mView == null) {
return;
}
if (mStateArray == null) {
mStateArray = new SparseArray<Parcelable>();
} else {
mStateArray.clear();
}
f.mView.saveHierarchyState(mStateArray);
if (mStateArray.size() > 0) {
f.mSavedViewState = mStateArray;
mStateArray = null;
}
}
关键的代码是 f.mView.saveHierarchyState(mStateArray);这个方法保存开始保存View的信息, 这个就是在开始分析的保存ViewTree那一部分的内容了。
在上面的内容保存完了还要保存当前已经添加的Fragment的信息,和回退栈的信息。
// Build list of currently added fragments.
if (mAdded != null) {
N = mAdded.size();
if (N > 0) {
added = new int[N];
for (int i=0; i<N; i++) {
added[i] = mAdded.get(i).mIndex;
if (added[i] < 0) {
throwException(new IllegalStateException(
"Failure saving state: active " + mAdded.get(i)
+ " has cleared index: " + added[i]));
}
if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
+ ": " + mAdded.get(i));
}
}
}
// Now save back stack.
if (mBackStack != null) {
N = mBackStack.size();
if (N > 0) {
backStack = new BackStackState[N];
for (int i=0; i<N; i++) {
backStack[i] = new BackStackState(this, mBackStack.get(i));
if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
+ ": " + mBackStack.get(i));
}
}
}
所以在Fragment保存的内容当中一共是当前active fragment的信息,已经添加的fragment 信息,和回退栈的信息,三部分
在回到Activity 的onSaveInstanceState 方法当中去,最后一步就是通知注册在Application当中的Activity 生命周期的回调。
onSaveInstanceState() 一般在onStop之前调用,再到ActivityThread的performStopActivity方法看看
final void performStopActivity(IBinder token, boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
performStopActivityInner(r, null, false, saveState, reason);
}
首先获取了了 一个 ActivityClientRecord 对象,然后在 performStopActivityInner 方法当中,根据saveState的值,会去调用 callCallActivityOnSaveInstanceState 方法
代码如下
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);
}
}
接着看 callActivityOnSaveInstanceState 方法,里面直接 调用了 activity.performSaveInstanceState(outState), 再回到Activity看performSaveInstanceState,
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
storeHasCurrentPermissionRequest(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}
调用了 onSaveInstanceState 这个就是前文分析的入口了,除了前文分析的保存的状态还保存了,dialog ,activity transaction, 权限相关的信息 ,这些信息都被存入了outState当中。而这个正是ActivityClientRecrod的成员变量之一,ActivityClientRecrod有最终被存在了 ActivityThread 的 mActivities 集合当中。
这里需要注意
现在保存的信息都分析完了,后面用户再回来的时候就需要将保存的信息再传给Activity,启动Acitivty在ActivityThread中的 performLaunchActivity 方法,
在这个方法当有如下代码
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
这里最终将ActivityClientRecord对象中保存的 state 在传递给 activity的 onCreate 方法,这样就可以在onCreate的时候实现对上一个Activity对象状态的恢复。