Fragment相关

fragment基本操作:

 getSupportFragmentManager().beginTransaction()
                    .add(id, fragment, tag)
                    .addToBackStack(null)
                    .commit();

以下就v4包下的FragmentManager进行源码分析。

1、FragmentManager#beginTransaction

该方法返回一个BackStackRecord对象
该对象内部有一个成员变量mOps:

ArrayList mOps = new ArrayList<>();

Op是一个封装了fragment操作以及转场动画的bean:

    static final class Op {
        int cmd;//dvfragment的操作,如add remove replace等
        Fragment fragment;
        int enterAnim;
        int exitAnim;
        int popEnterAnim;
        int popExitAnim;
    }

2、BackStackRecord#add(id, fragment, tag)

该方法会将add操作封装成一个Op对象,然后存入mOps集合中。

3、 BackStackRecord#addToBackStack(null)

@Override
    public FragmentTransaction addToBackStack(String name) {
        if (!mAllowAddToBackStack) {
            throw new IllegalStateException(
                    "This FragmentTransaction is not allowed to be added to the back stack.");
        }
        mAddToBackStack = true;
        mName = name;
        return this;
    }

注意mAddToBackStack 这个变量,很关键!该方法最重要的是让这个变量设为true。它的作用下面会讲到。

4、BackStackRecord#commit()

该方法最终调用commitInternal:

int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        mCommitted = true;
        if (addToBackStack) {
            //关键1
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        //关键2
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

如果调用了步骤3的addToBackStack方法,addToBackStack此时为true,进入判断执行关键1处代码,它的源码为:

ArrayList mBackStackIndices;
ArrayList mAvailBackStackIndices;
public int allocBackStackIndex(BackStackRecord bse) {
        synchronized (this) {
            if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
                if (mBackStackIndices == null) {
                    mBackStackIndices = new ArrayList();
                }
                int index = mBackStackIndices.size();
                mBackStackIndices.add(bse);
                return index;

            } else {
                //移除最后一个元素,返回最后一个元素的值。
                int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
                mBackStackIndices.set(index, bse);
                return index;
            }
        }
    }

刚开始这段代码看的我是云里雾里,没办法,只能写个demo来debug运行不断分析了:
demo中不停的开启新fragment,且加入回退栈,此时mAvailBackStackIndices=null,走第一个判断,所有事务(BackStackRecord)都会添加到mBackStackIndices 集合中,并不会进else判断。
然后多次按返回键回退几个fragment,紧接着重新开启fragment,此时才会进入else判断,意味着mAvailBackStackIndices这个集合此时不再为空且有内容了,更巧的是它的集合长度等于mAvailBackStackIndices的长度,那么mAvailBackStackIndices在哪里初始化并存放内容的呢?搜索mAvailBackStackIndices = new,找到下面这段代码,并debug验证了每次按返回键移除fragment都会执行这段代码:

    public void freeBackStackIndex(int index) {
        synchronized (this) {
            mBackStackIndices.set(index, null);
            if (mAvailBackStackIndices == null) {
                //在这里初始化了
                mAvailBackStackIndices = new ArrayList();
            }
            if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
            //最后添加到mAvailBackStackIndices 后返回的index,会陆续添加到mAvailBackStackIndices中。
            mAvailBackStackIndices.add(index);
        }
    }

总结下mBackStackIndicesmAvailBackStackIndices的操作:
前者会将BackStackRecord对象存入,这很正常;后者作用是:在从mBackStackIndices集合中移除BackStackRecord对象的时候,将该被移除的BackStackRecord对象所在原集合中的index存入mAvailBackStackIndices,注意加粗的移除,方式并非直接remove,而是ArrayList.set(index,null)。
为什么不直接用mBackStackIndices,添加就add,移除就remove呢?
我猜想可能是mBackStackIndices是ArrayList,ArryList基于数组实现,这样避免了释放数组空间并再次开辟的耗时,达到空间换时间提高效率的目的。
至于mBackStackIndices有啥用?好像跟什么adb命令,打印输出Activity信息啥的有关......走错码头了,看关键2吧。

5、FragmentManager#enqueueAction(OpGenerator action, boolean allowStateLoss)

关键2处代码调用mManager.enqueueAction(this, allowStateLoss),参数this即BackStackRecord对象。

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<>();
            }
            //将action添加到mPendingActions集合中
            mPendingActions.add(action);
            //执行action任务
            scheduleCommit();
        }
    }

scheduleCommit()方法很简单,它利用handler,将任务发送到主线程的任务队列,执行execPendingActions():

public boolean execPendingActions() {
        ensureExecReady(true);

        boolean didSomething = false;
        while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
            mExecutingActions = true;
            try {
                removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
            } finally {
                cleanupExec();
            }
            didSomething = true;
        }

        doPendingDeferredStart();
        burpActive();

        return didSomething;
    }

while循环的判断条件执行generateOpsForPendingActions:

private boolean generateOpsForPendingActions(ArrayList records,
            ArrayList isPop) {
        boolean didSomething = false;
        synchronized (this) {
            //当集合为空或没内容时,返回false,防止while循环无限轮询
            if (mPendingActions == null || mPendingActions.size() == 0) {
                return false;
            }

            final int numActions = mPendingActions.size();
            for (int i = 0; i < numActions; i++) {
                //这里是关键,且generateOps返回值关系到上面的while循环
                didSomething |= mPendingActions.get(i).generateOps(records, isPop);
            }
            //清空集合
            mPendingActions.clear();
            mHost.getHandler().removeCallbacks(mExecCommit);
        }
        return didSomething;
    }

generateOps方法点进入,发现是OpGenerator接口的一个抽象方法,它的实现其中一个是在BackStackRecord中,那就看一下,
BackStackRecord#generateOps:

    @Override
    public boolean generateOps(ArrayList records, ArrayList isRecordPop) {
        records.add(this);
        isRecordPop.add(false);
        if (mAddToBackStack) {
            //关键
            mManager.addBackStackState(this);
        }
        //始终返回true,上面的while条件一定成立
        return true;
    }

步骤3中,mAddToBackStack被设为true,进入判断,执行 mManager.addBackStackState(this);回到FragmentManager中来:

   void addBackStackState(BackStackRecord state) {
        if (mBackStack == null) {
            mBackStack = new ArrayList();
        }
        mBackStack.add(state);
    }

至此,我们可以说,凡是调用了.addToBackStack(null)方法,都会将相关的BackStackRecord放入FragmentManager中的成员变量mBackStack集合中。

generateOps方法这里始终返回true,那么就会执行while内的任务removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);,看名字是移除多余的操作并执行,然后经过一系列调用,最终执行的是record.executePopOps(moveToState);或者是record.executeOps()方法。先看record.executeOps():

6、BackStackRecord#executeOps

void executeOps() {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            final Fragment f = op.fragment;
            if (f != null) {
                f.setNextTransition(mTransition, mTransitionStyle);
            }
            switch (op.cmd) {
                case OP_ADD:
                    f.setNextAnim(op.enterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.exitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.exitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.enterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.exitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.enterAnim);
                    mManager.attachFragment(f);
                    break;
                case OP_SET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(f);
                    break;
                case OP_UNSET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(null);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
            if (!mReorderingAllowed && op.cmd != OP_ADD && f != null) {
                mManager.moveFragmentToExpectedState(f);
            }
        }
        if (!mReorderingAllowed) {
            // Added fragments are added at the end to comply with prior behavior.
            mManager.moveToState(mManager.mCurState, true);
        }
    }

遍历BackStackRecord对象中的mOps 集合,swith到mOps对象封装的任务,最终调用FragmentManager的相关方法执行该任务。

你可能感兴趣的:(Fragment相关)