天天看点

Activity源码分析-状态保存及恢复

本文基于 Android 8.0 代码分析

状态的保存

onSaveInstanceState 调用时机

Activity 生命周期中,我们知道 onSaveInstanceState 方法在 onPause 方法之后执行在onStop方法之前执行。这里我们首先看一下onPause方法的源码逻辑。熟悉 Activity 启动过程就知道生命周期处理主要在 ActivityThread 中完成。

ActivityThread.java

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
                                  boolean saveState, String reason) {
    ...
    // 1. 
    if (!r.activity.mFinished && saveState) {
        // 2.
        callCallActivityOnSaveInstanceState(r);
    }
    // 该方法中会回调到 Activity 的 onPause 方法
    performPauseActivityIfNeeded(r, reason);
 	...
}
           

注释 1 处 r.activity.mFinished 为 false; saveState 查找传入参数位置知是 isPreHoneycomb的结果,小于 Android3.0 返回 true。

注释 2 处的方法就是调用 Activity 保存状态的方法 onSaveInstanceState 方法 ,且该方法执行先于 onPause 方法,关于该方法具体在后续分析。

从这里知道 在Android3.0 之前 onSaveInstanceState 回调是在 onPause 方法之前的。

继续 onStop 方法的调用过程

ActivityThread.java

final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();

private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
    // 1. 获取 ActivityClientRecord
    ActivityClientRecord r = mActivities.get(token);
    ...
    performStopActivityInner(r, info, show, true, "handleStopActivity");
}
private void performStopActivityInner(ActivityClientRecord r,
            StopInfo info, boolean keepShown, boolean saveState, String reason) {
    if (r != null) {
        ...
        // 2.
        if (!r.activity.mFinished && saveState) {
            if (r.state == null) {
                // 3. 执行 Activity 的 onSaveInstanceState 方法
                callCallActivityOnSaveInstanceState(r);
            }
        }

        if (!keepShown) {
            try {
                // 执行 Activity 的 onStop 方法
                r.activity.performStop(false /*preserveWindow*/);
            } ...
        }
    }
}

           

注释 1 处,mActivities 是 ArrayMap 集合,保存了 ActivityClientRecord,之后使用时只需 从 mActivities 中获取即可。

注释 2 处,r.activity.mFinished 依然为 false,saveState 查找传入参数发现直接传入的是 true,故该条件语句可以进入。

注释 3 处,该方法和前面提到的方法相同。

由此可知 在Android3.0 及以后 onSaveInstanceState 回调是在 onStop 方法之前的。

这里来看下 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);
    }
}
           
// Instrumentation.java
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
    activity.performSaveInstanceState(outState);
}
// Activity.java
final void performSaveInstanceState(Bundle outState) {
    // 1. 用于保存 Activity 状态
    onSaveInstanceState(outState);
    // 2. 会回调 管理的 Dialog 的 onSaveInstanceState 方法
    saveManagedDialogs(outState);
    mActivityTransitionState.saveState(outState);
    storeHasCurrentPermissionRequest(outState);
}
           

数据的保存还是通过 ActivityClientRecord 的 state 来保存数据,其是 Bundle 类型。下面看看 Activity 的 onSaveInstanceState 做了哪些事情。

protected void onSaveInstanceState(Bundle outState) {
    // 1. mWindow 就是 PhoneWindow
    outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
    outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
    // 2. mFragment 是 FragmentController,其内部还是操作 HostCallbacks 对象,HostCallbacks 在 Activity 中创建,且是Activity 内部类
    Parcelable p = mFragments.saveAllState();
    ...
}
           

该方法主要做了两件事:

  • View 体系状态的保存。
  • Fragment 的状态保存。

下面看下 View 和 Fragment 的状态分别是怎么保存的。

View 的状态保存

mWindow 就是 PhoneWindow

PhoneWindow.java

@Override
public Bundle saveHierarchyState() {
    Bundle outState = new Bundle();
    if (mContentParent == null) {
        return outState;
    }
	
    SparseArray<Parcelable> states = new SparseArray<Parcelable>();
    // 1. View 层级各个View的状态保存
    // mContentParent 就是 id 为 com.android.internal.R.id.content 的 View, 也就是 View 树中内容区域的根s布局
    mContentParent.saveHierarchyState(states);
    outState.putSparseParcelableArray(VIEWS_TAG, states);

    // 2. 保存已获取焦点View 的id
    final View focusedView = mContentParent.findFocus();
    if (focusedView != null && focusedView.getId() != View.NO_ID) {
        outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
    }

    // 3. 保存 Panel 状态
    SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
    savePanelState(panelStates);
    if (panelStates.size() > 0) {
        outState.putSparseParcelableArray(PANELS_TAG, panelStates);
    }
	...
    return outState;
}
           

这里主要看注释 1

// View.java
public void saveHierarchyState(SparseArray<Parcelable> container) {
    dispatchSaveInstanceState(container);
}
// ViewGroup.java   遍历所有子View调用其 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);
        }
    }
}
// View.java
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
        mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
        // 调用 onSaveInstanceState 保存状态
        Parcelable state = onSaveInstanceState();
        ...
    }
}
           

如果 View 存在 id,且没有禁用状态保存,都会回调其 onSaveInstanceState() 方法。 EditText 在我们不进行手动状态保存时,其文字依然可以保持,就是因为其父类 TextView 重写了 onSaveInstanceState 方法,完成状态的保存。对于有些 View 状态没有恢复就是因为其没有重写 onSaveInstanceState 方法。

Fragment 的状态保存

前面知道 Fragment 的状态保存是调用了 FragmentController 的 saveAllState 方法,这里就一睹风采。

// FragmentController.java
public Parcelable saveAllState() {
    return mHost.mFragmentManager.saveAllState();
}
           

mHost 就是 Activity 的内部类 HostCallbacks。 mFragmentManager 在其父类中创建,是FragmentManagerImpl。 FragmentManagerImpl 是 FragmentManager 的具体实现类。

FragmentManagerImpl.java

Parcelable saveAllState() {
    ...
    // 保存所有存活的 Fragment
    int N = mActive.size();
    FragmentState[] active = new FragmentState[N];
    boolean haveFragments = false;
    for (int i=0; i<N; i++) {
        Fragment f = mActive.valueAt(i);
        if (f != null) {
            haveFragments = true;
            FragmentState fs = new FragmentState(f);
            active[i] = fs;
			...
        }
    }
	...
    int[] added = null;
    BackStackState[] backStack = null;

    // 保存添加过的 Fragment 
    N = mAdded.size();
    if (N > 0) {
        added = new int[N];
        for (int i=0; i<N; i++) {
            added[i] = mAdded.get(i).mIndex;
        }
    }

    // 保存回退栈
    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));
            }
        }
    }

    FragmentManagerState fms = new FragmentManagerState();
    fms.mActive = active;
    fms.mAdded = added;
    fms.mBackStack = backStack;
    fms.mNextFragmentIndex = mNextFragmentIndex;
    if (mPrimaryNav != null) {
        fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
    }
    saveNonConfig();
    return fms;
}
           

状态的恢复

onRestoreInstanceState 调用时机

直接看 ActivityThread 的 performLaunchActivity

ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    	...
        if (activity != null) {
            ...
            // 1. 回调 Activity 的 onCreate 方法
            mInstrumentation.callActivityOnCreate(activity, r.state);
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                // 2. 回调 Activity 的 onStart 方法
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                                                            r.persistentState);
                    }
                } else if (r.state != null) {
                    // 3. 回调 Activity 的 onRestoreInstanceState 方法
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
        r.paused = true;
        // 4. 将 Activity 的信息记录对象存到 mActivities 中。
        mActivities.put(r.token, r);

    }...
    return activity;
}
           

可见 onRestoreInstanceState 会在存储数据不为空的情况下会被调用,调用顺序是在 onStart 方法之后,onResume 之前。

总结

  • 在 Android 3.0 以前:onSaveInstanceState 在 onPause 之前回调;Android3.0 及以后在 onPause 之后,onStop 之前调用(如果只进入 Paused 状态,不会执行 onSaveInstanceState)。
  • onRestoreInstanceState 调用必须在Bundle 中有数据时,且在 onStart 之后,onResume 之前调用。
  • Activity 中 的 onSaveInstanceState 方法中会通知 View 体系 及 Fragment 的分别进行状态保存。

参考

Android源码解析(二十四)–>onSaveInstanceState执行时机