概述
我們知道Activity提供了onSaveInstanceState和onRestoreInstanceState回調方法用於狀態保存和恢復,同樣FragmentActivity和Fragment也支持狀態保存和恢復,FragmentActivity會在適當的時機,通過FragmentManagerImpl通知Fragment進行保存操作,接下來從源碼中跟蹤這個通知過程。
源碼探究
文中源碼基於’androidx.fragment:fragment:1.1.0’
狀態保存
FragmentActivity重寫了onSaveInstanceState方法:
[FragmentActivity.java]
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
// ···
// 調用FragmentController的saveAllState方法獲取Parcelable
Parcelable p = mFragments.saveAllState();
if (p != null) {
// 將Parcelable保存進outState,FRAGMENTS_TAG值爲"android:support:fragments"
outState.putParcelable(FRAGMENTS_TAG, p);
}
// ···
}
outState中以FRAGMENTS_TAG爲key存儲數據。
FragmentController的saveAllState方法中又調用FragmentManagerImpl的saveAllState方法:
[FragmentManagerImpl.java]
Parcelable saveAllState() {
// Make sure all pending operations have now been executed to get
// our state update-to-date.
forcePostponedTransactions();
endAnimatingAwayFragments();
execPendingActions();
// 標記狀態保存爲true
mStateSaved = true;
if (mActive.isEmpty()) {
return null;
}
// First collect all active fragments.
int size = mActive.size();
ArrayList<FragmentState> active = new ArrayList<>(size);
boolean haveFragments = false;
for (Fragment f : mActive.values()) {
if (f != null) {
if (f.mFragmentManager != this) {
throwException(new IllegalStateException(
"Failure saving state: active " + f
+ " was removed from the FragmentManager"));
}
haveFragments = true;
// 創建FragmentState用於保存Fragment中的成員變量值
FragmentState fs = new FragmentState(f);
active.add(fs);
// fs.mSavedFragmentState此時默認爲空
if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
// 派發通知fragment進行數據保存
fs.mSavedFragmentState = saveFragmentBasicState(f);
// 若有setTargetFragment,則進行TargetFragment相關數據保存
if (f.mTargetWho != null) {
Fragment target = mActive.get(f.mTargetWho);
if (target == null) {
throwException(new IllegalStateException(
"Failure saving state: " + f
+ " has target not in fragment manager: "
+ f.mTargetWho));
}
if (fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = new Bundle();
}
putFragment(fs.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG, target);
if (f.mTargetRequestCode != 0) {
fs.mSavedFragmentState.putInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
f.mTargetRequestCode);
}
}
} else {
fs.mSavedFragmentState = f.mSavedFragmentState;
}
if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
+ fs.mSavedFragmentState);
}
}
if (!haveFragments) {
if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
return null;
}
ArrayList<String> added = null;
BackStackState[] backStack = null;
// Build list of currently added fragments.
// 保存mAdded集合中的Fragment唯一ID
size = mAdded.size();
if (size > 0) {
added = new ArrayList<>(size);
for (Fragment f : mAdded) {
// f.mWho爲Fragment實例化時生成的唯一UUID
added.add(f.mWho);
if (f.mFragmentManager != this) {
throwException(new IllegalStateException(
"Failure saving state: active " + f
+ " was removed from the FragmentManager"));
}
if (DEBUG) {
Log.v(TAG, "saveAllState: adding fragment (" + f.mWho
+ "): " + f);
}
}
}
// Now save back stack.
// 若有addToBackStack,則進行回退棧相關數據保存
if (mBackStack != null) {
size = mBackStack.size();
if (size > 0) {
backStack = new BackStackState[size];
for (int i = 0; i < size; i++) {
// 創建BackStackState用於保存BackStackRecord的數據
backStack[i] = new BackStackState(mBackStack.get(i));
if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
+ ": " + mBackStack.get(i));
}
}
}
// 創建FragmentManagerState用於保存該FragmentManagerImpl整體數據
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
if (mPrimaryNav != null) {
fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
}
fms.mNextFragmentIndex = mNextFragmentIndex;
return fms;
}
該方法中創建FragmentState集合用以保存每個Fragment的數據,String集合保存每個Fragment的唯一ID,BackStackState數組保存每個BackStackRecord的數據,最終創建FragmentManagerState用以保存以上所有數據,並返回添加進Bundle中。
接着看saveFragmentBasicState方法,該方法中進行更詳細的數據保存,返回Bundle賦值給FragmentState的mSavedFragmentState成員保存:
[FragmentManagerImpl.java]
Bundle saveFragmentBasicState(Fragment f) {
Bundle result = null;
if (mStateBundle == null) {
mStateBundle = new Bundle();
}
// 觸發Fragment的onSaveInstanceState回調方法;通知Fragment的子Fragment進行狀態保存
f.performSaveInstanceState(mStateBundle);
// Lifecycle架構組件回調通知
dispatchOnFragmentSaveInstanceState(f, mStateBundle, false);
if (!mStateBundle.isEmpty()) {
result = mStateBundle;
mStateBundle = null;
}
// 若該fragment設置了view,則進行相關視圖樹的保存
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
// 不可見時保存mUserVisibleHint
result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
}
return result;
}
該方法中會通過performSaveInstanceState方法觸發Fragment的onSaveInstanceState回調方法,Fragment子類可重寫該方法保存數據。若該Fragment有設置view,還將通過Fragment的mInnerView成員的saveHierarchyState方法進行視圖樹的保存。
在進行了這一系列的保存後,數據都整合添加進Bundle,由ActivityClientRecord的state成員保存,同時FragmentManagerImpl的mStateSaved被標記爲true。
狀態恢復
進入FragmentActivity的onCreate方法:
[FragmentActivity.java]
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
if (savedInstanceState != null) {
// 當savedInstanceState不爲空時,取出FRAGMENTS_TAG對應的數據
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
// 將數據交給FragmentManagerImpl進行狀態恢復
mFragments.restoreSaveState(p);
// Check if there are any pending onActivityResult calls to descendent Fragments.
if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
mNextCandidateRequestIndex =
savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
if (requestCodes == null || fragmentWhos == null ||
requestCodes.length != fragmentWhos.length) {
Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
} else {
mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
for (int i = 0; i < requestCodes.length; i++) {
mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
}
}
}
}
if (mPendingFragmentActivityResults == null) {
mPendingFragmentActivityResults = new SparseArrayCompat<>();
mNextCandidateRequestIndex = 0;
}
super.onCreate(savedInstanceState);
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
mFragments.dispatchCreate();
}
在onCreate中,若savedInstanceState不爲空,則取出FRAGMENTS_TAG對應的數據,通過FragmentManagerImpl的restoreSaveState方法進行狀態恢復。
接着看restoreSaveState方法:
[FragmentManagerImpl.java]
void restoreSaveState(Parcelable state) {
// If there is no saved state at all, then there's nothing else to do
if (state == null) return;
FragmentManagerState fms = (FragmentManagerState)state;
if (fms.mActive == null) return;
// First re-attach any non-config instances we are retaining back
// to their saved state, so we don't try to instantiate them again.
// 處理setRetainInstance相關的Fragment的狀態恢復
for (Fragment f : mNonConfig.getRetainedFragments()) {
if (DEBUG) Log.v(TAG, "restoreSaveState: re-attaching retained " + f);
FragmentState fs = null;
for (FragmentState fragmentState : fms.mActive) {
if (fragmentState.mWho.equals(f.mWho)) {
fs = fragmentState;
break;
}
}
if (fs == null) {
// 若RetainedFragment對應的RetainedFragment不存在,則需要移除該RetainedFragment
if (DEBUG) {
Log.v(TAG, "Discarding retained Fragment " + f
+ " that was not found in the set of active Fragments " + fms.mActive);
}
// We need to ensure that onDestroy and any other clean up is done
// so move the Fragment up to CREATED, then mark it as being removed, then
// destroy it.
moveToState(f, Fragment.CREATED, 0, 0, false);
f.mRemoving = true;
moveToState(f, Fragment.INITIALIZING, 0, 0, false);
continue;
}
fs.mInstance = f;
f.mSavedViewState = null;
f.mBackStackNesting = 0;
f.mInLayout = false;
f.mAdded = false;
f.mTargetWho = f.mTarget != null ? f.mTarget.mWho : null;
f.mTarget = null;
if (fs.mSavedFragmentState != null) {
// 恢復RetainedFragment的數據
fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mSavedFragmentState = fs.mSavedFragmentState;
}
}
// Build the full list of active fragments, instantiating them from
// their saved state.
mActive.clear();
for (FragmentState fs : fms.mActive) {
if (fs != null) {
// 實例化Fragment,並用FragmentState保存的數據來初始化Fragment
Fragment f = fs.instantiate(mHost.getContext().getClassLoader(),
getFragmentFactory());
f.mFragmentManager = this;
if (DEBUG) Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
// 添加fragment至mActive成員中
mActive.put(f.mWho, f);
// Now that the fragment is instantiated (or came from being
// retained above), clear mInstance in case we end up re-restoring
// from this FragmentState again.
fs.mInstance = null;
}
}
// Build the list of currently added fragments.
mAdded.clear();
if (fms.mAdded != null) {
for (String who : fms.mAdded) {
// 獲取前面剛剛創建並保存的fragment
Fragment f = mActive.get(who);
if (f == null) {
throwException(new IllegalStateException(
"No instantiated fragment for (" + who + ")"));
}
f.mAdded = true;
if (DEBUG) Log.v(TAG, "restoreSaveState: added (" + who + "): " + f);
if (mAdded.contains(f)) {
throw new IllegalStateException("Already added " + f);
}
synchronized (mAdded) {
// 添加進mAdded成員中
mAdded.add(f);
}
}
}
// Build the back stack.
// 後退棧數據恢復
if (fms.mBackStack != null) {
mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
for (int i=0; i<fms.mBackStack.length; i++) {
BackStackRecord bse = fms.mBackStack[i].instantiate(this);
if (DEBUG) {
Log.v(TAG, "restoreAllState: back stack #" + i
+ " (index " + bse.mIndex + "): " + bse);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
bse.dump(" ", pw, false);
pw.close();
}
mBackStack.add(bse);
if (bse.mIndex >= 0) {
setBackStackIndex(bse.mIndex, bse);
}
}
} else {
mBackStack = null;
}
if (fms.mPrimaryNavActiveWho != null) {
mPrimaryNav = mActive.get(fms.mPrimaryNavActiveWho);
dispatchParentPrimaryNavigationFragmentChanged(mPrimaryNav);
}
this.mNextFragmentIndex = fms.mNextFragmentIndex;
}
該方法中利用保存在FragmentManagerState中的數據進行狀態恢復,其中在利用FragmentState恢復Fragment數據時,會將mSavedFragmentState賦值給Fragment的mSavedFragmentState成員。
mSavedFragmentState中保存了Fragment中的自定義存儲數據和視圖樹狀態
之後隨着FragmentActivity調度Fragment顯示,在Fragment的各生命週期階段中,可以使用mSavedFragmentState保存的數據恢復。
進入FragmentManagerImpl的生命週期狀態調度方法moveToState:
[FragmentManagerImpl.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// ···
if (f.mState <= newState) {
// ···
switch (f.mState) {
case Fragment.INITIALIZING:
if (newState > Fragment.INITIALIZING) {
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
f.mSavedFragmentState.setClassLoader(mHost.getContext()
.getClassLoader());
// 獲取保存的視圖樹狀態
f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
Fragment target = getFragment(f.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG);
f.mTargetWho = target != null ? target.mWho : null;
if (f.mTargetWho != null) {
f.mTargetRequestCode = f.mSavedFragmentState.getInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
}
if (f.mSavedUserVisibleHint != null) {
f.mUserVisibleHint = f.mSavedUserVisibleHint;
f.mSavedUserVisibleHint = null;
} else {
// 獲取保存的可見狀態
f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
}
if (!f.mUserVisibleHint) {
f.mDeferStart = true;
if (newState > Fragment.ACTIVITY_CREATED) {
newState = Fragment.ACTIVITY_CREATED;
}
}
}
// ···
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
} else {
f.mParentFragment.onAttachFragment(f);
}
dispatchOnFragmentAttached(f, mHost.getContext(), false);
if (!f.mIsCreated) {
dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
// 觸發Fragment的onCreate回調方法,並傳入bundle
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
// 派發Fragment的子Fragment的狀態恢復
f.restoreChildFragmentState(f.mSavedFragmentState);
f.mState = Fragment.CREATED;
}
}
// fall through
case Fragment.CREATED:
// We want to unconditionally run this anytime we do a moveToState that
// moves the Fragment above INITIALIZING, including cases such as when
// we move from CREATED => CREATED as part of the case fall through above.
if (newState > Fragment.INITIALIZING) {
ensureInflatedFragmentView(f);
}
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
// ···
}
f.mContainer = container;
// 觸發Fragment的onCreateView回調方法,並傳入bundle
f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
// 觸發Fragment的onViewCreated回調方法,並傳入bundle
f.onViewCreated(f.mView, f.mSavedFragmentState);
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
// Only animate the view if it is visible. This is done after
// dispatchOnFragmentViewCreated in case visibility is changed
f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
&& f.mContainer != null;
} else {
f.mInnerView = null;
}
}
// 觸發Fragment的onActivityCreated回調方法,並傳入bundle
f.performActivityCreated(f.mSavedFragmentState);
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
// 調用mInnerView的restoreHierarchyState方法傳入mSavedViewState進行視圖樹狀態恢復。
// 然後回調onViewStateRestored方法並傳入bundle。
f.restoreViewState(f.mSavedFragmentState);
}
// mSavedFragmentState賦值爲空
f.mSavedFragmentState = null;
}
// fall through
case Fragment.ACTIVITY_CREATED:
if (newState > Fragment.ACTIVITY_CREATED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.performStart();
dispatchOnFragmentStarted(f, false);
}
// fall through
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.performResume();
dispatchOnFragmentResumed(f, false);
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) { /* ··· */ }
// ···
}
從該方法中可以看出,在Fragment的生命週期回調方法中收到的savedInstanceState入參即爲Fragment的mSavedFragmentState,在派發完成後又會將mSavedFragmentState賦值爲空。
commit & commitAllowingStateLoss
這裏看下提交事務的兩個方法:commit、commitAllowingStateLoss,顧名思義,它們一個在提交時不允許狀態丟失、另一個允許。
[BackStackRecord.java]
public int commit() {
return commitInternal(false);
}
public int commitAllowingStateLoss() {
return commitInternal(true);
}
都調用了同一個方法commitInternal,只是傳入參數不同,一個傳false,另一個傳true。
繼續看commitInternal方法:
[BackStackRecord.java]
int commitInternal(boolean allowStateLoss) {
// ···
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
allowStateLoss參數直接傳入添加事務隊列的方法。
[FragmentManagerImpl.java]
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
// 不允許狀態丟失時,首先進行檢查
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
// 當FragmentActivity已經destroyed或持有FragmentHostCallback爲空時,若不允許狀態丟失,將拋出異常。
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
是否允許狀態丟失,就是在添加事務進隊列前,檢查狀態,以及是否拋出異常。
進入checkStateLoss方法:
[FragmentManagerImpl.java]
private void checkStateLoss() {
// 檢查狀態,判斷是否拋異常
if (isStateSaved()) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
}
@Override
public boolean isStateSaved() {
// See saveAllState() for the explanation of this. We do this for
// all platform versions, to keep our behavior more consistent between
// them.
// onSaveInstanceState時mStateSaved將置爲true,onStop時mStopped將置爲true
return mStateSaved || mStopped;
}
不允許在執行onSaveInstanceState回調方法後再添加Fragment事務操作。因爲Fragment的狀態保存是在onSaveInstanceState階段中,此後若再變更FragmentManagerImpl中的Fragment,這些Fragment的狀態不會進行保存。
onSaveInstanceState回調在Android P及以上版本觸發時機在onStop之後,在低版本觸發時機在onStop之前。
總結
FragmentActivity在onSaveInstanceState回調方法中,調用FragmentManagerImpl通知其管理的Fragment進行狀態保存。保存過程中會觸發Fragment的onSaveInstanceState回調,可通過重寫該方法保存自定義數據。若Fragment有設置view,還將進行視圖樹的保存。
FragmentActivity在onCreate回調方法中,判斷savedInstanceState參數是否有值,之後通知FragmentManagerImpl進行狀態恢復,實例化Fragment並將存儲着狀態的bundle賦值給mSavedFragmentState成員。
在Fragment從創建到顯示的生命週期狀態生長階段,通過mSavedFragmentState成員來恢復數據和視圖樹,會將mSavedFragmentState作爲入參調用對應生命週期回調方法,完成後再清除mSavedFragmentState。Fragment子類可在onCreate和onActivityCreated中恢復自定義數據。