I . 介绍
FragmentManager和FragmentTransaction是Android中用于管理和操作Fragment事务的重要类之一。它提供了一系列方法,用于执行Fragment的添加、替换、移除以及回滚等操作。
通过深入理解FragmentManager和FragmentTransaction的源码,更好地掌握Fragment事务的管理和操作。
在安卓开发中,FragmentManager和FragmentTransaction是核心的API,用于管理和操作Fragment的交互和展示。了解源码和实现细节,对于安卓开发工程师至关重要。
- 本文旨在深入解析FragmentManager和FragmentTransaction的源码和实现细节,帮助读者更好地理解和应用该API。
- 我们将探讨事务的创建和提交过程,以及Fragment的添加、替换和移除操作的实现。
- 此外,我们还将研究事务回滚流程的实现。
- 通过本文的阅读,将能够更好地理解FragmentManager和FragmentTransaction的工作原理,进而提升自己在安卓开发领域的技能和水平。
II. 核心类和事物创建的代码
源码结构和核心类的功能
-
FragmentTransaction的源码结构主要由以下核心类组成:
- FragmentTransaction:该类是Fragment事务的顶层类,提供了事务操作的入口和控制方法。
- BackStackRecord:该类继承自FragmentTransaction,负责管理Fragment事务的回滚和撤销操作。它维护了一个Fragment事务的回退栈,允许开发者在需要时回滚或撤销之前的事务
- FragmentManagerImpl:该类是FragmentManager的实现类,负责管理Fragment的生命周期和事务。在FragmentTransaction中,通过FragmentManagerImpl来执行具体的事务操作。
- FragmentTransactionOp:该类用于描述Fragment事务的操作,每个事务操作都可以看作是一个FragmentTransactionOp的实例。它记录了操作的类型、Fragment对象以及其他相关信息。
- 这些核心类相互协作,实现了对Fragment的添加、替换和移除等操作的管理和控制。通过深入理解它们的功能和源码实现,我们能更好地理解FragmentTransaction的工作原理。
事务的创建和提交过程
kotlin
val transaction = fm.beginTransaction()
transaction.add(R.id.main, fragment,tag)
//transaction.remove(fragment)
//transaction.replace(R.id.main, fragment,tag)
transaction.commit()
@NonNull
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
- 创建事务:首先,通过FragmentManager的beginTransaction()方法获取一个FragmentTransaction实例,通过该实例进行后续的事务操作。
- 添加、替换或移除Fragment:调用FragmentTransaction的add()、replace()、remove()等方法,传入相应的Fragment对象和容器ID,来执行对应的操作。
- 设置事务动画:通过调用FragmentTransaction的setCustomAnimations()方法,可以为事务设置自定义的进出栈动画和过渡效果。
- 将事务添加到回退栈:通过调用FragmentTransaction的addToBackStack()方法,可以将事务添加到回退栈中,以便在需要时进行回滚或撤销。
- 提交事务:调用FragmentTransaction的commit()方法,将事务提交给FragmentManagerImpl执行。提交后,FragmentManagerImpl会根据事务的操作列表逐个执行相应的操作。
添加、替换和移除操作的实现
kotlin
@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
......
if (tag != null) {
fragment.mTag = tag;
}
if (containerViewId != 0) {
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
addOp(new Op(opcmd, fragment));
}
void addOp(Op op) {
mOps.add(op);
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
}
添加、替换和移除操作的源码如上,所有的操作最后都走到了doAddOp()方法中,将tag和containerId存储到fragment之后新建FragmentTransactionOp对象,并且存储到队列中。
III. 事务提交操作流程的源码实现
从commit方法开始,探索fragment最后如何添加上去的。
FragmentTransaction中commit()源码
kotlin
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
mCommitted = true;
...
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop) {
records.add(this);
isRecordPop.add(false);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
return true;
}
interface OpGenerator {
boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop);
}
- commit调用如上,commitAllowingStateLoss()和commit()的区别就是传入了一个不同的布尔值,最后都调用了commitInternal()。
- commitInternal()方法里面拦截了重复的提交,之后调用FragmentManager的方法enqueueAction(),这里传给enqueueAction的对象是OpGenerator。
- OpGenerator的实现generateOps()方法将自身添加到任务列表,在commit的之后执行逻辑的时候这个方法会被调用。
- 调用FragmentManager的方法enqueueAction(),接下来看它的源码。
FragmentManager中enqueueAction()源码
kotlin
void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
if (mHost == null) {
if (mDestroyed) {
throw new IllegalStateException("FragmentManager has been destroyed");
} else {
throw new IllegalStateException("FragmentManager has not been attached to a "
+ "host.");
}
}
checkStateLoss();
}
synchronized (mPendingActions) {
...
mPendingActions.add(action);
scheduleCommit();
}
}
void scheduleCommit() {
synchronized (mPendingActions) {
...
boolean pendingReady = mPendingActions.size() == 1;
if (pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
private Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions(true);
}
};
-
enqueueAction()方法中,首先进行的状态检测,前面传入的allowStateLoss如果为false,就检测fragment是否已经销毁,或者是不是已经保存了状态。如果在保存状态之后提交了操作,在恢复的时候可能会丢失掉这些提交,所以在commit的时候拦截并且抛出异常,如果想要跳过这个检查,调用commitAllowingStateLoss()即可。
-
之后把事务添加到列表,然后调用scheduleCommit()启动事务,这里可以注意到启动调用了Handler的post(),所以commit之后实际的处理是延迟的,时间是不确定的,这是一个特别重要的特性,在大多数时候可能都被忽略了,但在处理一些时间先后特别重要的事情的时候,如果忽略掉这个延迟,很大概率会发生不可预料的意外情况。
-
延迟之后回调到execPendingActions()。
FragmentManager中execPendingActions()源码
kotlin
boolean execPendingActions(boolean allowStateLoss) {
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
}
didSomething = true;
}
return didSomething;
}
private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isPop) {
boolean didSomething = false;
synchronized (mPendingActions) {
if (mPendingActions.isEmpty()) {
return false;
}
final int numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
return didSomething;
}
private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop) {
...
final int numRecords = records.size();
int startIndex = 0;
for (int recordNum = 0; recordNum < numRecords; recordNum++) {
...
int reorderingEnd = recordNum + 1;
executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
startIndex = reorderingEnd;
recordNum = reorderingEnd - 1;
}
}
-
这里的方法开始源码逻辑太多,我对源码做了最大程度的删减,只保留了最简单情况下的调用流程。
-
execPendingActions()中循环的调用generateOpsForPendingActions()和removeRedundantOperationsAndExecute()方法,这里的循环也是处理一个特殊情况,为了更方便的理解,将这里的循环直接看作先后调用一下两个方法。
-
generateOpsForPendingActions()方法中,调用commit时传入的OpGenerator对象的generateOps()方法,然后这里调用的removeCallbacks(),这个方法现在看来是无用的,等会源码到另一个地方,就会知道为什么这里需要remove。
-
generateOps()方法的源码,可以再回到前面commit部分再看下,在其中将自身作为BackStackRecord对象存入了列表中。虽然还有添加了BackStack的代码,但我们先忽略它。
-
removeRedundantOperationsAndExecute()方法做了比较多的删减,最简洁的代码,就是一个循环,对列表中每一个BackStackRecord执行executeOpsTogether()方法。但这还是太复杂,因为他是一个列表,我们再假设这个列表只有一个元素,因为我们前面正常的调用只创建和提交了一次。
FragmentManager中executeOpsTogether()源码
kotlin
private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
boolean addToBackStack = false;
...
//step1
mTmpAddedFragments.addAll(mFragmentStore.getFragments());
Fragment oldPrimaryNav = getPrimaryNavigationFragment();
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);
}
}
mTmpAddedFragments.clear();
//step2
executeOps(records, isRecordPop, startIndex, endIndex);
if (USE_STATE_MANAGER) {
// The last operation determines the overall direction, this ensures that operations
// such as push, push, pop, push are correctly considered a push
boolean isPop = isRecordPop.get(endIndex - 1);
// Ensure that Fragments directly affected by operations
// are moved to their expected state in operation order
for (int index = startIndex; index < endIndex; index++) {
BackStackRecord record = records.get(index);
//step3
for (FragmentTransaction.Op op : record.mOps) {
Fragment fragment = op.mFragment;
if (fragment != null) {
FragmentStateManager fragmentStateManager =
createOrGetFragmentStateManager(fragment);
fragmentStateManager.moveToExpectedState();
}
}
}
// And only then do we move all other fragments to the current state
//step4
moveToState(mCurState, true);
}
}
//FragmentManager
private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
for (int i = startIndex; i < endIndex; i++) {
final BackStackRecord record = records.get(i);
record.executeOps();
}
}
//BackStackRecord
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;
switch (op.mCmd) {
case OP_ADD:
f.setNextAnim(op.mEnterAnim);
mManager.setExitAnimationOrder(f, false);
mManager.addFragment(f);
break;
case OP_REMOVE:
f.setNextAnim(op.mExitAnim);
mManager.removeFragment(f);
break;
...
}
}
}
//FragmentManager
void addFragment(@NonNull Fragment fragment) {
FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
fragment.mFragmentManager = this;
mFragmentStore.makeActive(fragmentStateManager);
if (!fragment.mDetached) {
mFragmentStore.addFragment(fragment);
}
}
- 这里还是删除了大量的代码,按照刚才提到的假设这个列表只有一个元素,就是我们最开始创建的BackStackRecord,并且isPop参数也为false,并且没有设置回退相关的属性。
- 第一步,调用BackStackRecord的expandOps(),这个方法一方面根据操作计算出新的oldPrimaryNav,可以理解为当前展示的fragment,例如remove的fragment如果是展示的fragment就需要返回空;另一方面将操作拆解成更基础的操作,比如replace操作需要拆解为oldPrimaryNav的remove和新的fragment的add。具体的代码因为篇幅问题不再贴出来。
- 第二步,FragmentManager的方法executeOps开始执行操作,调用到BackStackRecord的executeOps方法,其中根据不同的分类执行不同的操作,比如add调用FragmentManager的addFragment方法,remove调用FragmentManager的removeFragment方法。addFragment通过FragmentStore对象添加,不再展开。
- 第三步,对于操作列表中的fragment,调用FragmentStateManager的moveToExpectedState方法,将fragment流转到所对应的生命周期。
- 第四步,对所有已经添加的fragment流转生命周期,主要针对不再操作列表中的fragment,也是调用到FragmentStateManager的moveToExpectedState方法。
如何让事务同步执行
在调用了FragmentTransaction的commit方法之后,任务被添加到了handler中延迟去执行,但如果我们需要它立即去执行的话,按照前面的源码去理解,直接调用Runnable中回调的execPendingActions()去主动触发事务的处理,处理的过程中源码中已经将Handler回调清除掉,并且FragmentStateManager源码中提供了executePendingTransactions()方法供直接使用,这个方法会将所有的FragmentTransaction事务全部执行,在commit之后立即执行executePendingTransactions()方法,就可以同步的处理事务。
kotlin
public boolean executePendingTransactions() {
boolean updates = execPendingActions(true);
forcePostponedTransactions();
return updates;
}
另外FragmentTransaction还提供了commitNow()和commitNowAllowingStateLoss()方法,commitNow()调用到FragmentManager的execSingleAction()方法,源码如下:
kotlin
@Override
public void commitNow() {
disallowAddToBackStack();
mManager.execSingleAction(this, false);
}
void execSingleAction(@NonNull OpGenerator action, boolean allowStateLoss) {
if (allowStateLoss && (mHost == null || mDestroyed)) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
ensureExecReady(allowStateLoss);
if (action.generateOps(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
}
}
- execSingleAction()方法中,也都是熟悉的代码,跟前面的execPendingActions()方法极其类似,区别就是这里只是处理这一个FragmentTransaction的commit,对列表中的事务不做处理,就实现了将这一次的提交单独同步执行,不影响其他任务的排序。
Ⅳ. 事务回滚流程的源码实现
- 在添加fragment的时候,可以设置属性让fragment可以回滚,比如在顶部fragment点击返回,会滚到上一个fragment。
- 回滚操作是通过FragmentManager的popBackStack()方法实现的。直接上源码:
FragmentManager中popBackStack()源码
kotlin
public void popBackStack() {
enqueueAction(new PopBackStackState(null, -1, 0), false);
}
private class PopBackStackState implements OpGenerator {
@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop) {
return popBackStackState(records, isRecordPop, mName, mId, mFlags);
}
}
boolean popBackStackState(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop, @Nullable String name, int id, int flags) {
if (mBackStack == null) {
return false;
}
if (name == null && id < 0 && (flags & POP_BACK_STACK_INCLUSIVE) == 0) {
int last = mBackStack.size() - 1;
if (last < 0) {
return false;
}
records.add(mBackStack.remove(last));
isRecordPop.add(true);
}
return true;
}
- popBackStack()调用了enqueueAction,这个方法跟添加一样,传入OpGenerator对象,最终在execPendingActions方法中回调对数据进行处理。
- 这里看到回调中进入到FragmentManager的popBackStackState()方法,在这里从mBackStack堆栈中弹出最后一个BackStackRecord,而mBackStack的添加就是我们在提交的时候设置了属性,就会保留在这里。
- 这里弹出BackStackRecord之后注意isRecordPop设置了true,后面的区别也都是来自这个属性。
- execPendingActions执行完成后,根据前面看到的源码,下一步实际的操作到了executeOpsTogether中,前面的源码为了方便,去除了isRecordPop为true的源码,这里贴出来再看一次。
FragmentManager中executeOpsTogether()源码
kotlin
private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
@NonNull 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;
}
...
if (USE_STATE_MANAGER) {
// The last operation determines the overall direction, this ensures that operations
// such as push, push, pop, push are correctly considered a push
boolean isPop = isRecordPop.get(endIndex - 1);
// Ensure that Fragments directly affected by operations
// are moved to their expected state in operation order
for (int index = startIndex; index < endIndex; index++) {
BackStackRecord record = records.get(index);
if (isPop) {
// Pop operations get applied in reverse order
for (int opIndex = record.mOps.size() - 1; opIndex >= 0; opIndex--) {
FragmentTransaction.Op op = record.mOps.get(opIndex);
Fragment fragment = op.mFragment;
if (fragment != null) {
FragmentStateManager fragmentStateManager =
createOrGetFragmentStateManager(fragment);
fragmentStateManager.moveToExpectedState();
}
}
} else {
for (FragmentTransaction.Op op : record.mOps) {
Fragment fragment = op.mFragment;
if (fragment != null) {
FragmentStateManager fragmentStateManager =
createOrGetFragmentStateManager(fragment);
fragmentStateManager.moveToExpectedState();
}
}
}
}
// And only then do we move all other fragments to the current state
moveToState(mCurState, true);
}
}
- 第一个区别点在与expandOps替换成了trackAddedFragmentsInPop方法,两个方法原理是一样的,计算当前显示的fragment,不过跟之前反了过来。
- 第二个区别在生命周期同步的时候,顺序反过来,从最后一个开始同步。
- 在executeOpsTogether之后,走到executeOps()开始处理回调,在其中也是替换了方法,正常走到BackStackRecord的executeOps方法,现在走到BackStackRecord的executePopOps方法。源码如下
3. FragmentManager中executeOps()源码
kotlin
private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull 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);
record.executeOps();
}
}
}
void executePopOps(boolean moveToState) {
for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
final Op op = mOps.get(opNum);
Fragment f = op.mFragment;
switch (op.mCmd) {
case OP_ADD:
f.setNextAnim(op.mPopExitAnim);
mManager.setExitAnimationOrder(f, true);
mManager.removeFragment(f);
break;
case OP_REMOVE:
f.setNextAnim(op.mPopEnterAnim);
mManager.addFragment(f);
break;
...
}
}
}
-
executePopOps首先不同的是也是从后往前遍历事务并操作,与提交的时候反过来。
-
其中处理操作也是反过来的,比如add调用remove方法,remove调用add方法。
-
通过这样的各种各样的反操作,将最顶部的fragment弹出,并且从屏幕中移除,因为这里处理的时候,已经是提交时解析过的事务,replace操作也已经拆解,所以反向操作的时候,也会把之前的fragment添加回来,完成了回滚操作。
以上就是整个提交的流程。