Android技術周報是最近我剛創(chuàng)建的一個文集憔涉,這篇文章也是Android技術周報這個文集的第一篇文章(發(fā)現自己好久沒寫文章了),主要目的是記錄和分享一些工作中遇到的問題析苫,并對其進行深入研究兜叨,對于描述的內容有異議的可以留言,大家一起交流和學習衩侥。今天的內容是從源碼角度了解Activity中的 onSaveInstanceState 和 onRestoreInstanceState:
1. onSaveInstanceState到底做了些什么国旷?
protected void onSaveInstanceState(Bundle outState) {
// 存儲窗口視圖狀態(tài)
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
// 存儲Fragment狀態(tài)
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
// 存儲Android自動填充的狀態(tài),非重點
getAutofillManager().onSaveInstanceState(outState);
}
// 調用ActivityLifeCallbacks的onSaveInstanceState方法進行狀態(tài)存儲
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
從源碼上看茫死,不難發(fā)現onSaveInstanceState主要做了以下三個內容:
- 存儲窗口視圖狀態(tài)
- 存儲Fragment狀態(tài)
- 調用ActivityLifeCallbacks的onSaveInstanceState方法進行狀態(tài)存儲
通過調用PhoneWindow的saveHierarchyState方法實際上是調用mContentParent的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);
....
return outState;
}
其中mContentParent是Activity的主視圖跪但,本質是一個View對象,在Activity#setContentView()方法里進行初始化操作峦萎,接下來回到View的saveHierarchyState方法:
public void saveHierarchyState(SparseArray<Parcelable> container) {
dispatchSaveInstanceState(container);
}
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) {
// 以當前View的ID為key值存儲起來
container.put(mID, state);
}
}
}
在View的dispatchSaveInstanceState方法里屡久,會將View#onSaveInstanceState()方法返回的Parcelable對象以當前View的ID為key值存儲起來,并返回骨杂,這也意味著如果當前View沒有設置ID涂身,那么將無法進行View的onSaveInstanceState操作:
android:id="@+id/tv_save_state"
View的onSaveInstanceState方法默認返回空狀態(tài) BaseSavedState.EMPTY_STATE,可交由子View重寫搓蚪,如TextView#onSaveInstanceState():
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
// Save state if we are forced to
final boolean freezesText = getFreezesText();
boolean hasSelection = false;
int start = -1;
int end = -1;
if (mText != null) {
start = getSelectionStart();
end = getSelectionEnd();
if (start >= 0 || end >= 0) {
// Or save state if there is a selection
hasSelection = true;
}
}
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 {
ss.text = mText.toString();
}
}
if (hasSelection) {
// XXX Should also save the current scroll position!
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;
}
接下來進入Fragment狀態(tài)的保存方法蛤售,mFragments.saveAllState(),mFragments是一個FragmentController對象妒潭,主要用于提供FragmentManager對象悴能,維護Fragments的生命周期,這里不做過多介紹雳灾,所以最終是調用FragmentManager#saveAllState()方法漠酿,該方法最終會返回一個FragmentManagerState對象:
Parcelable saveAllState() {
...
// 第一步:收集所有處于active狀態(tài)的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) {
...
FragmentState fs = new FragmentState(f);
active[i] = fs;
if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = saveFragmentBasicState(f);
...
} else {
fs.mSavedFragmentState = f.mSavedFragmentState;
}
}
}
// 第二步:收集已經添加的Fragments的Index
int[] added = null;
BackStackState[] backStack = null;
N = mAdded.size();
if (N > 0) {
added = new int[N];
for (int i=0; i<N; i++) {
added[i] = mAdded.get(i).mIndex;
...
}
}
// 第三步:保存回退棧的內容,FragmentManager中的BackStack主要是用來存儲FragmentTransaction谎亩,具體可見下篇文章的講解
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));
}
}
}
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;
}
對于第一步的方法最終會調用FragmentManager#saveFragmentBasicState()方法炒嘲,此方法主要有以下任務:
Bundle saveFragmentBasicState(Fragment f) {
Bundle result = null;
...
// 調用Fragment#onSaveInstanceState()方法(可由子類重寫)
f.performSaveInstanceState(mStateBundle);
dispatchOnFragmentSaveInstanceState(f, mStateBundle, false);
...
// 保存View的視圖狀態(tài)宇姚,跟上面內容介紹一致
if (f.mView != null) {
saveFragmentViewState(f);
}
// mSavedViewState為已保存的視圖狀態(tài)
if (f.mSavedViewState != null) {
if (result == null) {
result = new Bundle();
}
result.putSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
}
// 記錄Fragment的顯示屬性
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;
}
Fragment的performSaveInstanceState除了保存自身狀態(tài)還會保存子Fragment的狀態(tài),實現如下:
void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
if (mChildFragmentManager != null) {
Parcelable p = mChildFragmentManager.saveAllState();
if (p != null) {
outState.putParcelable(Activity.FRAGMENTS_TAG, p);
}
}
}
最后夫凸,看一下Activity#onSaveInstanceState的最后一步:
getApplication().dispatchActivitySaveInstanceState(this, outState);
實際上是遍歷已注冊的ActivityLifecycleCallback浑劳,并調用其onActivitySaveInstanceState()方法:
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);
}
}
}
至此,Activity#onSaveInstanceState的工作已經做完了夭拌,總結起來魔熏,其時序圖如下:
講解過程省略了不少代碼,需要做詳細了解的可以進一步查看源碼鸽扁,關于onRestoreInstanceState的方法實現蒜绽,主要是以上方法的一個逆過程,這里不再做過多的敘述桶现,接下來內容主要講onSaveInstanceState與onRestoreInstanceState的調用時機躲雅。
2. onSaveInstanceState與onRestoreInstanceState調用時機
關于onSaveInstanceState調用時機的追蹤,我們先來簡單看一下一個Activity的啟動過程:
Activity的啟動過程與Binder進程間通信機制息息相關骡和,對于Binder進程間通信機制以及Activity的啟動過程吏夯,我們在后期的文章里會仔細說明,這里就不在做過多說明即横。Activity的啟動過程主要的步驟可以概括如下:
- MainActivity向ActivityManagerService發(fā)送一個啟動SecondActivity的進程間通信請求噪生;
- ActivityManagerService保存SecondActivity的相關信息,并向MainActivity發(fā)送一個進入中止狀態(tài)(pause)的進程間通信請求东囚;
- MainActivity進入中止狀態(tài)后跺嗽,向ActivityManagerService發(fā)送一個已進入中止狀態(tài)的進程間通信請求;
- ActivityManagerService發(fā)現SecondActivity所在進程不存在页藻,則會發(fā)起啟動新進程的請求桨嫁;
- 當新進程啟動完畢后,會向SecondActivity發(fā)送一個啟動完成的進程間通信請求份帐;
- ActivityManagerService將保存的SecondActivity信息發(fā)送給新創(chuàng)建的進程璃吧,以便其將SecondActivity啟動起來
我們主要看第三步,Activity接收ActivityManagerService的進程間通信請求最終都會由該Activity所在的進程對象ActivityThread里的Handler對象去處理:
// ActivityThread.java
private class H extends Handler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
...
case PAUSE_ACTIVITY: {
// 通知Activity進入中止狀態(tài)
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
}
核心方法為handlePauseActivity:
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
ActivityClientRecord r = mActivities.get(token);
if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
return;
}
if (r != null) {
...
r.activity.mConfigChangeFlags |= configChanges;
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
...
}
}
接著在往下看performPauseActivity:
final Bundle performPauseActivity(IBinder token, boolean finished,
boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
}
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState, String reason) {
...
if (finished) {
r.activity.mFinished = true;
}
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
callCallActivityOnSaveInstanceState(r);
}
...
}
這時候關鍵方法已經顯而易見了:
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);
}
}
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
PersistableBundle outPersistentState) {
activity.performSaveInstanceState(outState, outPersistentState);
}
final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
// 這就是我們希望看到的方法
onSaveInstanceState(outState, outPersistentState);
saveManagedDialogs(outState);
storeHasCurrentPermissionRequest(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
", " + outPersistentState);
}
總結起來废境,onSaveInstanceState會在以下情況下被調用:
- 當用戶按下home鍵畜挨;
- 長按home鍵切換應用程序;
- 按下電源鍵噩凹;
- 啟動一個新的Activity巴元;
- 屏幕方向切換;
- 電話打入等情況發(fā)生
而onRestoreInstanceState只有在activity確實是被系統(tǒng)回收驮宴,重新創(chuàng)建activity的情況下才會被調用逮刨,所以主要分為以下兩種情況:
a. activity沒有被銷毀:
onPause -> onSaveInstanceState -> onStop -> onRestart -> onStart -> onResume
b. activity被銷毀:
onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume
OK,今天的內容就到這里堵泽,下篇文章見 ~