Fragment从源码角度看add和replace过程
Posted ITRenj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fragment从源码角度看add和replace过程相关的知识,希望对你有一定的参考价值。
-
简书
-
CSDN
Fragment(一)从源码角度看add和replace过程
通过这篇博客,我们能知道以下问题:
Fragment
add()
和replace()
方法差别- 从源码角度分析
add()
和replace()
方法
1. Fragment
add()
和 replace()
方法差别
add()
是添加 Fragment
到容器布局中,再搭配事务对象(FragmentTransaction
)的 show()
和 hide()
方法来显示和隐藏 Fragment
,replace()
顾名思义“替换”,会销毁布局容器内的已有 Fragment
,然后重新创建一个新的 Fragment
显示到布局容器中。通过一下两种方式的生命周期方式对比:
add-show/hide 方式生命周期:
replace 方式生命周期:
我们可以发现,replace()
方式替换的,被替换的Fragment
会被彻底销毁,新的会重新创建,每一次的加载到界面到从界面消失的过程都是一个完整的生命周期;而 add()
结合 show()/hide()
方式的Fragment,切换时并不会彻底销毁 Fragment
,而是走了 onHiddenChanged()
回调方法,改变了对用户的可见性,同时注意,这个方法并不是生命周期方法。他是在FragmentTransaction
调用 show()
和 hide()
方法时才会回调的方法。
注意:如果将Fragment加入回退栈
-
对于add方式,生命周期方法回调无影响
-
对于 replace 方式,那么他在被替换的时候是不会走销毁的方法的,它的生命周期方法如下:
======================= 回退栈的使用说明 =======================
private fun changeShowFragment(showFragment: Fragment) supportFragmentManager.beginTransaction() .replace(R.id.fl_content, showFragment) // 将Fragment增加到回退栈,并指定回退栈的名称为 replaceFragment .addToBackStack("replaceFragment") .commitAllowingStateLoss() // 重写返回按钮 override fun handlerOnBack() // 判断回退栈是否有未出栈的Fragment if(supportFragmentManager.backStackEntryCount > 1) supportFragmentManager.popBackStack() else super.handlerOnBack()
======================= 回退栈的使用说明 结束 =======================
2. 从源码角度分析 add()
和 replace()
方法
上面从打印结果知道了 add()
和 replace()
的差别,这一小节,我们从源码的角度来分析、查看系统对各个方法的调用过程。
说明:源码版本是 AndroidX库,具体 androidx.fragment:1.3.4 版本
FragmentManager
和 FragmentTransaction
的获取
FragmentActivity
中获取 FragmentManager
和 FragmentTransaction
首先看看 FragmentManager
和 FragmentTransaction
的获取
-
在
FragmentActivity
中获取FragmentManager
final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); @NonNull public FragmentManager getSupportFragmentManager() return mFragments.getSupportFragmentManager();
通过
mFragments
获取,mFragments
就是FragmentController
,也是FragmentActivity
的一个成员变量,通过静态方法创建,并且传递了HostCallbacks
对象(注意:HostCallbacks extends FragmentHostCallback
,HostCallbacks继承至FragmentHostCallback),这个对象就是后面会使用到的mHost
。具体创建过程如下:@NonNull public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) return new FragmentController(checkNotNull(callbacks, "callbacks == null")); // 构造私有,通过静态方法创建,并且为 mHost 赋值 private FragmentController(FragmentHostCallback<?> callbacks) mHost = callbacks;
FragmentActivity
中调用getSupportFragmentManager()
方法,具体是调用mFragments.getSupportFragmentManager()
方法。所以我们看一下FragmentController
(上面说过了 mFragments 就是 FragmentController)的getSupportFragmentManager()
方法:@NonNull public FragmentManager getSupportFragmentManager() return mHost.mFragmentManager;
直接取的是
mHost
的变量mFragmentManager
,mHost
就是前面传递进来的HostCallbacks
对象,那么我们看看这个变量是什么:final FragmentManager mFragmentManager = new FragmentManagerImpl();
这个变量实际上是在
FragmentHostCallback
定义的,前面我们说过HostCallbacks
继承至FragmentHostCallback
,取到FragmentHostCallback
类中是没有问题的。看名字应该是一个FragmentManager
的实现类。具体定义如下:class FragmentManagerImpl extends FragmentManager
没错,确实是继承
FragmentManager
,但是类中没有任何具体的方法,FragmentManager
本身是抽象的,不能创建对象,所以通过一个实现类来创建实例。 -
在
FragmentActivity
中获取FragmentTransaction
通过以上分析,我们知道了在Activity
中获取到的FragmentManager
就是FragmentManagerImpl
对象,那么我们在来看看FragmentTransaction
是怎样取的,他是通过FragmentManager
取的,也就是FragmentManagerImpl
对象调用beginTransaction()
方法的返回值,通过前面我们知道这个方法实际上是在FragmentManager
实现的,所以看看FragmentManager
中的beginTransaction()
方法:@NonNull public FragmentTransaction beginTransaction() return new BackStackRecord(this);
很简单,直接创建了一个
BackStackRecord
对象返回,看看BackStackRecord
类的定义:final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManager.OpGenerator
到了这里,FragmentActivity
中获取 FragmentManager
和 FragmentTransaction
的过程已经知道了,那么接下来看看在 Fragment
中获取 FragmentManager
和 FragmentTransaction
的过程。
Fragment
中获取 FragmentManager
和 FragmentTransaction
-
在
Fragment
中获取FragmentManager
在Fragment
中获取FragmentManager
,是通过getChildFragmentManager()
方法,看一下Fragment
中这个方法的定义:@NonNull final public FragmentManager getChildFragmentManager() if (mHost == null) throw new IllegalStateException("Fragment " + this + " has not been attached yet."); return mChildFragmentManager;
直接返回了
mChildFragmentManager
对象,看看这个对象的定义:FragmentManager mChildFragmentManager = new FragmentManagerImpl();
直接创建了
FragmentManagerImpl
对象,赋值给父类FragmentManager
,这个类我们前面已经说过了。 -
在
Fragment
中获取FragmentTransaction
既然FragmentManager
对象是FragmentManagerImpl
,和FragmentActivity
中一样,那么通过FragmentManager
获取FragmentTransaction
也就是相同的了,这里就不再重复了。
扩展
通过前面的了解,我们知道了 FragmentController
中的 mHost
就是在创建 FragmentController
时传递进来的 HostCallbacks
对象,我们现在来看看 Fragment
中的 mHost
是在哪里定义的。
通过查看源码,我们发现 Fragment
中的 mHost
的赋值位置是在 FragmentLayoutInflaterFactory
类的 onCreateView()
方法中,这个方法被调用的过程是:
FragmentActivity#onCreateView()
->FragmentActivity#dispatchFragmentsOnCreateView()
->FragmentController#onCreateView()
->FragmentLayoutInflaterFactory#onCreateView()
在 FragmentLayoutInflaterFactory#onCreateView()
中有这样一行代码:
fragment.mHost = mFragmentManager.getHost();
其中的 mFragmentManager
是在构造方法中传递进来的
FragmentLayoutInflaterFactory(FragmentManager fragmentManager)
mFragmentManager = fragmentManager;
FragmentLayoutInflaterFactory
的创建位置在 FragmentManager
中:
private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
new FragmentLayoutInflaterFactory(this);
作为 FragmentManager
的一个全局成员变量,并且将 this
传递给 FragmentLayoutInflaterFactory
,所以最终 Fragment
中的 mHost
就是 FragmentManager
中的 getHost()
方法返回值:
@NonNull
FragmentHostCallback<?> getHost()
return mHost;
FragmentManager
中的 mHost
赋值位置在 FragmentManager
中的 attachController()
方法中(篇幅原因,同时方法中的内容不是这里关注的重点,具体方法内容就不放进来了),而这个方法的调用位置有两个:一个是 Activity
中调用,一个在 Fragment
中调用,这也是很好理解的,因为Fragment
中还可以嵌套Fragment
,那么子Fragment
中的 mHost
从哪里来了,就需要从父Fragment
中来了。具体的调用流程如下:
- Activity:
FragmentActivity()
构造 ->FragmentActivity#init()
->FragmentController#attachHost()
->FragmentManager#attachController()
- Fragment:
Fragment#performAttach()
(该方法中还会调用Fragment的onAttach()方法,它的调用位置就不再这里说了) ->FragmentManager#attachController()
在Activity
的调用流程中,传递的就是在 FragmentActivity
中创建的 HostCallbacks
对象,在 Fragment
中保存;在 Fragment
的调用流程中,Fragment#performAttach()
方法传递了当前的成员变量 mHost
,而这个变量值就是 Activity
中传递过来的。 也就是说,就是在同一个 Activity
中的所有 Fragment
都是共用一个 FragmentController
。
到这里,我们就将 add()
、replace()
过程的使用到的部分类有了一定的了解了,接下来就看看这两种方式的具体流程。
add()
-> show()/hide()
supportFragmentManager.beginTransaction()
.add(R.id.fl_content, addFragment1)
.add(R.id.fl_content, addFragment2)
.commitAllowingStateLoss()
supportFragmentManager.beginTransaction()
.show(showFragment)
.hide(hideFragment)
.commitAllowingStateLoss()
add()
add()
方法是属于 FragmentTransaction
类,我们看一下具体的代码,其中有多个重载方法
@NonNull
public final FragmentTransaction add(@NonNull Class<? extends Fragment> fragmentClass,
@Nullable Bundle args, @Nullable String tag)
// 调用 createFragment() 方法,创建Fragment实例对象,然后调用重载方法
return add(createFragment(fragmentClass, args), tag);
@NonNull
public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)
// 调用 doAddOp() 方法,传递 OP_ADD 参数
doAddOp(0, fragment, tag, OP_ADD);
return this;
@NonNull
public final FragmentTransaction add(@IdRes int containerViewId,
@NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args)
// 调用重载方法
return add(containerViewId, createFragment(fragmentClass, args));
@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment)
// 调用 doAddOp() 方法,传递 OP_ADD 参数
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
@NonNull
public final FragmentTransaction add(@IdRes int containerViewId,
@NonNull Class<? extends Fragment> fragmentClass,
@Nullable Bundle args, @Nullable String tag)
// 调用重载方法
return add(containerViewId, createFragment(fragmentClass, args), tag);
@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag)
// 调用 doAddOp() 方法,传递 OP_ADD 参数
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
FragmentTransaction add(@NonNull ViewGroup container, @NonNull Fragment fragment,
@Nullable String tag)
fragment.mContainer = container;
// 调用重载方法
return add(container.getId(), fragment, tag);
======================= 针对上面 add()
方法的一个说明:=======================
-
以上就是
add()
的各个方法,他们最终调用的都是doAddOp()
方法,并且传递了容器id,Fragment
对象,tag
和OP_ADD
参数(重点注意OP_ADD参数,) -
createFragment()
方法的作用是根据Fragment
的Class
创建对象@NonNull private Fragment createFragment(@NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args) // 调用 FragmentFactory#instantiate() 方法 Fragment fragment = mFragmentFactory.instantiate(mClassLoader, fragmentClass.getName()); if (args != null) // 设置参数 fragment.setArguments(args); return fragment;
FragmentFactory#instantiate()
方法@NonNull public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) try // 通过反射创建对象,Fragment 必须有无参构造,否则会报错 Class<? extends Fragment> cls = loadFragmentClass(classLoader, className); return cls.getConstructor().newInstance(); catch (Exception e)
======================= 针对上面 add()
方法的一个说明结束 =======================
继续查看 FragmentTransaction#doAddOp()
方法
// FragmentTransaction#doAddOp()
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd)
final Class<?> fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
// 省略对参数进行判断
// 调用 addOp() 方法,这里的 opcmd 参数实际上就是 OP_ADD
addOp(new Op(opcmd, fragment));
// FragmentTransaction#addOp()
void addOp(Op op)
mOps.add(op);
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
Op
类的定义
static final class Op
int mCmd; // 操作类型 可选有:OP_NULL|OP_ADD|OP_REPLACE|OP_REMOVE|OP_HIDE|OP_SHOW|OP_DETACH|OP_ATTACH
Fragment mFragment; // 操作的Fragment对象
int mEnterAnim; // 如此动画
int mExitAnim; // 退出动画
int mPopEnterAnim; // 弹入动画
int mPopExitAnim; // 弹出动画
Lifecycle.State mOldMaxState; // 老的生命周期状态值
Lifecycle.State mCurrentMaxState; // 当前的生命周期状态值(当前需要改变成那种状态)
Op(int cmd, Fragment fragment)
this.mCmd = cmd;
this.mFragment = fragment;
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
这两个方法比较简单,就是对参数进行判断,然后创建一个 Op
对象(注意创建对象的第一个参数实际就是 OP_ADD),将参数和对象保存进去,然后将整个 Op
对象添加到 FragmentTransaction#mOps
列表中。接下来就看 show()/hide()
方法的调用过程
show()/hide()
方法:
// FragmentTransaction#show() 方法
@NonNull
public FragmentTransaction show(@NonNull Fragment fragment)
// 调用 addOp() 方法,传递 OP_SHOW 参数
addOp(new Op(OP_SHOW, fragment));
return this;
// FragmentTransaction#show() 方法
@NonNull
public FragmentTransaction hide(@NonNull Fragment fragment)
// 调用 addOp() 方法,传递 OP_HIDE 参数
addOp(new Op(OP_HIDE, fragment));
return this;
这里都是直接调用了 addOp()
方法,只是在创建 Op
对象时传递了不同的参数, add()
方法传递的是 OP_ADD,show()
方法传递的是 OP_SHOW, hide()
方法传递的是 OP_HIDE
通过上面我们发现,这几个方法并没有什么实际的操作,仅仅是检查参数和保存数据,那么他们真正的操作应该就是在 FragmentTransaction#commit()
方法上了,这个方法我们之后在看,因为 add()
、 show()
、 hide()
方法都是保存数据,那我们先来看看 replace()
方法是不是也是只保存了需要操作的数据了。
replace()
同样,replace()
方法是属于 FragmentTransaction
类,我们看一下具体的代码
@NonNull
public final FragmentTransaction replace(@IdRes int containerViewId,
@NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args)
return replace(containerViewId, fragmentClass, args, null);
@NonNull
public final FragmentTransaction replace(@IdRes int containerViewId,
@NonNull Class<? extends Fragment> fragmentClass,
@Nullable Bundle args, @Nullable String tag)
return replace(containerViewId, createFragment(fragmentClass, args), tag);
@NonNull
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment)
return replace(containerViewId, fragment, null);
@NonNull
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag)
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
同样有多个重载方法,但是多个重载方法最终调用的也是 doAddOp()
方法,与我们上面的猜想一样,只是传递的参数是 OP_REPLACE
,与上面的对应也是关系类似。
到了这一步,我们就发现了,add()
、 show()
、 hide()
以及replace()
方法都是创建了一个 Op
对象,并保存到 FragmentTransaction#mOps
列表中去,实际操作应该是都是在 FragmentTransaction#commit()
方法中了,我们接着就来看看这个方法。
FragmentTransaction#commit()
commit()
方法有多个类似的,我们这里看看常用的 commit()
、 commitAllowingStateLoss()
两个,其实其他的几个也一样,他们最终调用的方法都是一样的,明白了这两个,其他的也就明白了。需要注意的是,这些方法在 FragmentTransaction
类中是抽象的,具体的实现在
BackStackRecord
类中,通过上面的分析我们也知道了,beginTransaction()
方法获取的就是 BackStackRecord
类对象。
BackStackRecord
类中的这两个方法具体实现如下:
@Override
public int commit()
return commitInternal(false);
@Override
public int commitAllowingStateLoss()
return commitInternal(true);
都是调用了 commitInternal()
方法,只是参数不一样,一个 false
,一个 true
,这个参数表示是否允许丢失状态信息,具体的作用我们通过源码继续了解。接着往下继续看 BackStackRecord#commitInternal()
方法
int commitInternal(boolean allowStateLoss)
// 防止重复提交
if (mCommitted) throw new IllegalStateException("commit already called");
// 省略打印日志代码
// 修改状态,正在提交
mCommitted = true;
// 判断是否需要保存到回退栈,调用了 addToBackStack() 方法才会为 true
if (mAddToBackStack)
mIndex = mManager.allocBackStackIndex();
else
mIndex = -1;
// 将操作放入到队列中,调用的是 FragmentManager 类中的方法
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
FragmentManager#enqueueAction()
方法:
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)
// mHost 是在 FragmentActivity 中创建,然后传递过来的,如果为 null,表示Fragment的容器布局对应的页面不存在了
if (mHost == null)
if (allowStateLoss)
// This FragmentManager isn't attached, so drop the entire transaction.
return;
throw new IllegalStateException("Activity has been destroyed");
// 把操作添加到 mPendingActions 中
mPendingActions.add(action);
// 继续调用方法
scheduleCommit();
FragmentManager#scheduleCommit()
方法:
void scheduleCommit()
synchronized (mPendingActions)
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions.size() == 1;
// 判断是否有已经准备好的,需要执行的任务
if (postponeReady || pendingReady)
// 先移除已有的消息,然后再通过Handler发送消息开始处理
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
// 更新返回状态是否启用,根据回退栈中的Fragment类确定
updateOnBackPressedCallbackEnabled();
主要来看FragmentManager#Handler
需要执行的任务 mExecCommit
做了什么
private Runnable mExecCommit = new Runnable()
@Override
public void run()
execPendingActions(true);
;
boolean execPendingActions(boolean allowStateLoss)
// 执行之前已推迟但现在已准备就绪的事务
ensureExecReady(allowStateLoss);
boolean didSomething = false;
// 1. 根据事务对象生成待执行的操作,并添加到记录中
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop))
mExecutingActions = true;
try
// 2. 移除多余的操作并执行
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
finally
// 清空缓存队列数据
cleanupExec();
didSomething = true;
updateOnBackPressedCallbackEnabled();
doPendingDeferredStart();
mFragmentStore.burpActive();
return didSomething;
我们一个一个方法来看:
-
首先看一下
FragmentManager#generateOpsForPendingActions()
方法// FragmentManager#generateOpsForPendingActions() 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 列表 mPendingActions.clear(); mHost.getHandler().removeCallbacks(mExecCommit); return didSomething;
在这个方法中遍历
mPendingActions
调用元素(其中的元素是在FragmentManager#enqueueAction()
方法中添加的BackStackRecord
对象)的generateOps()
方法,我们看一下这个方法:// BackStackRecord#generateOps() 方法 @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;
将当前对象加入到
records
中,实际上也就是FragmentManager#mTmpRecords
列表,并且给FragmentManager#mTmpIsPop
增加了false
元素,最后还根据是否需要加入到回退栈进行处理了。在
generateOpsForPendingActions()
中,执行完generateOps()
方法后就清空了FragmentManager#mPendingActions
列表。这个方法到这里就差不多了。我们回头接着看另外一个方法。 -
查看另一个
FragmentManager#removeRedundantOperationsAndExecute()
方法:// FragmentManager#removeRedundantOperationsAndExecute() private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isRecordPop) // ... if (startIndex != numRecords) executeOpsTogether(records, isRecordPop, startIndex, numRecords);
接着看
FragmentManager#executeOpsTogether()
方法:// FragmentManager#executeOpsTogether() 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; if (mTmpAddedFragments == null) mTmpAddedFragments = new ArrayList<>(); else mTmpAddedFragments.clear(); 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) // 1. 不是出栈,走这里 oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav); else oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav); addToBackStack = addToBackStack || record.mAddToBackStack; mTmpAddedFragments.clear(); // ... // 2. 展开操作 executeOps(records, isRecordPop, startIndex, endIndex); // ... // 根据是否加入回退栈进行处理 if (addToBackStack) reportBackStackChanged();
这里把不是特别重要的代码去掉了,主要注意两步:
-
record.expandOps(mTmpAddedFragments, oldPrimaryNav)
:这一步主要是操作展开(第二个参数与androidX导航组件相关,这里不管他)。比如说一个replace操作,需要把之前的Fragment
的移除掉和添加新的Fragment
的操作,并把新的操作对象Op
添加到mOps
列表中,这个列表我们在上面也看到过,不管是add还是replace都会调用FragmentTransaction#addOp()
方法将一个Op
对象添加到mOps
中。看一下OP_REPLACE
操作的代码case OP_REPLACE: final Fragment f = op.mFragment; final int containerId = f.mContainerId; boolean alreadyAdded = false; for (int i = added.size() - 1; i >= 0; i--) final Fragment old = added.get(i); if (old.mContainerId == containerId) if (old == f) alreadyAdded = true; else // 先移除老的Fragment操作,构建 Op 对象,保存到 mOps 列表 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.add(opNum, removeOp); added.remove(old); opNum++; if (alreadyAdded) // 如果已经存在,多余操作,删除 mOps.remove(opNum); opNum--; else // 没有,将操作改为 OP_ADD op.mCmd = OP_ADD; added.add(f);
对于replace操作,先是判断了是否已经存在(防止重复添加,如果是重复添加,这一步就是多余的,直接移除此次操作);如果不存在,将先将需要被替换的
Fragment
移除掉(也是构建一个Op
对象,指定OP_REMOVE
(移除)操作),然后将新的Fragment
操作由OP_REPLACE
修改为OP_ADD
:新增。 -
接下来看一下另一个
FragmentManager#executeOps(records, isRecordPop, startIndex, endIndex)
方法FragmentManager#executeOps(records, isRecordPop, startIndex, endIndex) 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); boolean moveToState = i == (endIndex - 1); record.executePopOps(moveToState); else record.bumpBackStackNesting(1); // 不是出栈操作,走else到这里 record.executeOps();
继续查看
BackStackRecord#expandOps()
方法: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.setPopDirection(false); f.setNextTransition(mTransition); f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames); // 1. 根据操作类型进行对应操作,我们主要看 OP_ADD,因为不管是 add 还是 replace 都是走的这一步,其他的操作我们就不一个一个看了。 switch (op.mCmd) case OP_ADD: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.setExitAnimationOrder(f, false); mManager.addFragment(f); break; case OP_REMOVE: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.removeFragment(f); break; case OP_HIDE: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.hideFragment(f); break; case OP_SHOW: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.setExitAnimationOrder(f, false); mManager.showFragment(f); break; case OP_DETACH: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.detachFragment(f); break; case OP_ATTACH: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.setExitAnimationOrder(f, false); mManager.attachFragment(f); break; case OP_SET_PRIMARY_NAV: mManager.setPrimaryNavigationFragment(f); break; case OP_UNSET_PRIMARY_NAV: mManager.setPrimaryNavigationFragment(null); break; case OP_SET_MAX_LIFECYCLE: mManager.setMaxLifecycle(f, op.mCurrentMaxState); break; default: throw new IllegalArgumentException("Unknown cmd: " + op.mCmd); // 2. 如果不是add操作,就会走这里 if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) if (!FragmentManager.USE_STATE_MANAGER) mManager.moveFragmentToExpectedState(f); // 3. 最终都会走到这里来 if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) // Added fragments are added at the end to comply with prior behavior. mManager.moveToState(mManager.mCurState, true);
这个方法可以分为三步:
1. 遍历mOps
操作列表,根据操作类型进行对应操作
2. 如果不是add操作,就调用FragmentManager.moveFragmentToExpectedState(f)
3. 调用FragmentManager.moveToState(int newState, boolean always)
-
-
我们一步一步看,首先第一步,
case
中调用FragmentManager#addFragment()
方法case OP_ADD: f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim); mManager.setExitAnimationOrder(f, false); mManager.addFragment(f); break;
接着往下走
FragmentManager#addFragment()
方法FragmentStateManager addFragment(@NonNull Fragment fragment) if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment); FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment); fragment.mFragmentManager = this; // 调用 FragmentStore#makeActive() 方法,将 Fragment 添加到 mActive 中 mFragmentStore.makeActive(fragmentStateManager); if (!fragment.mDetached) // 调用 FragmentStore#addFragment() 方法,将 Fragment 添加到 mAdded 中 mFragmentStore.addFragment(fragment); fragment.mRemoving = false; if (fragment.mView == null) fragment.mHiddenChanged = false; if (isMenuAvailable(fragment)) mNeedMenuInvalidate = true; return fragmentStateManager;
这个方法主要就是将该
Fragment
添加到mAdded
中和mActive
中,具体代码比较简单,就不放出来了。 -
第二步主要是将
mOps
中的所有对应的Fragment
设置到对应的状态,并且调用回调,这个第二步调用的方法在后面第三步中也会调用到,就在后面放一起说明。 -
接着我们跳过第二步,直接看第三步调用
FragmentManager.moveToState(int newState, boolean always)
方法void moveToState(int newState, boolean always) if (mHost == null && newState != Fragment.INITIALIZING) throw new IllegalStateException("No activity"); // always:表示是否需要强制更新状态,即使状态一样,否则的话,状态一样时不更新 if (!always && newState == mCurState) return; mCurState = newState; if (USE_STATE_MANAGER) // 使用状态管理,(不管是否使用状态管理,最后都是调用的同样的方法,只是在中间过程有些不一样) mFragmentStore.moveToExpectedState(); else // 不使用状态管理,在之前,我们已经将相关操作添加到这两个列表中了 // mFragmentStore.getFragments() 方法返回的就是 mAdded 列表 for (Fragment f : mFragmentStore.getFragments()) moveFragmentToExpectedState(f); // mFragmentStore.getActiveFragmentStateManagers() 方法返回的就是 mActive 列表 for (FragmentStateManager fragmentStateManager : mFragmentStore.getActiveFragmentStateManagers()) Fragment f = fragmentStateManager.getFragment(); if (!f.mIsNewlyAdded) moveFragmentToExpectedState(f); boolean beingRemoved = f.mRemoving && !f.isInBackStack(); if (beingRemoved) mFragmentStore.makeInactive(fragmentStateManager); startPendingDeferredFragments(); if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) mHost.onSupportInvalidateOptionsMenu(); mNeedMenuInvalidate = false;
我们分别看一下这两个的调用过程
-
使用状态管理:直接调用
FragmentStateManager#moveToExpectedState()
方法// FragmentStateManager#moveToExpectedState() void moveToExpectedState() try mMovingToState = true; int newState; // 根据状态调用对应的方法 attach()/create()/createView()/... while ((newState = computeExpectedState()) != mFragment.mState) if (newState > mFragment.mState) // Moving upward int nextStep = mFragment.mState + 1; switch (nextStep) case Fragment.ATTACHED: attach(); break; case Fragment.CREATED: create(); break; case Fragment.VIEW_CREATED: ensureInflatedView(); createView(); break; case Fragment.AWAITING_EXIT_EFFECTS: activityCreated(); break; case Fragment.ACTIVITY_CREATED: if (mFragment.mView != null && mFragment.mContainer != null) SpecialEffectsController controller = SpecialEffectsController .getOrCreateController(mFragment.mContainer, mFragment.getParentFragmentManager()); int visibility = mFragment.mView.getVisibility(); SpecialEffectsController.Operation.State finalState = SpecialEffectsController.Operation.State.from(visibility); controller.enqueueAdd(finalState, this); mFragment.mState = Fragment.ACTIVITY_CREATED; break; case Fragment.STARTED: start(); break; case Fragment.AWAITING_ENTER_EFFECTS: mFragment.mState = Fragment.AWAITING_ENTER_EFFECTS; break; case Fragment.RESUMED: resume(); break; else // Moving downward int nextStep = mFragment.mState - 1; switch (nextStep) case Fragment.AWAITING_ENTER_EFFECTS: pause(); break; case Fragment.STARTED: mFragment.mState = Fragment.STARTED; break; case Fragment.ACTIVITY_CREATED: stop(); break; case Fragment.AWAITING_EXIT_EFFECTS: if (FragmentManager.isLoggingEnabled(Log.DEBUG)) Log.d(TAG, "movefrom ACTIVITY_CREATED: " + mFragment); if (mFragment.mView != null) // Need to save the current view state if not done already // by saveInstanceState() if (mFragment.mSavedViewState == null) saveViewState(); if (mFragment.mView != null && mFragment.mContainer != null) SpecialEffectsController controller = SpecialEffectsController .getOrCreateController(mFragment.mContainer, mFragment.getParentFragmentManager()); controller.enqueueRemove(this); mFragment.mState = Fragment.AWAITING_EXIT_EFFECTS; break; case Fragment.VIEW_CREATED: mFragment.mInLayout = false; mFragment.mState = Fragment.VIEW_CREATED; break; case Fragment.CREATED: destroyFragmentView(); mFragment.mState = Fragment.CREATED; break; case Fragment.ATTACHED: destroy(); break; case Fragment.INITIALIZING: detach(); break; // 根据需要回调 Fragment#onHiddenChanged() 方法 if (FragmentManager.USE_STATE_MANAGER && mFragment.mHiddenChanged) if (mFragment.mView != null && mFragment.mContainer != null) // Get the controller and enqueue the show/hide SpecialEffectsController controller = SpecialEffectsController .getOrCreateController(mFragment.mContainer, mFragment.getParentFragmentManager()); if (mFragment.mHidden) controller.enqueueHide(this); else controller.enqueueShow(this); if (mFragment.mFragmentManager != null) mFragment.mFragmentManager.invalidateMenuForFragment(mFragment); mFragment.mHiddenChanged = false; mFragment.onHiddenChanged(mFragment.mHidden); finally mMovingToState = false;
-
不使用状态管理:
FragmentManager#moveFragmentToExpectedState(f)
(这个方法也就是上面非add操作时先会调用的方法,这里就一起看了) ->FragmentManager#moveToState(@NonNull Fragment f)
->FragmentManager#moveToState(@NonNull Fragment f, int newState)
->FragmentManager#moveToState(@NonNull Fragment f, int newState)
-> 根据状态调用FragmentStateManager#attach()/create()/createView()/activityCreated()/.../destroy()/detach()
等方法,和使用状态管理调用同样的方法。
最后,通过调用FragmentStateManager#attach()/create()/createView()/activityCreated()/.../destroy()/detach()
等方法最终会回调 Fragment
的对应生命周期方法。
Fragment
的 View
加载到容器中的过程
将 Fragment#createView()
方法的 View
加载到具体的页面上在 FragmentStateManager#createView()
方法中实现:
-
在该方法(
FragmentStateManager#createView()
)中调用Fragment#performCreateView()
方法进而调用Fragment#onCreateView()
方法创建View
并赋值给Fragment
的成员变量mView
-
在该方法(
FragmentStateManager#createView()
)中接着调用FragmentStateManager#addViewToContainer()
方法void addViewToContainer() int index = mFragmentStore.findFragmentIndexInContainer(mFragment); mFragment.mContainer.addView(mFragment.mView, index);
通过调用
addView()
方法将View
增加到容器中,mContainer
就是加载Fragment
的容器。
以上是关于Fragment从源码角度看add和replace过程的主要内容,如果未能解决你的问题,请参考以下文章