js css html

Fragment(一)从源码角度看add和replace过程

2022-05-06  本文已影响0人  ITRenj

Fragment(一)从源码角度看add和replace过程

博客对应的Demo地址:GitHubGitee

通过这篇博客,我们能知道以下问题:

1. Fragment add()replace() 方法差别

add() 是添加 Fragment 到容器布局中,再搭配事务对象(FragmentTransaction)的 show()hide() 方法来显示和隐藏 Fragmentreplace()顾名思义“替换”,会销毁布局容器内的已有 Fragment,然后重新创建一个新的 Fragment 显示到布局容器中。通过一下两种方式的生命周期方式对比:

1-1.jpg 1-2.jpg

我们可以发现,replace() 方式替换的,被替换的Fragment会被彻底销毁,新的会重新创建,每一次的加载到界面到从界面消失的过程都是一个完整的生命周期;而 add() 结合 show()/hide() 方式的Fragment,切换时并不会彻底销毁 Fragment,而是走了 onHiddenChanged() 回调方法,改变了对用户的可见性,同时注意,这个方法并不是生命周期方法。他是在FragmentTransaction调用 show()hide() 方法时才会回调的方法。

注意:如果将Fragment加入回退栈

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 版本

FragmentManagerFragmentTransaction 的获取

FragmentActivity 中获取 FragmentManagerFragmentTransaction

首先看看 FragmentManagerFragmentTransaction 的获取

到了这里,FragmentActivity 中获取 FragmentManagerFragmentTransaction 的过程已经知道了,那么接下来看看在 Fragment 中获取 FragmentManagerFragmentTransaction 的过程。

Fragment 中获取 FragmentManagerFragmentTransaction

扩展

通过前面的了解,我们知道了 FragmentController 中的 mHost 就是在创建 FragmentController 时传递进来的 HostCallbacks 对象,我们现在来看看 Fragment 中的 mHost 是在哪里定义的。

通过查看源码,我们发现 Fragment 中的 mHost 的赋值位置是在 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 中创建的 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() 方法的一个说明:=======================

  1. 以上就是 add() 的各个方法,他们最终调用的都是 doAddOp() 方法,并且传递了容器id,Fragment对象,tagOP_ADD 参数(重点注意OP_ADD参数,

  2. createFragment() 方法的作用是根据 FragmentClass 创建对象

     @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;
}

我们一个一个方法来看:

  1. 首先看一下 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 列表。这个方法到这里就差不多了。我们回头接着看另外一个方法。

  2. 查看另一个 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();
         }
     }
    

    这里把不是特别重要的代码去掉了,主要注意两步:

    1. 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:新增。

    2. 接下来看一下另一个 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)

我们分别看一下这两个的调用过程

最后,通过调用FragmentStateManager#attach()/create()/createView()/activityCreated()/.../destroy()/detach() 等方法最终会回调 Fragment 的对应生命周期方法。

FragmentView 加载到容器中的过程

Fragment#createView() 方法的 View 加载到具体的页面上在 FragmentStateManager#createView() 方法中实现:

  1. 在该方法(FragmentStateManager#createView())中调用 Fragment#performCreateView() 方法进而调用 Fragment#onCreateView() 方法创建View 并赋值给 Fragment 的成员变量 mView

  2. 在该方法(FragmentStateManager#createView())中接着调用 FragmentStateManager#addViewToContainer() 方法

     void addViewToContainer() {
         int index = mFragmentStore.findFragmentIndexInContainer(mFragment);
         mFragment.mContainer.addView(mFragment.mView, index);
     }
    

    通过调用 addView() 方法将 View 增加到容器中,mContainer 就是加载 Fragment 的容器。

上一篇 下一篇

猜你喜欢

热点阅读