Fragment源码分析(二):commitXXX和popXXX

Fragment源码分析分两部分:

使用刨坑

commitXXX和popXXX

前言

接着上一篇继续将fragment的提交过程,为啥单独将提交过程呢,因为它复杂嘛。。。

  1. commit过程和pop过程其实是一样的,支持生成backStackState一个生成popBackStackState。
  2. add、remove、show、hide、replece过程其实也是一样的,只是对应的标志位不同
  3. show就是将view设置为visible,hide就是Gone,replace:如果有了,先remove在add,如果没有直接add
  4. 情况捏就是这么个情况
    首先引入一段代码,因为使用了addToBackStack,因此不能用带now的commit
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.fragment_one, new FirstFragment(R.layout.fragment_first), "firstFragment");
transaction.addToBackStack("fragment_one");
transaction.commit();

commitXXX()提交过程:

我们知道,commitXXX之前的操作都是做个记录,虚晃一枪,真正执行的操作是commitXXX();提交方法一共有四个,上一篇我们粗略介绍了其中的差别,现在我们详细讲一下:
注意:这里的disallowAddToBackStack()和上一节将的addToBackStack是相矛盾的,同时设置会相互报错,二者必然选其一,因此只要有Now,就不能加入backStack;

@Override
public int commit() {
    return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
    return commitInternal(true);
}
@Override
public void commitNow() {
    disallowAddToBackStack();
    mManager.execSingleAction(this, false);
}
@Override
public void commitNowAllowingStateLoss() {
    disallowAddToBackStack();
    mManager.execSingleAction(this, true);
}

popBackStackXXX()提交过程:

弹出一共有6种:

  1. 空参就是一次pop操作弹出一个栈顶的fragment的元素
  2. name就是一次弹出name以及name以上的fragment的元素
  3. id就是一次弹出id以及id以上的元素
  4. 就那么简单
public abstract void popBackStack();
public abstract boolean popBackStackImmediate();

public abstract void popBackStack(@Nullable String name, int flags);
public abstract boolean popBackStackImmediate(@Nullable String name, int flags);

public abstract void popBackStack(int id, int flags);
public abstract boolean popBackStackImmediate(int id, int flags);

(一)执行提交前的准备工作

有now和没有now的区别就是能否添加回退栈,这里由于篇幅原因,commit的一些前奏我就总结一下吧:

  1. 四种commit()都不能重复提交,不然报错:没有now的报重复提交,有now的报重复添加fragment
  2. 没有AllowingStateLoss的commit()会判断当前的activity是否执行onStop或者onSaveInstanceState,否则报错:不能在onSaveInstanceState之后提交。有的话直接return结束本地提交操作
  3. 如果addToBackStack,有now的会报错,没有now的会给mBackStack集合进行装箱操作。
  4. 没有now的会将recorder装箱到mPendingActions中去,等待handler的消息分发执行;
  5. 没有now的从execPendingActions()方法开始执行,有now的从execSingleAction开始执行。
提交方式mPendingActionsaddToBackStackcheckStateLoss
commit装箱能加,装箱mBackStack报错
commitNow不装箱不能,没有mBackStack报错
commitA装箱能加,装箱mBackStack丢弃
commitNowA不装不能,没有mBackStac丢弃

checkStateLoss就是第二点;

(二)执行动作

过程很长,我就挑重点的讲解,不然怕你们看不下去;
因为commit是最复杂的,我们从execPendingActions()方法开始讲解。
不论哪种提交方式,都是这么三步:

  1. 一、用来判断是否丢弃本次提交;二、生成mTmpRecords、mTmpIsPop两个数组集合
  2. 给mTmpRecords、mTmpIsPop以及mBackStack进行装箱
  3. 第三步重点讲解
public boolean execPendingActions() {
    ensureExecReady(true);1)
    boolean didSomething = false;
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {2-----------------generateOpsForPendingActions的作用---------------------------
  records.add(this); //this指的是BackStackRecord
  isRecordPop.add(false); //因为commit所以是false,如果是pop那么就是true
  if (mAddToBackStack) {
      mManager.addBackStackState(this);//如果有addToBackStack那么就装箱mBackStack集合
  }
------------------------------------------------------------------
        mExecutingActions = true;
        try {
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);3} finally {
            cleanupExec();
        }
        didSomething = true;
    }
    updateOnBackPressedCallbackEnabled(); //设置返回键
    doPendingDeferredStart();
    burpActive();
    return didSomething;
}

(三)开始执行

private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop) {
.................日常判空......................
    ......重点是executeOpsTogether方法:recordNum = 0;reorderingEnd = 1........
    executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
    ................
}
1. startTransitions开始事务
2. executeOps执行ops操作
private void executeOpsTogether(ArrayList<BackStackRecord> records,ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
    boolean addToBackStack = false;
    addToBackStack = addToBackStack || record.mAddToBackStack; // 有回退栈
    ................................
    if (!allowReordering) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,false);1}
    executeOps(records, isRecordPop, startIndex, endIndex);2................................
}

(3-1)startTransitions开始事务

FragmentTransition.java
static void startTransitions(FragmentManagerImpl fragmentManager,ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,int startIndex, int endIndex, boolean isReordered) {
    SparseArray<FragmentContainerTransition> transitioningFragments =
            new SparseArray<>();
            
    ...........................简化省略,看这句话就行了..............................
    calculateFragments(record, transitioningFragments, isReordered);
   ----------------------------调用方法---------------------------------
   //这个方法中给transitioningFragments、mActive集合进行装箱,然后调用moveToState方法 
   addToFirstInLastOut(transaction, op, transitioningFragments, false, isReordered);
   ----------------------------调用方法---------------------------------
   //这个是核心方法,详细见(3-1-1)
	manager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
   ----------------------------end-------------------------------------------
   ...........................简化省略.............................
    
}

(3-1-1)核心方法moveToState()方法

该方法是fragment的最最核心的方法,说白了就是生命周期的调度过程,总结一下:
commitXXX到onResume():结束
popbackStackXXX到onDetach():结束

Created with Raphaël 2.2.0 开始:fragment的state状态是0 onAttach(Context);先 onAttach(Activity);后 Activity中执行onAttachFragment(Fragment) onCreate(savedInstanceState); Lifecycle.Event.ON_CREATE:通知更新生命周期 onCreateView(LayoutInflater i, ViewGroup v,Bundle s): 这里获取布局view,并添加到对那个的id中 onViewCreated(View v, Bundle s): 返回上一步骤创建的view,就是为了使用findViewById方便点,别的没啥特殊的 onActivityCreated(Bundle s): fragment的state状态更新成1 onViewStateRestored(Bundle s): Lifecycle.Event.ON_CREATE:通知更新生命周期 onStart(): Lifecycle.Event.ON_START通知更新生命周期 onResume(): Lifecycle.Event.ON_RESUME通知更新生命周期 onPause(); Lifecycle.Event.ON_PAUSE通知更新生命周期 onStop(); Lifecycle.Event.ON_STOP通知更新生命周期 onDestroyView(); Lifecycle.Event.ON_DESTROY通知更新生命周期 (1)onCreateAnimation(); (2)onCreateAnimator(); (3)如果有动画,动态移除fragment (4)然后移除view (4.1)view.clearAccessibilityFocus();移除焦点 (4.2)cancelTouchTarget(view);移除点击 (4.3)imm.onViewDetachedFromWindow(this);移除输入法界面 onDestroy(); Lifecycle.Event.ON_DESTROY通知更新生命周期 onDetach(); 结束
........源码太长影响美观,看上面的图就行了........

#2

(3-2)executeOps执行ops操作

执行什么呢,当然是fragment动画,以及add、remove、hide、show、等一系列操作了;但是这些操作也只是在fragment中的对应的属性字段进行修改,如fragment.mAdded = true;然后操作mAdded集合。

这里最终还是调用了(3-1-1)的5个参数的moveToState方法,继续执行刚才的onCreate操作

private static void executeOps(ArrayList<BackStackRecord> records,ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
..............简化省略,主要看这句....................
	record.executeOps();
}
//这个方法就是用来给fragment加载动画,并执行fragment的add、remove、hide、show、等一系列操作的;
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.setNextTransition(mTransition, mTransitionStyle);
        }
        switch (op.mCmd) {
            case OP_ADD:
                f.setNextAnim(op.mEnterAnim);
                mManager.addFragment(f, false);
                break;
            case OP_REMOVE:
                f.setNextAnim(op.mExitAnim);
                mManager.removeFragment(f);
                break;
            case OP_HIDE:
                f.setNextAnim(op.mExitAnim);
                mManager.hideFragment(f);
                break;
            case OP_SHOW:
                f.setNextAnim(op.mEnterAnim);
                mManager.showFragment(f);
                break;
            case OP_DETACH:
                f.setNextAnim(op.mExitAnim);
                mManager.detachFragment(f);
                break;
            case OP_ATTACH:
                f.setNextAnim(op.mEnterAnim);
                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;
        }
        if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
            mManager.moveFragmentToExpectedState(f);
        }
    }
    if (!mReorderingAllowed) {
    //这里最终还是调用了(3-1-1)的5个参数的moveToState方法,继续执行刚才的onCreate操作
        mManager.moveToState(mManager.mCurState, true);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值