美文网首页
Fragment源码简析(一)

Fragment源码简析(一)

作者: andev009 | 来源:发表于2018-01-08 17:55 被阅读41次

    先看使用Fragment的简单例子,这里用Android support v4的源码:

    Fragment fragment= new Fragment();
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction().add(R.id.container,fragment).commit();
    

    进入FragmentActivity的getSupportFragmentManager方法:

    public FragmentManager getSupportFragmentManager() {
            return mFragments.getSupportFragmentManager();
    }
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    

    可以看到FragmentManager是从FragmentController里取得的,那么看看FragmentController里有什么:

    public class FragmentController {
         public static final FragmentController 
             createController(FragmentHostCallback<?> callbacks) {
               return new FragmentController(callbacks);
         }
          public FragmentManager getSupportFragmentManager() {
               return mHost.getFragmentManagerImpl();
         }
         .........
    }
    

    又来了新类FragmentHostCallback,里面有个mFragmentManager变量:

    public abstract class FragmentHostCallback<E> extends FragmentContainer {
           final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
           .........
    }
    

    看到这里,只要知道FragmentManager最后来自于FragmentManagerImpl就可以了,看名字知道是FragmentManager的实现类。
    下面进入beginTransaction方法,在FragmentManagerImpl里找到:

    public FragmentTransaction beginTransaction() {
            return new BackStackRecord(this);
    }
    

    beginTransaction的作用就是返回一个BackStackRecord对象,可见事务办理都是交给了BackStackRecord这个类,这个类值得注意。
    继续往下走,例子只是进行了add这个事务。查看BackStackRecord类里的add方法,有几个重载方法,最后都走到了其中一个,有空可以查看所有的源码,这里的主干代码是:

    private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
            fragment.mFragmentManager = mManager;
            fragment.mTag = tag;
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
            addOp(new Op(opcmd, fragment));//这里的opcmd是OP_ADD
        }
    

    只是设置了fragment的成员变量,然后调用addOp,注意opcmd,对fragment的操作有很多,这里是OP_ADD,常用的还有OP_REPLACE,OP_REMOVE,OP_HIDE,OP_SHOW等。addOp方法干了啥:

    void addOp(Op op) {
            mOps.add(op);
            op.enterAnim = mEnterAnim;
            op.exitAnim = mExitAnim;
            op.popEnterAnim = mPopEnterAnim;
            op.popExitAnim = mPopExitAnim;
    }
    ArrayList<Op> mOps = new ArrayList<>();
    

    动画相关的不管,这步操作只是简单的将封装的ADD事务插入到ArrayList mOps里。现在准备工作做好了,到了最后一步,提交事务,调用commit()方法:

    public int commit() {
          return commitInternal(false);
    }
    int commitInternal(boolean allowStateLoss) {
            mCommitted = true;
            if (mAddToBackStack) {
                mIndex = mManager.allocBackStackIndex(this);
            } else {
                mIndex = -1;
            }
            mManager.enqueueAction(this, allowStateLoss);
            return mIndex;
    }
    

    这里流程只关注最后一句,由FragmentManager将之前的ADD操作加入队列。
    一句话总结下上面的流程:将新建Fragment的事务封装成ADD操作交给FragmentManager,FragmentManager将ADD操作入队列。
    下面看看入队列做了什么:

    public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
            if (!allowStateLoss) {
                checkStateLoss();
            }
            synchronized (this) {
                if (mDestroyed || mHost == null) {
                    if (allowStateLoss) {
                        // This FragmentManager isn't attached, so drop the entire transaction.
                        return;
                    }
                    throw new IllegalStateException("Activity has been destroyed");
                }
                if (mPendingActions == null) {//PendingActions 是空,就新建一个
                    mPendingActions = new ArrayList<>();
                }
                mPendingActions.add(action);//ADD操作加入ArrayList
                scheduleCommit();
            }
        }
    

    enqueue意思是入队,但是这里其实是个列表,不用在意这些细节。加入队列,后面scheduleCommit的名字看起来就是提交这个列表,执行列表里的各个操作了,看看源码:

    private void scheduleCommit() {
            synchronized (this) {
                boolean postponeReady =
                        mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
                boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
                if (postponeReady || pendingReady) {
                    mHost.getHandler().removeCallbacks(mExecCommit);
                    mHost.getHandler().post(mExecCommit);
                }
            }
        }
    

    又是通过Handler机制传递消息的。Handler从哪来的?mHost是什么?最开始的FragmentActivity里有个mHandler:

    public class FragmentActivity extends BaseFragmentActivityApi16 implements
            ActivityCompat.OnRequestPermissionsResultCallback,
            ActivityCompat.RequestPermissionsRequestCodeValidator {
             final FragmentController mFragments = 
             FragmentController.createController(new HostCallbacks());//mHost就是HostCallbacks,是FragmentHostCallback子类  
             final Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                 ............
                }
             }
    
            };
             ......
    }
    
    //activity.mHandler,Handler在这里
    public abstract class FragmentHostCallback<E> extends FragmentContainer {
       FragmentHostCallback(FragmentActivity activity) {
            this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);//mHandler就是FragmentActivity里的Handler
        }
        .........
    }
    

    好了,这里我们知道了mHost.getHandler().post(mExecCommit)的Handler是来自于FragmentActivity。这里有个问题scheduleCommit是在FragmentManager里调用的,FragmentManager的mHost为什么就是FragmentController的mHost呢?之后再分析,先看主流程,继续上面的:

       mHost.getHandler().post(mExecCommit);//mExecCommit是个Runnable
       Runnable mExecCommit = new Runnable() {
            @Override
            public void run() {
                execPendingActions();
            }
        };
        /**
         * Only call from main thread!
         */
        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;
        }
    
    private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
                ArrayList<Boolean> isPop) {
            boolean didSomething = false;
            synchronized (this) {
                if (mPendingActions == null || mPendingActions.size() == 0) {
                    return false;
                }
    
                final int numActions = mPendingActions.size();
                for (int i = 0; i < numActions; i++) {
                    didSomething |= mPendingActions.get(i).generateOps(records, isPop);//开始跑OP了
                }
                mPendingActions.clear();
                mHost.getHandler().removeCallbacks(mExecCommit);
            }
            return didSomething;
        }
    

    这里mPendingActions.get(i).generateOps(records, isPop)的generateOps是个接口方法,找到mPendingActions列表中的元素是哪个类,看看generateOps具体实现,这里的mPendingActions.get(i)就是上面的ADD操作,是个BackStackRecord对象,所以看看BackStackRecord的generateOps方法:

    /**
         * Implementation of {@link FragmentManagerImpl.OpGenerator}.
         * This operation is added to the list of pending actions during {@link #commit()}, and
         * will be executed on the UI thread to run this FragmentTransaction.
         *
         * @param records Modified to add this BackStackRecord
         * @param isRecordPop Modified to add a false (this isn't a pop)
         * @return true always because the records and isRecordPop will always be changed
         */
        @Override
    final class BackStackState implements Parcelable {
        public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
            records.add(this);//ADD加入records
            isRecordPop.add(false);
            if (mAddToBackStack) {
                mManager.addBackStackState(this);
            }
            return true;
        }
        ...........
    }
    

    看到这里知道了,generateOpsForPendingActions只是将mPendingActions里的元素加入到了mTmpRecords。那真正执行操作的应该就是removeRedundantOperationsAndExecute方法了:

    //只贴主要代码
    private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
                ArrayList<Boolean> isRecordPop) {
           .............
          final int numRecords = records.size();
          int startIndex = 0;
          for (int recordNum = 0; recordNum < numRecords; recordNum++) {
              if (startIndex != recordNum) {
                     executeOpsTogether(records, isRecordPop, startIndex, recordNum);
               }
           }
           .............
    }
    

    这里面又有很多调用,但是最终会回到每个BackStackRecord的executeOps()方法,executeOps就是个按操作类型执行各种具体动作的方法,比如OP_ADD,OP_REMOVE等等,看看OP_ADD操作干了什么:

       void executeOps() {
              final Fragment f = op.fragment;
               switch (op.cmd) {
                    case OP_ADD:
                        f.setNextAnim(op.enterAnim);
                        mManager.addFragment(f, false); //第二个参数false,又回到了FragmentManager
                        break;
                   .............
                  }
              if (!mReorderingAllowed) {
               // Added fragments are added at the end to comply with prior behavior.
                mManager.moveToState(mManager.mCurState, true);
            }
        }     
    
    final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
        final ArrayList<Fragment> mAdded = new ArrayList<>();
         public void addFragment(Fragment fragment, boolean moveToStateNow) 
         {
            if (DEBUG) Log.v(TAG, "add: " + fragment);
            makeActive(fragment);
            if (!fragment.mDetached) {
                if (mAdded.contains(fragment)) {
                    throw new IllegalStateException("Fragment already added: " + fragment);
                }
                synchronized (mAdded) {
                    mAdded.add(fragment);
                }
                fragment.mAdded = true;
                fragment.mRemoving = false;
                if (fragment.mView == null) {
                    fragment.mHiddenChanged = false;
                }
                if (fragment.mHasMenu && fragment.mMenuVisible) {
                    mNeedMenuInvalidate = true;
                }
                if (moveToStateNow) {//前面传来的是false,注意
                    moveToState(fragment);
                }
            }
        }
        //具体的Fragment操作都在FragmentManager里
        public void removeFragment(Fragment fragment) {
         ..........
        }
        public void hideFragment(Fragment fragment) {
           ........
        }
    }
    

    原来FragmentManager不过是将Fragment加入到自身的mAdded列表或者操作Fragment自身的属性,比如隐藏属性mHiddenChanged,具体查看其他几个方法就知道了。

    再总结下上面一堆代码:将ADD操作加入FragmentManager的mPendingActions列表后提交,经过Handler机制在主线程中,执行ADD操作的executeOps方法,将新的Fragment插入到FragmentManager的mAdded列表。

    走到这里,准备工作都做好了,下面该Fragment的生命周期上场了。因为传到addFragment的moveToStateNow是false,所以addFragment方法本身并没有走生命周期流程,回到executeOps方法,看到在最后调用了 mManager.moveToState。

    下一篇Fragment源码简析(二)

    相关文章

      网友评论

          本文标题:Fragment源码简析(一)

          本文链接:https://www.haomeiwen.com/subject/mpnbnxtx.html