文章目錄
- 概述
- 源碼探究
- FragmentManager的由來
- FragmentController
- HostCallbacks
- FragmentManagerImpl
- FragmentController、HostCallbacks、FragmentManagerImpl之間關係
- 添加事務操作
- 處理事務操作
- generateOpsForPendingActions
- generateOps
- removeRedundantOperationsAndExecute
- executeOpsTogether
- executeOps
- addFragment
- moveToState
- REMOVE操作類型
- REPLACE操作類型
- HIDE和SHOW操作類型
- 總結
概述
平時開發中經常使用Fragment的場景是創建Fragment並添加到FragmentActivity的指定佈局容器中。要實現這樣的操作,首先需要獲取FragmentManager,接着開啓事務FragmentTransaction,並添加add、remove、replace、hide、show等等操作,最後commitXXX提交事務執行對應操作。
接下來進入源碼追蹤這個過程,看看FragmentManager是如何進行調度執行。
源碼探究
文中源碼基於’androidx.fragment:fragment:1.1.0’
FragmentManager的由來
在FragmentActivity中通過getSupportFragmentManager方法來獲取FragmentManager:
[FragmentActivity.java]
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
該方法中又通過mFragments成員來獲取:
[FragmentController.java]
public FragmentManager getSupportFragmentManager() {
return mHost.mFragmentManager;
}
其中又通過mHost成員來獲取。
在研究FragmentManager之前,先來看看mFragments、mHost是什麼。
FragmentController
先來看看FragmentActivity的mFragments成員:
[FragmentActivity.java]
public class FragmentActivity extends ComponentActivity implements
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
// ···
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// ···
}
mFragments爲FragmentController對象。
接着看createController方法,這裏傳入HostCallbacks實例:
[FragmentController.java]
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}
private FragmentController(FragmentHostCallback<?> callbacks) {
// 持有HostCallbacks引用
mHost = callbacks;
}
HostCallbacks
在創建FragmentController時,實例化了HostCallbacks並賦值給FragmentController的mHost成員。
[FragmentActivity.java]
class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
ViewModelStoreOwner,
OnBackPressedDispatcherOwner {
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
// ···
}
HostCallbacks繼承自FragmentHostCallback,爲FragmentActivity的內部類,持有FragmentActivity的引用。
[FragmentHostCallback.java]
public abstract class FragmentHostCallback<E> extends FragmentContainer {
// ···
FragmentHostCallback(@NonNull FragmentActivity activity) {
this(activity, activity /*context*/, new Handler(), 0 /*windowAnimations*/);
}
FragmentHostCallback(@Nullable Activity activity, @NonNull Context context,
@NonNull Handler handler, int windowAnimations) {
// 持有FragmentActivity上下文引用
mActivity = activity;
mContext = Preconditions.checkNotNull(context, "context == null");
// 構造函數中創建的Handler,默認運行在主線程
mHandler = Preconditions.checkNotNull(handler, "handler == null");
// 動畫相關,默認爲0
mWindowAnimations = windowAnimations;
}
// ···
}
可以看出HostCallbacks持有當前FragmentActivity上下文,並創建了一個主線程Handler。
FragmentManagerImpl
FragmentManager爲抽象類,而FragmentManagerImpl是其實現類:
[FragmentManagerImpl.java]
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
// ···
}
在FragmentHostCallback實例化時會創建FragmentManagerImpl:
[FragmentHostCallback.java]
public abstract class FragmentHostCallback<E> extends FragmentContainer {
// ···
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
// ···
}
FragmentHostCallback的mFragmentManager成員持有FragmentManagerImpl。
FragmentManagerImpl的綁定
在FragmentActivity的onCreate方法中:
[FragmentActivity.java]
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 調用FragmentController的attachHost方法,參數傳null
mFragments.attachHost(null /*parent*/);
// ···
}
接着看attachHost方法:
[FragmentController.java]
public void attachHost(@Nullable Fragment parent) {
// 調用FragmentManagerImpl的attachController方法,並傳入HostCallbacks實例,參數parent爲null。
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
進入FragmentManagerImpl的attachController方法:
[FragmentManagerImpl.java]
public void attachController(@NonNull FragmentHostCallback host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
// 持有HostCallbacks引用
mHost = host;
mContainer = container;
mParent = parent;
if (mParent != null) {
// Since the callback depends on us being the primary navigation fragment,
// update our callback now that we have a parent so that we have the correct
// state by default
updateOnBackPressedCallbackEnabled();
}
// Set up the OnBackPressedCallback
// 省略BackPressed設置部分
// ···
// Get the FragmentManagerViewModel
// 省略ViewModel設置部分
// ···
}
FragmentActivity在onCreate中進行FragmentManagerImpl的綁定操作,在FragmentManagerImpl的attachController方法中接收HostCallbacks實例並保存。
FragmentController、HostCallbacks、FragmentManagerImpl之間關係
FragmentActivity持有FragmentController引用,FragmentController持有HostCallbacks引用,HostCallbacks持有FragmentActivity引用,FragmentActivity和FragmentManagerImpl互相持有引用。
FragmentActivity通過FragmentController獲取HostCallbacks,再通過HostCallbacks間接調用FragmentManagerImpl。FragmentManagerImpl通過HostCallbacks來間接獲取上下文和執行回調方法。
添加事務操作
開啓事務
獲取到FragmentManagerImpl實例後,通過它的beginTransaction方法開啓一個事務:
[FragmentManagerImpl.java]
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
這裏創建BackStackRecord(繼承自FragmentTransaction,並實現BackStackEntry、OpGenerator接口),BackStackRecord將持有FragmentManagerImpl。
FragmentTransaction封裝一個事務,一個事務包含一組操作(單個或多個操作)。
添加add Fragment的操作
這裏以,往FragmentActivity中添加一個Fragment爲例。
通常添加Fragment是通過調用FragmentTransaction的add方法,傳入佈局ID和Fragment實例:
[FragmentTransaction.java]
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
// tag可選參數,可通過tag查找fragment,OP_ADD標識add操作類型
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
BackStackRecord重寫了doAddOp方法:
[BackStackRecord.java]
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
super.doAddOp(containerViewId, fragment, tag, opcmd);
// 將持有的FragmentManagerImpl賦值給Fragment的mFragmentManager成員
fragment.mFragmentManager = mManager;
}
該方法中通過super還是調用FragmentTransaction的doAddOp,只是在執行完後爲Fragment的mFragmentManager成員賦值。
[FragmentTransaction.java]
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
final Class<?> fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
// 檢查fragment是否是匿名類,或者非public訪問性,或者定義在另一個類中但沒有聲明static
if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|| (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
+ " must be a public static class to be properly recreated from"
+ " instance state.");
}
if (tag != null) {
// 檢查是否fragment已有tag但和當前傳入的tag不同
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
// fragment保存tag
fragment.mTag = tag;
}
// containerViewId即爲FragmentActivity中用於添加這個fragment的佈局容器ID
if (containerViewId != 0) {
if (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
// 檢查是否fragment已經設置容器ID但與當前傳入的ID不同
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
// fragment保存容器ID,mFragmentId默認爲容器ID
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
// 添加操作
addOp(new Op(opcmd, fragment));
}
該方法中做了以下幾步:
- 該方法中首先校驗我們自定義的Fragment:
- 不能是匿名類
- 訪問性必須是public
- 若是成員類,必須是靜態類
- 接着檢查tag(若有傳入)是否和fragment已有保存的不同,最後保存在fragment中
- 接着檢查佈局ID(若有傳入),該佈局爲FragmentActivity中用於承載fragment的ViewGroup,必須有設置ID,fragment中若已有設置必須相同,最後fragment保存容器ID,mFragmentId默認也爲容器ID
- 封裝Op保存操作類型和fragment,並添加至操作集合
Op
Op表示一個操作,看它的構造函數:
[FragmentTransaction.java]
Op(int cmd, Fragment fragment) {
// 保存操作類型
this.mCmd = cmd;
// 保存待操作的fragment
this.mFragment = fragment;
// 生命週期狀態置爲RESUMED,對應Activity執行onResume之後的狀態
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
}
addOp
[FragmentTransaction.java]
void addOp(Op op) {
// 保存Op對象
mOps.add(op);
// 動畫相關,默認都爲0
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
}
FragmentTransaction的mOps成員用於保存Op對象,mOps爲ArrayList。
提交事務
FragmentTransaction有四個提交事務的方法:commit、commitAllowingStateLoss、commitNow、commitNowAllowingStateLoss。這四個方法都爲抽象類,具體實現在BackStackRecord中。
這裏以commitAllowingStateLoss爲例:
[BackStackRecord.java]
public int commitAllowingStateLoss() {
return commitInternal(true);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
// 省略DEBUG部分 ···
mCommitted = true;
// mAddToBackStack默認爲false,若調用addToBackStack方法的話爲true
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
// 此時傳入的allowStateLoss爲true
// 通過FragmentManagerImpl入隊
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
接着看FragmentManagerImpl的enqueueAction方法,此時傳入BackStackRecord自身和true:
[FragmentManagerImpl.java]
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
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表示待執行操作集合,action即爲BackStackRecord(實現了OpGenerator接口)
mPendingActions.add(action);
scheduleCommit();
}
}
接着看scheduleCommit方法:
[FragmentManagerImpl.java]
void scheduleCommit() {
synchronized (this) {
// 標記是否存在延遲事務,默認不存在
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
// 標記是否僅存在一個待執行事務,第一次通過enqueueAction提交事務時符合條件
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
// 符合條件,通過Handler調度任務執行
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
updateOnBackPressedCallbackEnabled();
}
}
}
當存在延遲事務或第一次提交事務時,會通過Handler來post一個Runnable執行操作,這裏的Handler即HostCallbacks實例化時創建的主線程Handler。
可見通過commit、commitAllowingStateLoss方法提交的事務不會立即執行,而是等待主線程LOOPER下一次取出消息時執行。
處理事務操作
前文中使用Handler post的mExecCommit是一個Runnable:
[FragmentManagerImpl.java]
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
觸發時將調用execPendingActions方法處理事務操作:
[FragmentManagerImpl.java]
public boolean execPendingActions() {
// 檢查狀態和初始化mTmpRecords、mTmpIsPop集合和處理延遲事務
ensureExecReady(true);
boolean didSomething = false;
// 生成命令並保存在mTmpRecords、mTmpIsPop集合中
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
// 標記當前處於執行事務中
mExecutingActions = true;
try {
// 移除或合併多餘的操作並執行
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
updateOnBackPressedCallbackEnabled();
// 執行推遲啓動的Fragment
doPendingDeferredStart();
// 清理mActive集合
burpActive();
return didSomething;
}
該方法中會在一個while循環中檢索待執行事務並執行,當generateOpsForPendingActions返回false表示沒有待執行的事務,則結束while循環。
兩個集合的說明:
- mTmpRecords:保存待執行的BackStackRecord。
- mTmpIsPop:標記與mTmpRecords對應索引的BackStackRecord是添加類型還是移除類型的,默認爲false,通過popBackStack回退時,會標記對應索引位置爲true。
generateOpsForPendingActions
[FragmentManagerImpl.java]
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isPop) {
// 標記是否有執行事務
boolean didSomething = false;
synchronized (this) {
// 若不存在待執行事務則返回false
if (mPendingActions == null || mPendingActions.size() == 0) {
return false;
}
final int numActions = mPendingActions.size();
// 遍歷mPendingActions,此時僅有一個OP_ADD類型的BackStackRecord
for (int i = 0; i < numActions; i++) {
// 依次調用generateOps方法
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
// 清空mPendingActions
mPendingActions.clear();
// 移除mExecCommit,避免冗餘執行
mHost.getHandler().removeCallbacks(mExecCommit);
}
return didSomething;
}
generateOps
這裏以添加Fragment爲例,此時mPendingActions中存在一個OP_ADD類型的BackStackRecord,查看它的generateOps方法:
[BackStackRecord.java]
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Run: " + this);
}
// records集合添加BackStackRecord自身
records.add(this);
// isRecordPop添加false
isRecordPop.add(false);
// mAddToBackStack默認爲false,因此不加入回退棧
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
return true;
}
removeRedundantOperationsAndExecute
[FragmentManagerImpl.java]
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop) {
if (records == null || records.isEmpty()) {
return;
}
if (isRecordPop == null || records.size() != isRecordPop.size()) {
throw new IllegalStateException("Internal error with the back stack records");
}
// Force start of any postponed transactions that interact with scheduled transactions:
executePostponedTransaction(records, isRecordPop);
final int numRecords = records.size();
int startIndex = 0;
for (int recordNum = 0; recordNum < numRecords; recordNum++) {
// 標記是否支持操作排序優化,默認爲false
final boolean canReorder = records.get(recordNum).mReorderingAllowed;
if (!canReorder) {
// execute all previous transactions
if (startIndex != recordNum) {
executeOpsTogether(records, isRecordPop, startIndex, recordNum);
}
// execute all pop operations that don't allow reordering together or
// one add operation
int reorderingEnd = recordNum + 1;
// 非pop事務都返回false
if (isRecordPop.get(recordNum)) {
while (reorderingEnd < numRecords
&& isRecordPop.get(reorderingEnd)
&& !records.get(reorderingEnd).mReorderingAllowed) {
reorderingEnd++;
}
}
// 執行指定索引區間中的BackStackRecord
executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
startIndex = reorderingEnd;
recordNum = reorderingEnd - 1;
}
}
if (startIndex != numRecords) {
// 開啓操作排序優化情況下可能會滿足該if條件
executeOpsTogether(records, isRecordPop, startIndex, numRecords);
}
}
操作排序優化
當有多個待執行事務時,FragmentManager會刪除部分冗餘事務操作。例如:
- 假設有兩個事務對同一佈局容器一起執行,一個事務添加了一個 Fragment A,下一個事務將其替換爲 Fragment B。則優化後會將第一個操作取消,僅添加 Fragment B。
- 假設有三個事務,一個事務添加了 Fragment A,第二個事務添加了 Fragment B,然後第三個刪除了 Fragment A。那麼優化後將不會執行 Fragment A的添加和刪除,僅添加 Fragment B。
排序優化操作會導致出現超出開發者預期的行爲,因此默認不進行此操作。
executeOpsTogether
進入executeOpsTogether方法:
[FragmentManagerImpl.java]
private void executeOpsTogether(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
// ···
executeOps(records, isRecordPop, startIndex, endIndex);
// ···
}
進入executeOps方法:
[FragmentManagerImpl.java]
private static void executeOps(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
for (int i = startIndex; i < endIndex; i++) {
final BackStackRecord record = records.get(i);
final boolean isPop = isRecordPop.get(i);
if (isPop) {
record.bumpBackStackNesting(-1);
// Only execute the add operations at the end of
// all transactions.
boolean moveToState = i == (endIndex - 1);
// 執行回退操作
record.executePopOps(moveToState);
} else {
record.bumpBackStackNesting(1);
// OP_ADD類型執行executeOps
record.executeOps();
}
}
}
executeOps
看BackStackRecord的executeOps方法中的OP_ADD case:
[BackStackRecord.java]
void executeOps() {
final int numOps = mOps.size();
// 遍歷該事務中的操作
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.mFragment;
if (f != null) {
f.setNextTransition(mTransition, mTransitionStyle);
}
switch (op.mCmd) {
case OP_ADD:
f.setNextAnim(op.mEnterAnim);
// 添加Fragment
mManager.addFragment(f, false);
break;
// 省略其他case ···
default:
throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
}
if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
mManager.moveFragmentToExpectedState(f);
}
}
// mReorderingAllowed默認爲false
if (!mReorderingAllowed) {
// Added fragments are added at the end to comply with prior behavior.
// 更新狀態,這裏傳入FragmentManagerImpl的當前狀態和true
mManager.moveToState(mManager.mCurState, true);
}
}
該方法中處理OP_ADD時,首先通過addFragment方法添加fragment至集合中保存,最後通過moveToState更新狀態並設置fragment。
addFragment
[FragmentManagerImpl.java]
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (DEBUG) Log.v(TAG, "add: " + fragment);
// 將fragment添加至mActive集合保存,若設置setRetainInstance還將添加入FragmentManagerViewModel中保存
makeActive(fragment);
// 此時爲OP_ADD操作,mDetached爲false
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
synchronized (mAdded) {
// fragment加入mAdded集合
mAdded.add(fragment);
}
// mAdded用於標記該fragment是否已經加入mAdded集合
fragment.mAdded = true;
// mRemoving標記該fragment是否從Activity移除
fragment.mRemoving = false;
// 此時mView還未生成,爲null
if (fragment.mView == null) {
fragment.mHiddenChanged = false;
}
if (isMenuAvailable(fragment)) {
mNeedMenuInvalidate = true;
}
// 此時傳入的moveToStateNow爲false
if (moveToStateNow) {
moveToState(fragment);
}
}
}
將fragment添加入mActive和mAdded集合中。
moveToState
回到BackStackRecord.executeOps方法中,在方法的最後執行moveToState方法:
[FragmentManagerImpl.java]
void moveToState(int newState, boolean always) {
if (mHost == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No activity");
}
if (!always && newState == mCurState) {
return;
}
// 更新狀態,此時傳入的newState和mCurState相等
mCurState = newState;
// Must add them in the proper order. mActive fragments may be out of order
final int numAdded = mAdded.size();
// 遍歷mAdded,依次取出Fragment處理
for (int i = 0; i < numAdded; i++) {
Fragment f = mAdded.get(i);
moveFragmentToExpectedState(f);
}
// 省略···
}
該方法中依次取出Fragment,調用moveFragmentToExpectedState將Fragment根據最終期望的狀態進行初始化設置。
mCurState成員記錄FragmentManagerImpl的當前狀態,狀態值有:
- INITIALIZING(0):初始狀態,默認狀態
- CREATED(1):初創狀態,對應onCreate、onDestroyView階段
- ACTIVITY_CREATED(2):created以上、started未滿狀態,對應onStart、onStop階段
- STARTED(3):started以上、resumed未滿階段,對應onResume、onPause階段
- RESUMED(4):resumed以上狀態,對應onResume完成階段
看moveFragmentToExpectedState方法:
[FragmentManagerImpl.java]
void moveFragmentToExpectedState(Fragment f) {
if (f == null) {
return;
}
if (!mActive.containsKey(f.mWho)) {
if (DEBUG) {
Log.v(TAG, "Ignoring moving " + f + " to state " + mCurState
+ "since it is not added to " + this);
}
return;
}
int nextState = mCurState;
if (f.mRemoving) {
if (f.isInBackStack()) {
nextState = Math.min(nextState, Fragment.CREATED);
} else {
nextState = Math.min(nextState, Fragment.INITIALIZING);
}
}
// 調度fragment到目標狀態對應階段,並執行對應階段的初始化設置
moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
if (f.mView != null) {
// ···
}
if (f.mHiddenChanged) {
completeShowHideFragment(f);
}
}
該方法中調用另一個moveToState重載方法:
[FragmentManagerImpl.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// 省略狀態檢查校驗部分
// ···
// 判斷fragment的生命週期狀態是否小等於FragmentManager的狀態,剛創建添加的fragment狀態默認爲INITIALIZING
if (f.mState <= newState) {
// ···
switch (f.mState) {
case Fragment.INITIALIZING:
// 開始進入attach階段
if (newState > Fragment.INITIALIZING) {
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
// 省略mSavedFragmentState部分 ···
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.mFragmentManager;
// If we have a target fragment, push it along to at least CREATED
// so that this one can rely on it as an initialized dependency.
// 省略mTarget部分 ···
// 省略mTargetWho部分 ···
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.performAttach();
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);
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState);
f.mState = Fragment.CREATED;
}
}
// fall through
// 注意此處無break,會繼續往下匹配case執行
case Fragment.CREATED:
// 開始進入CreateView階段
// 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) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(
"Cannot create fragment "
+ f
+ " for a container view with no id"));
}
// 獲取佈局容器,通過FragmentActivity.this.findViewById(f.mContainerId)獲取
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
String resName;
try {
resName = f.getResources().getResourceName(f.mContainerId);
} catch (Resources.NotFoundException e) {
resName = "unknown";
}
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ resName
+ ") for fragment " + f));
}
}
f.mContainer = container;
// performGetLayoutInflater中通過FragmentActivity上下文獲取LayoutInflater
// performCreateView中會觸發fragment的onCreateView方法,
// 返回我們自定義的視圖,並賦值給mView成員
f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
// 將fragment的view加入佈局容器中
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
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;
}
}
f.performActivityCreated(f.mSavedFragmentState);
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
f.restoreViewState(f.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) {
// 省略生命週期逆生長部分,即onPause、onStop、onDestroyView、onDestroy、onDetach
// ···
}
if (f.mState != newState) {
Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+ "expected state " + newState + " found " + f.mState);
// 更新fragment的狀態
f.mState = newState;
}
}
moveToState方法中在CREATED狀態階段,完成了Fragment視圖的創建(若有自定義視圖),接着添加至給定的佈局容器中。
moveToState方法還會根據Fragment和FragmentManager當前的生命週期狀態,調度Fragment的狀態更新,在其中還會觸發Fragment各階段的生命週期回調方法。
REMOVE操作類型
通過調用BackStackRecord的remove方法,傳入指定Fragment,達到移除Fragment的作用。
[BackStackRecord.java]
public FragmentTransaction remove(@NonNull Fragment fragment) {
if (fragment.mFragmentManager != null && fragment.mFragmentManager != mManager) {
throw new IllegalStateException("Cannot remove Fragment attached to "
+ "a different FragmentManager. Fragment " + fragment.toString() + " is already"
+ " attached to a FragmentManager.");
}
return super.remove(fragment);
}
調用父類FragmentTransaction的remove方法:
[FragmentTransaction.java]
public FragmentTransaction remove(@NonNull Fragment fragment) {
addOp(new Op(OP_REMOVE, fragment));
return this;
}
remove方法中創建Op對象,傳入命令類型OP_REMOVE和要移除的fragment,添加到命令集合mOps成員中。
接下來的步驟就是提交事務,加入事務隊列,等待調度執行,同OP_ADD一樣,將會執行BackStackRecord的executeOps方法:
[BackStackRecord.java]
void executeOps() {
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.mFragment;
if (f != null) {
f.setNextTransition(mTransition, mTransitionStyle);
}
switch (op.mCmd) {
// ···
case OP_REMOVE:
f.setNextAnim(op.mExitAnim);
// 將該fragment從FragmentManagerImpl的mAdded成員中移除,並設置
// 該fragment的mAdded成員爲false、mRemoving成員爲true
mManager.removeFragment(f);
break;
// ···
}
// mReorderingAllowed默認爲false
if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
// 更新fragment的生命狀態和執行對應階段的生命週期回調和釋放銷燬
mManager.moveFragmentToExpectedState(f);
}
}
if (!mReorderingAllowed) {
// Added fragments are added at the end to comply with prior behavior.
// 更新當前FragmentManagerImpl中管理的Fragment的狀態
mManager.moveToState(mManager.mCurState, true);
}
}
moveFragmentToExpectedState和moveToState方法在處理OP_ADD命令時見到過,是通用方法,其他命令也都會調用這兩個方法。
[FragmentManagerImpl.java]
void moveFragmentToExpectedState(Fragment f) {
// ···
int nextState = mCurState;
// mRemoving此時已經置爲true
if (f.mRemoving) {
// 修改要更新至的目標狀態,若該fragment不爲最後一個,則目標狀態爲CREATED
if (f.isInBackStack()) {
nextState = Math.min(nextState, Fragment.CREATED);
} else {
nextState = Math.min(nextState, Fragment.INITIALIZING);
}
}
// 調度fragment到目標狀態對應階段,並執行對應階段的處理
moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
// ···
}
[FragmentManagerImpl.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// ···
if (f.mState <= newState) {
// ···
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
// ···
case Fragment.STARTED:
// ···
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null) {
// Need to save the current view state if not
// done already.
if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
saveFragmentViewState(f);
}
}
f.performDestroyView();
dispatchOnFragmentViewDestroyed(f, false);
if (f.mView != null && f.mContainer != null) {
// Stop any current animations:
f.mContainer.endViewTransition(f.mView);
f.mView.clearAnimation();
AnimationOrAnimator anim = null;
// If parent is being removed, no need to handle child animations.
if (f.getParentFragment() == null || !f.getParentFragment().mRemoving) {
if (mCurState > Fragment.INITIALIZING && !mDestroyed
&& f.mView.getVisibility() == View.VISIBLE
&& f.mPostponedAlpha >= 0) {
anim = loadAnimation(f, transit, false,
transitionStyle);
}
f.mPostponedAlpha = 0;
if (anim != null) {
animateRemoveFragment(f, anim, newState);
}
// 設置了view和佈局容器的情況下,需要從佈局中移除該Fragment的view
f.mContainer.removeView(f.mView);
}
}
// 解除引用
f.mContainer = null;
f.mView = null;
// Set here to ensure that Observers are called after
// the Fragment's view is set to null
f.mViewLifecycleOwner = null;
f.mViewLifecycleOwnerLiveData.setValue(null);
f.mInnerView = null;
f.mInLayout = false;
}
// fall through
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (mDestroyed) {
// The fragment's containing activity is
// being destroyed, but this fragment is
// currently animating away. Stop the
// animation right now -- it is not needed,
// and we can't wait any more on destroying
// the fragment.
if (f.getAnimatingAway() != null) {
View v = f.getAnimatingAway();
f.setAnimatingAway(null);
v.clearAnimation();
} else if (f.getAnimator() != null) {
Animator animator = f.getAnimator();
f.setAnimator(null);
animator.cancel();
}
}
if (f.getAnimatingAway() != null || f.getAnimator() != null) {
// We are waiting for the fragment's view to finish
// animating away. Just make a note of the state
// the fragment now should move to once the animation
// is done.
f.setStateAfterAnimating(newState);
newState = Fragment.CREATED;
} else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
boolean beingRemoved = f.mRemoving && !f.isInBackStack();
if (beingRemoved || mNonConfig.shouldDestroy(f)) {
boolean shouldClear;
if (mHost instanceof ViewModelStoreOwner) {
shouldClear = mNonConfig.isCleared();
} else if (mHost.getContext() instanceof Activity) {
Activity activity = (Activity) mHost.getContext();
shouldClear = !activity.isChangingConfigurations();
} else {
shouldClear = true;
}
if (beingRemoved || shouldClear) {
mNonConfig.clearNonConfigState(f);
}
f.performDestroy();
dispatchOnFragmentDestroyed(f, false);
} else {
f.mState = Fragment.INITIALIZING;
}
f.performDetach();
dispatchOnFragmentDetached(f, false);
if (!keepActive) {
if (beingRemoved || mNonConfig.shouldDestroy(f)) {
makeInactive(f);
} else {
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
if (f.mTargetWho != null) {
Fragment target = mActive.get(f.mTargetWho);
if (target != null && target.getRetainInstance()) {
// Only keep references to other retained Fragments
// to avoid developers accessing Fragments that
// are never coming back
f.mTarget = target;
}
}
}
}
}
}
}
}
if (f.mState != newState) {
Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+ "expected state " + newState + " found " + f.mState);
f.mState = newState;
}
}
OP_REMOVE操作會把指定的fragment從FragmentManagerImpl中移除,移除過程中會視配置情況進行狀態保存、移除view、釋放fragment、FragmentManagerImpl調度其他fragment等處理。
REPLACE操作類型
通過調用FragmentTransaction的replace方法,傳入指定的佈局容器ID和fragment,達到替換佈局容器中的fragment的view。
[FragmentTransaction.java]
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
// 必須指定佈局容器ID
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
添加OP_REPLACE類型的Op到mOps集合中。
接着看執行命令操作的方法executeOpsTogether:
[FragmentManagerImpl.java]
private void executeOpsTogether(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
// ···
for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
final BackStackRecord record = records.get(recordNum);
final boolean isPop = isRecordPop.get(recordNum);
if (!isPop) {
// 根據操作類型進行展開操作
oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
} else {
oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
}
addToBackStack = addToBackStack || record.mAddToBackStack;
}
// ···
// 執行操作
executeOps(records, isRecordPop, startIndex, endIndex);
// ···
}
該方法中再執行命令操作前會先調用BackStackRecord的expandOps方法中根據操作類型進行展開操作。
[BackStackRecord.java]
Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
// 遍歷mOps集合中的Op
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.mCmd) {
case OP_ADD:
case OP_ATTACH:
added.add(op.mFragment);
break;
case OP_REMOVE:
case OP_DETACH: {
added.remove(op.mFragment);
if (op.mFragment == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
opNum++;
oldPrimaryNav = null;
}
}
break;
case OP_REPLACE: {
final Fragment f = op.mFragment;
final int containerId = f.mContainerId;
// 標記該fragment是否添加過
boolean alreadyAdded = false;
// 遍歷FragmentManagerImpl的mAdded中的Fragment
for (int i = added.size() - 1; i >= 0; i--) {
final Fragment old = added.get(i);
// 判斷是否指定過相同的佈局容器ID
if (old.mContainerId == containerId) {
// 判斷指定了相同佈局容器的那個fragment是否就是這個fragment
if (old == f) {
// 標記爲true
alreadyAdded = true;
} else {
// This is duplicated from above since we only make
// a single pass for expanding ops. Unset any outgoing primary nav.
if (old == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
opNum++;
oldPrimaryNav = null;
}
// 創建OP_REMOVE的操作
final Op removeOp = new Op(OP_REMOVE, old);
removeOp.mEnterAnim = op.mEnterAnim;
removeOp.mPopEnterAnim = op.mPopEnterAnim;
removeOp.mExitAnim = op.mExitAnim;
removeOp.mPopExitAnim = op.mPopExitAnim;
// 添加進mOps中
mOps.add(opNum, removeOp);
// 移除指定的佈局容器中的那個fragment
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
// 若該fragment已經添加了,移除這個操作即可
mOps.remove(opNum);
opNum--;
} else {
// 將這個操作的類型修改成OP_ADD
op.mCmd = OP_ADD;
// 將fragment添加進mAdded中
added.add(f);
}
}
break;
case OP_SET_PRIMARY_NAV: {
// ···
}
break;
}
}
return oldPrimaryNav;
}
可以看到OP_REPLACE操作其實是調整爲OP_REMOVE+OP_ADD。
HIDE和SHOW操作類型
通過FragmentTransaction的hide和show方法,可以將指定的fragment隱藏和顯示。
[FragmentTransaction.java]
public FragmentTransaction hide(@NonNull Fragment fragment) {
addOp(new Op(OP_HIDE, fragment));
return this;
}
public FragmentTransaction show(@NonNull Fragment fragment) {
addOp(new Op(OP_SHOW, fragment));
return this;
}
添加OP_HIDE或OP_SHOW類型的命令。
接着看處理的部分,在executeOps方法的OP_HIDE case和OP_SHOW case中,會調用FragmentManagerImpl的hideFragment和showFragment方法:
[FragmentManagerImpl.java]
public void hideFragment(Fragment fragment) {
if (DEBUG) Log.v(TAG, "hide: " + fragment);
if (!fragment.mHidden) {
// 將mHidden成員標記爲true
fragment.mHidden = true;
// Toggle hidden changed so that if a fragment goes through show/hide/show
// it doesn't go through the animation.
fragment.mHiddenChanged = !fragment.mHiddenChanged;
}
}
public void showFragment(Fragment fragment) {
if (DEBUG) Log.v(TAG, "show: " + fragment);
if (fragment.mHidden) {
// 將mHidden成員標記爲false
fragment.mHidden = false;
// Toggle hidden changed so that if a fragment goes through show/hide/show
// it doesn't go through the animation.
fragment.mHiddenChanged = !fragment.mHiddenChanged;
}
}
Fragment中是通過mHidden成員來標記當前是要隱藏還是要顯示。
接下來在FragmentManagerImpl的moveToState方法中,會根據mHidden值來設置view的可見:
[FragmentManagerImpl.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// ···
if (f.mState <= newState) {
// ···
switch (f.mState) {
// ···
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) {
// 該處理從xml文件中添加Fragment
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) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(
"Cannot create fragment "
+ f
+ " for a container view with no id"));
}
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
String resName;
try {
resName = f.getResources().getResourceName(f.mContainerId);
} catch (Resources.NotFoundException e) {
resName = "unknown";
}
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ resName
+ ") for fragment " + f));
}
}
f.mContainer = container;
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);
}
// 在創建完view後,判斷mHidden是否爲true
if (f.mHidden) {
// 設置view爲GONE
f.mView.setVisibility(View.GONE);
}
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;
}
}
f.performActivityCreated(f.mSavedFragmentState);
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
// ···
}
} else if (f.mState > newState) {
// ···
}
// ···
}
void ensureInflatedFragmentView(Fragment f) {
if (f.mFromLayout && !f.mPerformedCreateView) {
f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
f.mView.setSaveFromParentEnabled(false);
// 若mHidden爲true,則將view設置爲GONE
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
} else {
f.mInnerView = null;
}
}
}
若mHidden設置爲true,則會將通過Fragment創建的view的可見屬性設置爲GONE。
回到FragmentManagerImpl的moveFragmentToExpectedState方法:
[FragmentManagerImpl.java]
void moveFragmentToExpectedState(Fragment f) {
// ···
moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
// ···
// mHiddenChanged默認爲false,當對fragment進行顯示隱藏操作變化時會變爲true
if (f.mHiddenChanged) {
completeShowHideFragment(f);
}
}
該方法中在執行完moveToState方法將fragment調整到最終目標狀態後,在該方法的結尾會判斷調用completeShowHideFragment方法,進入這個方法看看做了什麼動作:
[FragmentManagerImpl.java]
void completeShowHideFragment(final Fragment fragment) {
// 判斷該fragment中是否有創建view
if (fragment.mView != null) {
AnimationOrAnimator anim = loadAnimation(fragment, fragment.getNextTransition(),
!fragment.mHidden, fragment.getNextTransitionStyle());
// 判斷是否設置了Animator
if (anim != null && anim.animator != null) {
anim.animator.setTarget(fragment.mView);
// 判斷該fragment是否隱藏
if (fragment.mHidden) {
// isHideReplaced方法判斷是否正在進行隱藏的過渡動畫中
if (fragment.isHideReplaced()) {
// 正在進行隱藏的過渡動畫
fragment.setHideReplaced(false);
} else {
// 設置進行隱藏的過渡動畫
final ViewGroup container = fragment.mContainer;
final View animatingView = fragment.mView;
container.startViewTransition(animatingView);
// Delay the actual hide operation until the animation finishes,
// otherwise the fragment will just immediately disappear
anim.animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
container.endViewTransition(animatingView);
animation.removeListener(this);
if (fragment.mView != null && fragment.mHidden) {
fragment.mView.setVisibility(View.GONE);
}
}
});
}
} else {
// 若爲顯示,則將fragment的view設置爲VISIBLE
fragment.mView.setVisibility(View.VISIBLE);
}
anim.animator.start();
} else {
if (anim != null) {
// 未設置Animator,但設置了Animation
fragment.mView.startAnimation(anim.animation);
anim.animation.start();
}
final int visibility = fragment.mHidden && !fragment.isHideReplaced()
? View.GONE
: View.VISIBLE;
// 設置fragment的view的可見屬性
fragment.mView.setVisibility(visibility);
if (fragment.isHideReplaced()) {
fragment.setHideReplaced(false);
}
}
}
if (fragment.mAdded && isMenuAvailable(fragment)) {
mNeedMenuInvalidate = true;
}
// 把mHiddenChanged成員置回false
fragment.mHiddenChanged = false;
// 回調onHiddenChanged方法
fragment.onHiddenChanged(fragment.mHidden);
}
該方法中邏輯主要是過渡動畫和view可見屬性的設置。
總結
前文大致跟蹤了一個Fragment從新建到添加入FragmentActivity的過程。
首先FragmentManager將“添加Fragment”的行爲封裝成一個Op操作,再將Op加入一個事務BackStackRecord,然後將事務加入待執行隊列保存,之後通過Handler調度至主線程執行。
接着FragmentManager從遍歷待執行隊列中的事務,依次執行。執行過程中根據操作類型以及Fragment狀態和FragmentManager狀態,執行Fragment對應階段的處理和生命週期回調。