本文基于 Android8.0 源码
Android源码分析 - Parcel 与 Parcelable
Android特别的数据结构(二)ArrayMap源码解析
Android源码分析 —— Activity栈管理(基于Android8)
Android-全面理解Binder原理
Android从屏幕刷新到View的绘制(一)之 Window、WindowManager和WindowManagerService之间的关系
onSaveInstanceState(Bundle savedInstance) 是 Android 用来保存一些异常情况下(例如由横竖屏切换等)而导致 Activity 销毁的数据。通过这个方式来保持 Activity 状态的方式,可以在下次再次打开此 Activity 时恢复数据。当然,如果用户主动返回,例如 finish() 掉 Activity,或者按了 Home键,这是不会走 onSaveInstanceState() 方法的。
我们从源码的角度来看一下是在哪里发起 onSaveInstance() 的,来到 ActivityThread.java,AMS(ActivityManagerService)通过ApplicationThread给APP进程发送通知,调度Activity,关于Activity销毁,可能会走 onPause(),onStop(),onDestroy()。在performPauseActivity()和performStopActivity()中,在异常退出的情况下,会回调 onSaveInstanceState()
进行状态保存.
//ActivityThread.java
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,boolean saveState, String reason) {//...//如果finished为true,说明是用户主动退出的Activity,例如finish()方法,或者按了Home键。if (finished) {r.activity.mFinished = true;}if (!r.activity.mFinished && saveState) {//如果不是用户主动发起关闭的,而且需要保存状态,就调用保存方法callCallActivityOnSaveInstanceState(r);}//回调Activity的onPause()方法performPauseActivityIfNeeded(r, reason);//...return !r.activity.mFinished && saveState ? r.state : null;
}private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {if (r.paused) {//如果已经pause了,不用再回调onPause()了return;}try {r.activity.mCalled = false;//通过Instrumentation回调Activity组件的onPause()方法mInstrumentation.callActivityOnPause(r.activity);} catch (Exception e) {throw e;}r.paused = true;
}
可以看到,当 ActivityThread.java 收到对某个 Activity 的onPause()请求时,首先会判断 finished 变量,它表示了 Activity 是用户主动退出的,还是尤其其他情况导致的onPaused。如果是因为后者,也就是异常因素,就会进入到 callCallActivityOnSaveInstanceState(r)
方法保存状态,然后再进入到 Activity 的 onPause() 回调。
关注到 callCallActivityOnSaveInstanceState() 的内容:
//ActivityThread.java
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {//将数据存到 Bundle 中r.state = new Bundle();r.state.setAllowFds(false);//这个 persistable 是在配置文件中可以设置的属性,这个是持久化存储的能力,可以实现系统关机后重启的数据恢复能力。而普通的 savedInstanceState 只是存在了系统的内存中。if (r.isPersistable()) {r.persistentState = new PersistableBundle();mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,r.persistentState);} else {mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);}
}
其中,persistable是Android 5.0 提供的新的配置,在Manifest配置文件中,可以为 Activity 设置一个属性:
android:persistableMode="persistAcrossReboots|persistRootOnly|persistNever"
如果设置了这个值,在保存状态信息的时候除了保存在 r.state 这个 Bundle对象里,还会保存在 r.persistentState 这个 PersistableBundle对象中。简单来看一下是如何持久化存储的,显然要通过文件存储:
//PersistableBundle
public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {unparcel();XmlUtils.writeMapXml(mMap, out, this);
}public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException,
XmlPullParserException {final int outerDepth = in.getDepth();final String startTag = in.getName();final String[] tagName = new String[1];int event;while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&(event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {if (event == XmlPullParser.START_TAG) {return new PersistableBundle((ArrayMap)XmlUtils.readThisArrayMapXml(in, startTag, tagName,new MyReadMapCallback()));}}return EMPTY;
}@Override
public void writeUnknownObject(Object v, String name, XmlSerializer out)throws XmlPullParserException, IOException {if (v instanceof PersistableBundle) {out.startTag(null, TAG_PERSISTABLEMAP);out.attribute(null, "name", name);((PersistableBundle) v).saveToXml(out);out.endTag(null, TAG_PERSISTABLEMAP);} else {throw new XmlPullParserException("Unknown Object o=" + v);}
}
查看到其源码,发现是通过xml文件来进行的数据持久化存储。它相比Bundle额外实现了 XmlUtils.WriteMapCallback 接口。
三个结束Activity的生命周期中,都有保存状态的尝试,onStop也不例外。
//ActivityThread.java
private void performStopActivityInner(ActivityClientRecord r,StopInfo info, boolean keepShown, boolean saveState, String reason) {//...if (r != null) {//如果stop的时候发现activity连pause都还没有,会先进行pause,然后继续stop任务performPauseActivityIfNeeded(r, reason);//尝试保存状态信息if (!r.activity.mFinished && saveState) {if (r.state == null) {//如果不是用户主动退出的Activity,且之前没有保存过状态信息,这里会调用 onSaveInstanceState()进行保存。callCallActivityOnSaveInstanceState(r);}}//如果仍然可见,但是位于下方,则不会调用onStopif (!keepShown) {try {//回调onStop()方法r.activity.performStop(false /*preserveWindow*/);} catch (Exception e) {//...}r.stopped = true; }}
}
这里和onPause生命周期类似,都会尝试对状态信息进行保存。不同的是,如果之前已经保存过状态信息了(performPauseActivity()中已经保存过了),这里就不会再次保存,浪费资源。
在Destroy()的回调过程中,并没有执行状态保存,只是健壮性判断,如果之前没有调用过pause或者stop,就会调用,而在pause和stop过程中,就已经有过状态保存了。
在 handleDestroyActivity() 中,首先调用了 performDestroyActivity(),之后就开始了Activity的关闭,与WMS通信,通知当前ActivityWindow的关闭。接下来也会通过 ActivityManager.getService().activityDestroyed(token)
通知 AMS,同时将状态数据(ActivityClientRecord的数据)回传给AMS(中的ActivityRecord)。
//ActivityThread.java
private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,int configChanges, boolean getNonConfigInstance) {if (finishing) {r.activity.mFinished = true;}//如果还没pause,先pauseperformPauseActivityIfNeeded(r, "destroy");//如果还没stop,先stopr.activity.performStop(r.mPreserveWindow);//最后回调onDestorymInstrumentation.callActivityOnDestroy(r.activity);
}
也就是说,只要Activity要进行关闭,不论到stop还是Destroy,都会先尝试将pause的情况走完,也就是总会调用到 performPauseActivity(),而其中也总会尝试将state状态数据进行保存。
上文可以看到,最后通过Instrumentation发起了Activity的 onSaveInstanceState() , 它最终会保存:
我们首先看到调用入口 callCallActivityOnSaveInstanceState()
:
//ActivityThread.java
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的 performSaveInstanceState()
//Activity.java
final void performSaveInstanceState(Bundle outState) {//保存窗口信息、以及Fragment信息onSaveInstanceState(outState);//通知所有Dialog进行状态保存saveManagedDialogs(outState);mActivityTransitionState.saveState(outState);storeHasCurrentPermissionRequest(outState);
}protected void onSaveInstanceState(Bundle outState) {//保存窗口信息(保存View)outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);//保存所有Fragmet信息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);
}
我们主要关注保存了哪些数据,首先看到 mWindow.saveHierarchyState()
,Activity的Window只有PhoneWindow实现,我们直接看到PhoneWindow:
//PhoneWindow.java//这个是window content,要么是DecorView(没设置setContentView(),默认DecorView),要么是DecorView的孩子(setContentView())
ViewGroup mContentParent;@Override
public Bundle saveHierarchyState() {Bundle outState = new Bundle();if (mContentParent == null) {return outState;}//SparseArray来临时保存信息,这是一种Key为integer类型,Value为任意类型的数据结构,是Google为Android设计的内存优化的数据结构。SparseArray states = new SparseArray();//来到了ViewGroup的保存,显然这里只会保存DecorView,或者setContentView设置的视图mContentParent.saveHierarchyState(states);//包存到outState中outState.putSparseParcelableArray(VIEWS_TAG, states);//还需要保存获得焦点的是哪个View,保存它的idfinal View focusedView = mContentParent.findFocus();if (focusedView != null && focusedView.getId() != View.NO_ID) {outState.putInt(FOCUSED_ID_TAG, focusedView.getId());}// save the panelsSparseArray panelStates = new SparseArray();savePanelState(panelStates);if (panelStates.size() > 0) {outState.putSparseParcelableArray(PANELS_TAG, panelStates);}//ToolBar的信息也要保存if (mDecorContentParent != null) {SparseArray actionBarStates = new SparseArray();mDecorContentParent.saveToolbarHierarchyState(actionBarStates);outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);}return outState;
}
PhoneWindow会保存View的数据、Panel的数据、ToolBar的数据。我们关注到View数据的保存。它首先会通过 ViewGroup,这个要么是 DecorView,要么是用户通过 setContentView()
设置的一个 ViewGroup,调用其 mContentParent.saveHierarchyState()
,这在 View.java 中实现:
//View.java
public void saveHierarchyState(SparseArray container) {dispatchSaveInstanceState(container);
}protected void dispatchSaveInstanceState(SparseArray container) {//只要View有id,并且没有取消状态保存的标志,就可以被保存if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {//回调View的onSaveInstanceState()Parcelable state = onSaveInstanceState();if (state != null) {//将结果放到container中container.put(mID, state);}}
}
对于View本身而言,就是通过onSaveInstanceState()保存自身的状态,但是只看View.java本身的代码并没有保存什么信息,通常View级别的子类会将保存逻辑写在重写的onSaveInstanceState()
中。我们关注到它的实现类,例如TextView:
//TextView.java
@Override
public Parcelable onSaveInstanceState() {//先调用父类View的onSaveInstanceState()方法,拿到一个ParcelableParcelable superState = super.onSaveInstanceState();//这个boolean来自配置文件的 freezesText 标签设置final boolean freezesText = getFreezesText();boolean hasSelection = false;int start = -1;int end = -1;//CharSequence类型的mTextif (mText != null) {//如果有选择的起始点、终止点,说明之前有光标,记录光标和选中状态start = getSelectionStart();end = getSelectionEnd();if (start >= 0 || end >= 0) {hasSelection = true;}}//如果设置了freezesText标志,或者有选中状态,就进行文字的状态保存if (freezesText || hasSelection) {SavedState ss = new SavedState(superState);if (freezesText) {//如果是富文本的内容,按富文本的方式进行保存if (mText instanceof Spanned) {final Spannable sp = new SpannableStringBuilder(mText);if (mEditor != null) {removeMisspelledSpans(sp);sp.removeSpan(mEditor.mSuggestionRangeSpan);}ss.text = sp;} else {//如果是普通文本,直接存为String类型ss.text = mText.toString();}}//保存光标信息if (hasSelection) {ss.selStart = start;ss.selEnd = end;}if (isFocused() && start >= 0 && end >= 0) {ss.frozenWithFocus = true;}ss.error = getError();if (mEditor != null) {//如果有编辑器,同时也记录编辑器的状态信息ss.editorState = mEditor.saveInstanceState();}return ss;}return superState;
}
TextView的状态存储,首先调用了父类View的默认onSaveInstanceState()实现,然后将自己的数据填入其中,包括文本信息、光标选中状态、编辑器Editor。
View的子类ViewGroup则是重写了dispatchSaveInstanceState()
方法,就是收集其下所有子View的状态,进行综合保存。
@Override
protected void dispatchSaveInstanceState(SparseArray 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);}}
}
显然保存的数据存在Bundle中的,Bundle实现了Parcelable接口,我们能猜到最终这个数据会包存到某个内存中。继续猜测,APP进程可能会被杀,而且Activity的发起实际是通过AMS,我们也能够猜到这个数据是存在AMS所在进程的内存空间中。后续代码跟踪也证实了这一点:
我们回顾到最初发起 onSaveInstanceState 的地方:
//ActivityThread.java
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);}
}
显然,我们最终将所有状态信息写到了这个 ActivityClientRecord 对象中。最后通过AMS上报生命周期状态(同时也上报了状态信息)
//ActivityThread.java
private void handlePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport, int seq) {//...ActivityClientRecord r = mActivities.get(token);//...performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");//...ActivityManager.getService().activityPaused(token);
}
可以看到,最后将存储后的内容交给了AMS,所有的信息保存在了AMS的ActivityRecord之中。假设Activity所在的进程被杀了,或者旋转屏幕了,再次启动这个Activity的时候,AMS复用之前的ActivityRecord,并从其中得到之前保存的数据。换句话说,存的这些状态数据,保存在了SystemServer进程中。
留存疑问,如果Activity的启动模式是SingleTask,是否会复用之前的ActivityRecord?如果是,那么保存的状态信息是否丢失了?
Activity的 onRestoreInstanceState()
方法,在ActivityThread.java中,通过 performLaunchActivity() 方法进行回调:
//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {//1.activity.attach主要是创建Windowactivity.attach(...);//2.activity.onCreat(),分为是否persistableif(r.isPersistable()){mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);}else{mInstrumentation.callActivityOnCreate(activity, r.state);}//onStart()方法if (!r.activity.mFinished) {activity.performStart();r.stopped = false;}//r.state!=null的话,说明之前异常退出,会回调onRestoreInstanceState()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) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}
}
如果这个Activity是第一次进入,之前并没有异常退出,那么r.state就是空的,调用到 onCreate() 时传入的 Bundle savedInstanceState 也就是空的。同样的,如果之前没有异常退出,r.persistentState也是空的。
如果之前异常退出了(或者屏幕旋转了),那么r.state就非空,在onCreate()中可以获取到其内容,接下来也将回调 onRestoreInstanceState()
。
onRestoreInstanceState() 默认实现是恢复window的信息:
//Activity.java
protected void onRestoreInstanceState(Bundle savedInstanceState) {if (mWindow != null) {Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);if (windowState != null) {//恢复windowmWindow.restoreHierarchyState(windowState);}}
}
PhoneWindow.restoreHierarchyState()
也是通过DecorView或者ViewGroup来进行视图数据恢复:
//PhoneWindow.java
@Override
public void restoreHierarchyState(Bundle savedInstanceState) {if (mContentParent == null) {return;}SparseArray savedStates= savedInstanceState.getSparseParcelableArray(VIEWS_TAG);if (savedStates != null) {//View数据恢复mContentParent.restoreHierarchyState(savedStates);}//焦点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();}}//Panels恢复SparseArray panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);if (panelStates != null) {restorePanelState(panelStates);}//Toolbar数据恢复if (mDecorContentParent != null) {SparseArray actionBarStates =savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);if (actionBarStates != null) {doPendingInvalidatePanelMenu();mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);}}
}
通过重写 onSaveInstanceState()
方法,往bundle中存入额外数据,需要注意的是,这个bundle最后也是要通过binder通信发送到AMS的,所以数据量不能太多:
//MyActivity.java
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState){//调用父类的方法(父类默认实现了View视图的状态保存)super.onSaveInstanceState(outState,outPersistentState);outStte.putString("test",str);
}
可以在 onRestoreInstanceState()
中进行恢复:
@Override
public void onRestoreInstanceState(Bundle savedInstanceState,PersistableBundle persistentState){//调用父类的方法(父类默认实现了View状态的恢复)super.onRestoreInstanceState(savedInstanceState,persistentState);str = savedInstanceState.getString("temp");
}
也可以在 onCreate()
中进行恢复(检查Bundle是否为空):
@Override
protected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if(savedInstance != null){//之前有状态数据信息保存,可能还有自己额外保存的数据str = savedInstanceState.getString("temp");}
}
MainActivity如下
public class MainActivity extends AppCompatActivity {private static final String TAG = "Fy_MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.e(TAG,"onCreate");}//所有生命周期都打印//...@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);Log.e(TAG,"onSaveInstanceState");outState.putString("test","im Tu Fengyi");}@Overrideprotected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);String s = savedInstanceState.getString("test");Log.e(TAG,"onRestoreInstanceState gets s:"+s);}
}
旋转屏幕后,打印结果为:(Android8.0):
onCreate
onStart
onResumeonPause
onSaveInstanceState
onStop
onDestroyonCreate
onStart
onRestoreinstanceState gets s:im Tu Fengyi
onResume
旋转屏幕后,打印结果为:(Android9.0 之后改了onSaveInstance()回调的位置位置)
2023-03-14 20:04:08.859 12301-12301/? E/Fy_MainActivity: onCreate
2023-03-14 20:04:08.874 12301-12301/? E/Fy_MainActivity: onStart
2023-03-14 20:04:08.898 12301-12301/? E/Fy_MainActivity: onResume
2023-03-14 20:06:14.853 12301-12301/? E/Fy_MainActivity: onPause
2023-03-14 20:06:14.855 12301-12301/? E/Fy_MainActivity: onStop
2023-03-14 20:06:14.858 12301-12301/? E/Fy_MainActivity: onSaveInstanceState
2023-03-14 20:06:14.859 12301-12301/? E/Fy_MainActivity: onDestroy
2023-03-14 20:06:14.922 12301-12301/? E/Fy_MainActivity: onCreate
2023-03-14 20:06:14.926 12301-12301/? E/Fy_MainActivity: onStart
2023-03-14 20:06:14.927 12301-12301/? E/Fy_MainActivity: onRestoreInstanceState gets s:im Tu Fengyi
2023-03-14 20:06:14.927 12301-12301/? E/Fy_MainActivity: onResume
上一篇:ESP32中定时计数器的使用
下一篇:数据结构—双向带头循环链表的实现