Android fragment add、replace、commit源码浏览

前言:

     最近看了 fragment 源码,为方便自己以后查看,在此记录一下

     源码版本:Androidx

正文:

在此,我们看一下 fragment 中 add、replace、commit等方法

先放一段伪代码:

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        HomeFragment homeFragment = new HomeFragment();
        fragmentTransaction.add(R.id.main_tab_fl, homeFragment);
        fragmentTransaction.replace(R.id.main_tab_fl,homeFragment);
        fragmentTransaction.commit();

1、先看第一行 FragmentManager fragmentManager = getSupportFragmentManager();

看源码一直往下走

所在类:FragmentActivity.java

     public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }
所在类:FragmentController.java
    public FragmentManager getSupportFragmentManager() {
        return mHost.getFragmentManagerImpl();
    }
所在类:FragmentHostCallback.java

    FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManager;
    }

到此,我们可以看到 返回的类型为  FragmentManagerImpl ,也走到了最后,接着我们在 FragmentManagerImpl.java 这个类中找到 beginTransaction 这个方法。

2、这样就到了第二行:FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

所在类:FragmentManagerImpl.java

    @Override
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }
所在类:BackStackRecord.java

    public BackStackRecord(FragmentManagerImpl manager) {
        mManager = manager;
    }

由上面一下代码可以看出 fragment 的实现路线是

FragmentActivity
    -> FragmentController
      -> FragmentHostCallback
        -> FragmentManagerImpl
          -> BackStackRecord

至此,我们可以看到有关于 FragmentManage r中的操作都是在 FragmentManagerImpl 类中提供了实现方法,但是关于其管理等操作,最后还是封装进了 BackStackRecord 中。接下来我们就在 BackStackRecord 中看看 add、replace、commit 方法

第三行只是 new 一个 fragment,方便下面代码观看,此处不看

3、接着进入第四行 fragmentTransaction.add(R.id.main_tab_fl, homeFragment);

我们在 BackStackRecord 中查找 add 方法:

    @Override
    public FragmentTransaction add(int containerViewId, Fragment fragment) {
        // 注意此时的 OP_ADD 字段参数,在后面真正执行 Fragment 的操作时会用到,
        // 用来判断当前Fragment 的真正操作是什么?添加 add、移除 remove、隐藏 hide 或者显示 show 等
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }

    接着继续进入 doAddOp 方法,只看关键部分

    private void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
       ......

        if (tag != null) {
            // 此处判断 tag 是否为空
        }

        if (containerViewId != 0) {
            // 此处判断传入的 fragment 容器 id 是否为空
        }
        // 最后进入 addop 方法
        addOp(new Op(opcmd, fragment));
    }
    
    接着进入 addop 方法中

    void addOp(Op op) {
        mOps.add(op);
        ......
    }

我们可以看到,源码中将整个操作封装成了一个Op,Op 应该是一个数据结构容器,通过 addOp(op) 方法将其添加到 mOps 列表里面去。这个列表是源码在上面定义的一个链表。 

到此 add 方法执行结束,这一步可以理解为是帮我们做一系列的判断和赋值等操作。所有的 添加、替换 等操作都是在 commit 中实现的

4、add 后执行 commit 操作,也就是第 6 行 fragmentTransaction.commit();

在 BackStackRecord 中查找 commit :

    @Override
    public int commit() {
        return commitInternal(false);
    }
    
    继续往下走,进入 commitInternal 方法,只放一些关键性代码

    int commitInternal(boolean allowStateLoss) {
        //只能进行一次commit()操作,否则报异常
        if (mCommitted) throw new IllegalStateException("commit already called");
        ...
        mCommitted = true;
        //是否加入了回退栈(在addToBackStack()中赋值为true)
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        //this是一个FragmentManagerImpl.OpGenerator对象,BackStackRecord实现了这个接口
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

    接着进入 enqueueAction  方法
    
    /**
     * 添加一个操作到待操作队列
     *
     */
    public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            //检查状态是否丢失,通常会遇见的两个异常就来自此处的检查
            checkStateLoss();
        }
            ......
            mPendingActions.add(action);
            // 进入 scheduleCommit 方法
            scheduleCommit();
    }

    接着进入 scheduleCommit 方法
    void scheduleCommit() {
        synchronized (this) {
            //存在延期执行的操作
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            //准备执行的操作
            boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;        
            if (postponeReady || pendingReady) {
                // 此处执行了异步操作,提交了 mExecCommit
                // 放弃所有操作,从新开始新的操作,并且线程安全
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
            }
        }
    }
    
    接下来,进入 mExecCommit 方法

    Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            // 最终在主线程中执行 execPendingActions(); 方法
            execPendingActions();
        }
    };
    
    再往下走,进入 execPendingActions 方法
    
    /**
     * 只能从主线程中调用
     */
    public boolean execPendingActions() {
        // 步骤一,检查是否是主线程、是否已经在执行、检查状态是否丢失
        
        ensureExecReady(true);

        boolean didSomething = false;
        // 步骤二,generateOpsForPendingActions会判断当前是否还有任务
        while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
            mExecutingActions = true;
            try {

                // 步骤三,去掉多余任务,并执行任务
                // 执行任务的时候,会去调用 BackStackRecord 中的 expandOps 方法,里面会执行之前的Ops
                removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
            } finally {
                // 重置mExecutingActions = false
                // 清空mTmpIsPop和mTmpRecords
                cleanupExec();
            }
            didSomething = true;
        }
        
        // 步骤四
        doPendingDeferredStart();
        burpActive();

        return didSomething;
    }

步骤三 removeRedundantOperationsAndExecute 和 步骤四  最后都会执行到 moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)

4.1、先看步骤三

    private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop) {
        ......
        for (int recordNum = 0; recordNum < numRecords; recordNum++) {
                ......
                // 执行 所有出栈入栈的优化操作
                int reorderingEnd = recordNum + 1;
                if (isRecordPop.get(recordNum)) {
                    while (reorderingEnd < numRecords
                            && isRecordPop.get(reorderingEnd)
                            && !records.get(reorderingEnd).mReorderingAllowed) {
                        reorderingEnd++;
                    }
                }
                //执行BackStackRecord的可优化和不可优化Op
                executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);

        }
        ......
    }
    
    继续进入 executeOpsTogether 方法
    // executeOpsTogether 函数很复杂但是主要也就这两个函数调用关键。第一个只是取出我们刚刚新建的fragment,
    // 最后一个才是真的吧fragment加入到页面上。
    // 而我们在代码中调用执行 replace 后,commit提交后就会进入 expandOps 方法中,switch选择进入 OP_REPLACE  
    
    private void executeOpsTogether(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
        
        oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);    
        
        executeOps(records, isRecordPop, startIndex, endIndex);

        ......

    }
    
    继续看 executeOps 方法

    private static void executeOps(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        for (int i = startIndex; i < endIndex; i++) {
            ......
            if (isPop) {
                ......
                record.executePopOps(moveToState);
            } else {
                ......
                record.executeOps();
            }
        }
    }

    executeOps 方法中,执行后,会进入 executePopOps(moveToState) 或者 executeOps() 方法中,
    而这两个方法,最后都会调用 moveToState(mManager.mCurState, true)。
    
    接下来看看  executePopOps(moveToState) 和 executeOps():

     void executePopOps(boolean moveToState) {
       ......
            mManager.moveToState(mManager.mCurState, true);
       ......
    }
    void executeOps() {
       ......
            // Added fragments are added at the end to comply with prior behavior.
            mManager.moveToState(mManager.mCurState, true);
       ......
    }
    
    继续看看 moveToState(mManager.mCurState, true)

    void moveToState(int newState, boolean always) {
       ......
           startPendingDeferredFragments();
       ......
    }
    
    进入 startPendingDeferredFragments,请记住这里,步骤四,也会走到这里

    void startPendingDeferredFragments() {
        if (mActive == null) return;
             ......
             performPendingDeferredStart(f);
             ......
    }
    
    然后进入 performPendingDeferredStart

    public void performPendingDeferredStart(Fragment f) {
            ......
            moveToState(f, mCurState, 0, 0, false);
            .....
       
    }
    
    最终进入了 moveToState(f, mCurState, 0, 0, false) 这个方法中,在这里进行 fragment 的创建等,
    我们也可以在这看到 为什么 fragment 的生命周期会依次执行 onAttach() -》onCreate() -》onCreateView() ..... 
    

    

现在我们看一下 moveToState(f, mCurState, 0, 0, false) ,太多了,只截取部分

    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        ......
        if (f.mState <= newState) {
            switch (f.mState) {
                case Fragment.INITIALIZING:
                        .....
                        dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                        f.mCalled = false;

                        // 此处执行 fragment 的 onAttach,具体的,大家可以点进去看
                        f.onAttach(mHost.getContext()); 
                        ......
                        if (!f.mIsCreated) {
                            dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                            // 此处执行 fragment 的 onCreate 
                            f.performCreate(f.mSavedFragmentState);
                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                        }
                        ......
    
                case Fragment.CREATED:
                        ensureInflatedFragmentView(f);
                        ......
                        // 这里的 mContainerId 就是我们传入的 Fragment 容器 id,
                        container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                        // 将根据传入 id 得到的 container 赋值给 mContainer 
                        f.mContainer = container;
                        ......
                        
                        // 这里会执行 fragment 的 onCreateView
                        // 点进入会看到 f.performCreateView -> mView = onCreateView(inflater, container, savedInstanceState)
                        // onCreateView 中返回为 null,所以我们在自己的 fragment 中重写该方法,写入自己的 view
                        f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                        ......
                        // 判断由 onCreateView 得到的 mView 是否为空
                        if (f.mView != null) {
                            ......
                            if (container != null) {
                                // mView  不为空,就添加到 fragment 容器中
                  ********************  到此,才真正的添加到了容器中 ********************
                                container.addView(f.mView);
                            }
                            ......
                        }
// 剩下的 大家可以自己看看
                case Fragment.ACTIVITY_CREATED:
    
                case Fragment.STARTED:

             }  
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                
                case Fragment.STARTED:

                case Fragment.ACTIVITY_CREATED:

                case Fragment.CREATED:
             }    
        }  
        ......
    }

4.2 步骤四 doPendingDeferredStart();

    void doPendingDeferredStart() {
        if (mHavePendingDeferredStart) {
            mHavePendingDeferredStart = false;
            startPendingDeferredFragments();
        }
    }

   进入 startPendingDeferredFragments 中

    void startPendingDeferredFragments() {
        if (mActive == null) return;

        for (int i=0; i<mActive.size(); i++) {
            Fragment f = mActive.valueAt(i);
            if (f != null) {
                performPendingDeferredStart(f);
            }
        }
    }

    进入 performPendingDeferredStart 中

    public void performPendingDeferredStart(Fragment f) {
        if (f.mDeferStart) {
            if (mExecutingActions) {
                // Wait until we're done executing our pending transactions
                mHavePendingDeferredStart = true;
                return;
            }
            f.mDeferStart = false;
            // 最后调用 moveToState 
            moveToState(f, mCurState, 0, 0, false);
        }
    }    

    可以看到,最后依然会进入 moveToState(f, mCurState, 0, 0, false) 中,大家可以看上面的 moveToState 的解释

5、执行 replace 操作,也就是第五行中的 fragmentTransaction.replace(R.id.main_tab_fl,homeFragment)

    其实 replace 与 add 操作类似,都是帮我们做一系列的判断和赋值等操作

    @Override
    public FragmentTransaction replace(int containerViewId, Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }

    /    

    @Override
    public FragmentTransaction replace(int containerViewId, Fragment fragment,
            @Nullable String tag) {
        ....
        // 调用 doAddOp,注意这里的 opcmd = OP_REPLACE
        doAddOp(containerViewId, fragment, tag, OP_REPLACE);
        return this;
    }

    进入 doAddOp 方法

    private void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        ......
        // 和 add 中的一样,最后都会进入 addOp,不同的是 opcmd
        addOp(new Op(opcmd, fragment));
    }
    
    void addOp(Op op) {
        mOps.add(op);
        ......
    }
    

commit 操作提交后,会执行 executeOpsTogether 中的 record.expandOps(mTmpAddedFragments, oldPrimaryNav) 方法,至于commit操作如何走到 executeOpsTogether 方法中的,大家可以看看 4 中 commit 操作的流程

接下来我们看一下 expandOps 方法:

Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
        for (int opNum = 0; opNum < mOps.size(); opNum++) {
            final Op op = mOps.get(opNum);
            switch (op.cmd) {
                case OP_ADD:
                case OP_ATTACH:
                    added.add(op.fragment);
                    break;
                case OP_REMOVE:
                case OP_DETACH: {
                    added.remove(op.fragment);
                    if (op.fragment == oldPrimaryNav) {
                        mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.fragment));
                        opNum++;
                        oldPrimaryNav = null;
                    }
                }
                break;
                    
                // 因为 replace 中 op.cmd 为 OP_REPLACE 最后会走进这里在
                case OP_REPLACE: {
                    final Fragment f = op.fragment;
                    final int containerId = f.mContainerId;
                    boolean alreadyAdded = false;
                    // 从后往前遍历 ArrayList<Fragment> 中的Fragment,看一下mContainerId 是否与添加的 Fragment一致
                    for (int i = added.size() - 1; i >= 0; i--) {
                        final Fragment old = added.get(i);
                        // 判断 mContainerId 是否一致
                        if (old.mContainerId == containerId) {
                            if (old == f) {
                                // 如果一致,将 alreadyAdded 置为 true
                                alreadyAdded = true;
                            } else {
                                // This is duplicated from above since we only make
                                // a single pass for expanding ops. Unset any outgoing primary nav.
                                if (old == oldPrimaryNav) {
                                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
                                    opNum++;
                                    oldPrimaryNav = null;
                                }
                                final Op removeOp = new Op(OP_REMOVE, old);
                                removeOp.enterAnim = op.enterAnim;
                                removeOp.popEnterAnim = op.popEnterAnim;
                                removeOp.exitAnim = op.exitAnim;
                                removeOp.popExitAnim = op.popExitAnim;
                                mOps.add(opNum, removeOp);
                                added.remove(old);
                                opNum++;
                            }
                        }
                    }
                    if (alreadyAdded) {
                        // alreadyAdded 为 true时,移除mOps中的该实例
                        mOps.remove(opNum);
                        opNum--;
                    } else {
                        op.cmd = OP_ADD;
                        added.add(f);
                    }
                }
                break;
                ......
            }
        }
        return oldPrimaryNav;
    }

由上面流程可以看出:

其实现为:

  • 从后往前遍历 ArrayList<Fragment> 中的Fragment,看一下mContainerId 是否与添加的 Fragment一致
  • 如果没有,alreadyAdded 为 false,直接在 ArrayList<Fragment> 中 add 添加
  • 若有 mContainerId 相同,分两种情况:
    • 有相同实例时,移除 mOps中 的该实例
    • 实例不相同时,添加到 mOps 中,同时remove 移除 ArrayList<Fragment> 中旧的 Fragment,再 add 添加新的Fragment

本人水平有限,目前 fragment 源码学习 只能分析到这样了,如果有分析的哪里有问题,麻烦看的小伙伴,进行指正,谢谢!

后面有新的理解,还会修改的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值