Fragment源码简析(一)

先看使用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 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 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 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 records,
            ArrayList 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 records, ArrayList isRecordPop) {
        records.add(this);//ADD加入records
        isRecordPop.add(false);
        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
        return true;
    }
    ...........
}

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

//只贴主要代码
private void removeRedundantOperationsAndExecute(ArrayList records,
            ArrayList 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 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源码简析(二)

你可能感兴趣的