Activity的onSaveInstanceState方法
先看一下官方文档:
/** * 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). * *
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}. * *
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. * *
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. * *
If called, this method will occur after {@link #onStop} for applications * targeting platforms starting with {@link android.os.Build.VERSION_CODES#P}. * For applications targeting earlier platform versions this method will occur * before {@link #onStop} and 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 */
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
getAutofillManager().onSaveInstanceState(outState);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
-
触发时机
当Activity被放到后台时回调,比如按HOME键或者打开新的Activity,注意按返回键是不会回调的。
-
回调时机
如果targetsdk>=P而且运行在P手机上,就在onStop之后回调;否则,在onStop之前回调, 但不保证是否在onPause之前或之后回调,目前测试发现都是在onPause之后回调。
-
原理分析
ActivityThread的callActivityOnStop方法:
private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) { // Before P onSaveInstanceState was called before onStop, starting with P it's // called after. Before Honeycomb state was always saved before onPause. final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null && !r.isPreHoneycomb(); final boolean isPreP = r.isPreP(); if (shouldSaveState && isPreP) { callActivityOnSaveInstanceState(r); } try { r.activity.performStop(false /*preserveWindow*/, reason); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to stop activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } r.setState(ON_STOP); if (shouldSaveState && !isPreP) { callActivityOnSaveInstanceState(r); } }
这里shouldSaveState用于判断是否需要回调,如果按back键返回,mFinished为true,就不会回调了。最终调用callActivityOnSaveInstanceState方法:
private void callActivityOnSaveInstanceState(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); } }
注意这里是outState被创建的地方,最终会保存到ActivityClientRecord中。Instrument的callActivityOnSaveInstanceState方法:
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) { 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方法了。其实onSaveInstanceState方法自己是有默认实现一些逻辑的:
protected void onSaveInstanceState(Bundle outState) { outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState()); outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId); Parcelable p = mFragments.saveAllState(); if (p != null) { outState.putParcelable(FRAGMENTS_TAG, p); } if (mAutoFillResetNeeded) { outState.putBoolean(AUTOFILL_RESET_NEEDED, true); getAutofillManager().onSaveInstanceState(outState); } getApplication().dispatchActivitySaveInstanceState(this, outState); }
首先会保存View相关信息,mWindow实际上是PhoneWindow对象,看看它的saveHierarchyState方法:
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其实就是布局的顶层ViewGroup,会调用其saveHierarchyState方法:
public void saveHierarchyState(SparseArray<Parcelable> container) { dispatchSaveInstanceState(container); }
ViewGroup和View的dispatchSaveInstanceState方法都有自己的实现,这一点跟Touch事件分发类似,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); } } }
首先会调用View的dispatchSaveInstanceState方法保存当前ViewGroup的信息,然后遍历子View,调用dispatchSaveInstanceState方法,看看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); } } }
可以看到,真正保存View信息的逻辑就在这里,如果View有自己的ID,就回调onSaveInstanceState方法,最终得到一个Parcelable对象,保存到SparseArray中,这里的哈希表,是以View的ID为key的。因此如果View没有设置ID,onSaveInstanceState也就不会被回调了。
回到最开始Activity的onSaveInstanceState默认实现,继续往下看,接着会保存Fragment的信息,这个先不深入分析,看最后调用Application的dispatchActivitySaveInstanceState方法:
/* package */ void dispatchActivitySaveInstanceState(Activity activity, Bundle outState) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { for (int i=0; i<callbacks.length; i++) { ((ActivityLifecycleCallbacks)callbacks[i]).onActivitySaveInstanceState(activity, outState); } } }
这个ActivityLifecycleCallbacks看起来很眼熟,没错它就是在Application中用来监听所有Activity生命周期的回调,可以看到,所有Activity的onSaveInstanceState,也会统一回调到这里。
Activity的onRestoreInstanceState方法
还是一样先看官方文档:
/** * This method is called after {@link #onStart} when the activity is * being re-initialized from a previously saved state, given here in * savedInstanceState. 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}. * *
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 */ protected void onRestoreInstanceState(Bundle savedInstanceState) { if (mWindow != null) { Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG); if (windowState != null) { mWindow.restoreHierarchyState(windowState); } } }
-
触发时机
当Activity被系统意外回收后,重新进入页面时会被回调。
-
回调时机
在onStart之后被回调,也就是 onStart --> onRestoreInstanceState --> onResume
-
与onCreate区别
主要的区别是参数问题,onCreate的savedInstanceState可能为空,使用时需要判断,而onRestoreInstanceState的savedInstanceState保证不为空。另外一个区别是回调时机不同,取决于要在哪个阶段进行恢复,如果要先在onCreate中做一些初始化后再恢复,就采用onRestoreInstanceState方法。
-
原理分析
ActivityThread的handleStartActivity方法:
@Override public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) { final Activity activity = r.activity; if (r.activity == null) { // TODO(lifecycler): What do we do in this case? return; } if (!r.stopped) { throw new IllegalStateException("Can't start activity that is not stopped."); } if (r.activity.mFinished) { // TODO(lifecycler): How can this happen? return; } // Start activity.performStart("handleStartActivity"); r.setState(ON_START); if (pendingActions == null) { // No more work to do. return; } // Restore instance state if (pendingActions.shouldRestoreInstanceState()) { if (r.isPersistable()) { if (r.state != null || r.persistentState != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } ...... }
可以看到,这里会先调用performStart方法,最终就是回调Activity的onStart方法,接着Instrumentation的callActivityOnRestoreInstanceState方法,在调用前会对r.state进行判空,也就是前面说的传入的参数保证不为空的原因。另外注意这个r.state其实就是上面onSaveInstanceState保存的那个Bundle对象。看看Instrumentation的callActivityOnRestoreInstanceState方法:
public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) { activity.performRestoreInstanceState(savedInstanceState); }
看Activity的performRestoreInstanceState方法:
final void performRestoreInstanceState(Bundle savedInstanceState) { onRestoreInstanceState(savedInstanceState); restoreManagedDialogs(savedInstanceState); }
然后就直接回调onRestoreInstanceState方法了:
protected void onRestoreInstanceState(Bundle savedInstanceState) { if (mWindow != null) { Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG); if (windowState != null) { mWindow.restoreHierarchyState(windowState); } } }
这里会取出之前保存的View信息windowState,然后调用PhoneWindow的restoreHierarchyState对View进行恢复,流程跟onSaveInstanceState保存View信息差不多,这里不再分析。