- 简书
- CSDN
Fragment(一)从源码角度看add和replace过程
通过这篇博客,我们能知道以下问题:
-
Fragmentadd()和replace()方法差别 - 从源码角度分析
add()和replace()方法
1. Fragment add() 和 replace() 方法差别
add() 是添加 Fragment 到容器布局中,再搭配事务对象(FragmentTransaction)的 show() 和 hide() 方法来显示和隐藏 Fragment,replace()顾名思义“替换”,会销毁布局容器内的已有 Fragment,然后重新创建一个新的 Fragment 显示到布局容器中。通过一下两种方式的生命周期方式对比:
1-1.jpg
1-2.jpg
我们可以发现,replace() 方式替换的,被替换的Fragment会被彻底销毁,新的会重新创建,每一次的加载到界面到从界面消失的过程都是一个完整的生命周期;而 add() 结合 show()/hide() 方式的Fragment,切换时并不会彻底销毁 Fragment,而是走了 onHiddenChanged() 回调方法,改变了对用户的可见性,同时注意,这个方法并不是生命周期方法。他是在FragmentTransaction调用 show() 和 hide() 方法时才会回调的方法。
注意:如果将Fragment加入回退栈
- 对于add方式,生命周期方法回调无影响
- 对于 replace 方式,那么他在被替换的时候是不会走销毁的方法的,它的生命周期方法如下:
1-3.jpg
======================= 回退栈的使用说明 =======================
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中获取FragmentManagerfinal 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的容器。










网友评论