Fragment流程浅析

1,098 阅读8分钟
先从fragment基本用法出发:

getSupportFragmentManager().beginTransaction()
           .add(R.id.basic, new PageFragment()).commit();
其中点进去getSupportFragmentManager()可以看到跳转到FragmentActivity:

public FragmentManager getSupportFragmentManager() {     
    return mFragments.getSupportFragmentManager();  
}
先看下mFragments是啥:

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {    
      return new FragmentController(callbacks);
}
往下看.

private FragmentController(FragmentHostCallback<?> callbacks) {  
  mHost = callbacks;
}
public FragmentManager getSupportFragmentManager() {
    return mHost.getFragmentManagerImpl();
}
看样子是调用了FragmentHostCallback的getFragmentManagerImpl(),往下看HostCallbaks的代码:
class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
    public HostCallbacks() {
        super(FragmentActivity.this /*fragmentActivity*/);
    }

    @Override
    public LayoutInflater onGetLayoutInflater() {
        return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this);
    }

    //代码省略...
    @Override
    public FragmentActivity onGetHost() {
        return FragmentActivity.this;
    }

    @Override
    public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
        FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);
    }

     //代码省略...
   
    @Override
    public void onStartActivityFromFragment(
            Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) {
        FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode, options);
    }

    @Override
    public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
            @NonNull String[] permissions, int requestCode) {
        FragmentActivity.this.requestPermissionsFromFragment(fragment, permissions,
                requestCode);
    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        FragmentActivity.this.onAttachFragment(fragment);
    }

    //代码省略...
    @Nullable
    @Override
    public View onFindViewById(int id) {
        return FragmentActivity.this.findViewById(id);
    }
    //代码省略...
}
先有个印象,这里还有startActivity这样的方法,其实Fragment中启动的方法都是调用这里的,而且HostCallbacks是FragmentActivity的内部类,所以构造方法直接持有了Activity引用.
这里没找到getSupportFragmentManager()方法,再看看它的父类:
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    private final Activity mActivity;
    final Context mContext;
    private final Handler mHandler;
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    
     //省略大部分代码
    public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
        this(context instanceof Activity ? (Activity) context : null, context, handler,
                windowAnimations);
    }

    FragmentHostCallback(FragmentActivity activity) {
        this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
    }

    FragmentHostCallback(Activity activity, Context context, Handler handler,
            int windowAnimations) {
        mActivity = activity;
        mContext = context;
        mHandler = handler;
        mWindowAnimations = windowAnimations;
    }

    /**
     * Return a {@link LayoutInflater}.
     * See {@link Activity#getLayoutInflater()}.
     */
    public LayoutInflater onGetLayoutInflater() {
        return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    Activity getActivity() {
        return mActivity;
    }

    Context getContext() {
        return mContext;
    }

    Handler getHandler() {
        return mHandler;
    }

    FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManager;
    }
}
可以看到子类没有重写getSupportFragmentManager()方法,所以获得的对象就是FragmentMangerImpl了.再继续往下看beginTransaction()方法:
@Override
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}
又可以看到beginTransaction()返回的对象是BacStateRecord,继续往下看
@Override
public FragmentTransaction add(Fragment fragment, String tag) {
    doAddOp(0, fragment, tag, OP_ADD);
    return this;
}

@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

@Override
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
    doAddOp(containerViewId, fragment, tag, OP_ADD);
    return this;
}

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    final Class fragmentClass = fragment.getClass();
    final int modifiers = fragmentClass.getModifiers();
    if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
            || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
        throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                + " must be a public static class to be  properly recreated from"
                + " instance state.");
    }

    fragment.mFragmentManager = mManager;

    if (tag != null) {
        if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
            throw new IllegalStateException("Can't change tag of fragment "
                    + fragment + ": was " + fragment.mTag
                    + " now " + tag);
        }
        fragment.mTag = tag;
    }

    if (containerViewId != 0) {
        if (containerViewId == View.NO_ID) {
            throw new IllegalArgumentException("Can't add fragment "
                    + fragment + " with tag " + tag + " to container view with no id");
        }
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            throw new IllegalStateException("Can't change container ID of fragment "
                    + fragment + ": was " + fragment.mFragmentId
                    + " now " + containerViewId);
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }

    Op op = new Op();
    op.cmd = opcmd;
    op.fragment = fragment;
    addOp(op);
}

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

@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
    if (containerViewId == 0) {
        throw new IllegalArgumentException("Must use non-zero containerViewId");
    }

    doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    return this;
}

@Override
public FragmentTransaction remove(Fragment fragment) {
    Op op = new Op();
    op.cmd = OP_REMOVE;
    op.fragment = fragment;
    addOp(op);

    return this;
}

@Override
public FragmentTransaction hide(Fragment fragment) {
    Op op = new Op();
    op.cmd = OP_HIDE;
    op.fragment = fragment;
    addOp(op);

    return this;
}

@Override
public FragmentTransaction show(Fragment fragment) {
    Op op = new Op();
    op.cmd = OP_SHOW;
    op.fragment = fragment;
    addOp(op);

    return this;
}
void addOp(Op op) {
    mOps.add(op);
    op.enterAnim = mEnterAnim;
    op.exitAnim = mExitAnim;
    op.popEnterAnim = mPopEnterAnim;
    op.popExitAnim = mPopExitAnim;
}
所有add方法和replace方法都调用到doAppOp方法,然后最终都回调到addOp方法。
先看下doAppOp方法,首先先检测fragment是不是匿名类或者不是公共类或者是成员变量且是静态的,就抛出异常.
接下来给fragment赋值,首先就是赋值mFragmentManager为FragmentMangerImpl,如果用户设置tag,则再设置fragment的tag,如果之前设置过就报错,mContainerId同理,接下来看Op这个类:
static final class Op {
    int cmd;
    Fragment fragment;
    int enterAnim;
    int exitAnim;
    int popEnterAnim;
    int popExitAnim;
}

就几个成员变量,cmd都是设为1,然后放入fragment,然后放入设置的动画.show和hide也调用该方法,然后看最后一步commit:

@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);
}

@Override
public FragmentTransaction setAllowOptimization(boolean allowOptimization) {
    mAllowOptimization = allowOptimization;
    return this;
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) throw new IllegalStateException("commit already called");
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Commit: " + this);
        LogWriter logw = new LogWriter(TAG);
        PrintWriter pw = new PrintWriter(logw);
        dump("  ", null, pw, null);
        pw.close();
    }
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex; 
commit操作都调用了commitInternal方法,这里有个mCommit控制,如果同一个BackStackRecord对象第二次再commit,是会报错的,DEBUG模式下打印log,
mAddToBackStack赋值在以下代码:
@Override
public FragmentTransaction disallowAddToBackStack() {
    if (mAddToBackStack) {
        throw new IllegalStateException(
                "This transaction is already being added to the back stack");
    }
    mAllowAddToBackStack = false;
    return this;
}
设置过回退栈名称的 mAddToBackStack = true;
如果mAddToBackStack为true,则加入到FragmentManger的一个集合中,并返回在当前集合中的位置,代码如下:
public int allocBackStackIndex(BackStackRecord bse) {
    synchronized (this) {
        if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
            if (mBackStackIndices == null) {
                mBackStackIndices = new ArrayList<BackStackRecord>();
            }
            int index = mBackStackIndices.size();
            if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
            mBackStackIndices.add(bse);
            return index;

        } else {
            int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
            if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
            mBackStackIndices.set(index, bse);
            return index;
        }
    }
}
接下来执行的是mManager.enqueueAction(this, allowStateLoss),
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<>();
        }
        mPendingActions.add(action);
        scheduleCommit();
    }
}
这里我们可以分析commit()和commitAllowingStateLoss()啥区别了,commit传入的allowStateLoss的是false,而commitAllowingStateLoss()传入的是true,两个唯一的 不同点就是commit执行了allowStateLoss方法:
private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }
}
判断mStateSaved是否保存,如果保存了则不允许再次
提交,然后报错,也就是说commit()必须在onSaveInstanceState()方法之前调用,不然就是抛异常了.
继续往下看,这里用synchronized锁,如果被销毁了或者mHost为空,则报异常说activity已经销毁了,这个mHost是持有activity的引用的.队列为空则创建队列,然后加入当前的action,当前action实现的方法如下:
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Run: " + this);
    }

    records.add(this);
    isRecordPop.add(false);
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
    return true;
}
其实就是加入FragmentManager的队列而已.继续看:
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);
        }
    }
}
mHost.getHandler()其实就是FragmentActivity中的mHandler了,先移除,确保没有该Callback,然后加入Callback.看下具体实现:
Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};
public boolean execPendingActions() {
    ensureExecReady(true);

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

    doPendingDeferredStart();

    return didSomething;
}
再回头看下commitNow()和commitNowAllowingStateLoss()方法,就是设置禁止加入返回栈,然后execSingleAction方法和execPendingActions()几乎一模一样,从这里看出commit和commitNow()的区别就是一个需要handler队列来执行,一个直接执行,allowStateLoss还是代表是否检测.
@Override
public FragmentTransaction disallowAddToBackStack() {
    if (mAddToBackStack) {
        throw new IllegalStateException(
                "This transaction is already being added to the back stack");
    }
    mAllowAddToBackStack = false;
    return this;
}
public void execSingleAction(OpGenerator action, boolean allowStateLoss) {
    ensureExecReady(allowStateLoss);
    if (action.generateOps(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
    }

    doPendingDeferredStart();
}
看下generateOpsForPendingActions(mTmpRecords, mTmpIsPop):
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isPop) {
    int numActions;
    synchronized (this) {
        if (mPendingActions == null || mPendingActions.size() == 0) {
            return false;
        }

        numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {
            mPendingActions.get(i).generateOps(records, isPop);
        }
        mPendingActions.clear();
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return numActions > 0;
}
​其实就是执行了上面的generateOps方法,而且mPendingActions执行结束被清空了。
其他代码有点繁多,自己有情趣可以去看看,现在重点来看 doPendingDeferredStart():
void doPendingDeferredStart() {
    if (mHavePendingDeferredStart) {
        boolean loadersRunning = false;
        for (int i = 0; i < mActive.size(); i++) {
            Fragment f = mActive.get(i);
            if (f != null && f.mLoaderManager != null) {
                loadersRunning |= f.mLoaderManager.hasRunningLoaders();
            }
        }
        if (!loadersRunning) {
            mHavePendingDeferredStart = false;
            startPendingDeferredFragments();
        }
    }
}
void startPendingDeferredFragments() {
    if (mActive == null) return;

    for (int i=0; i<mActive.size(); i++) {
        Fragment f = mActive.get(i);
        if (f != null) {
            performPendingDeferredStart(f);
        }
    }
}
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(f, mCurState, 0, 0, false);
    }
}
由于能力有限,就直接讲最重要的 moveToState(f, mCurState, 0, 0, false)方法了.
讲这个之前,首先得先讲Fragment如何和Activity生命周期联系起来.
看下FragmentActivity的onCreate方法:
protected void onCreate(@Nullable Bundle savedInstanceState) {
      //代码省略..
      mFragments.dispatchCreate();
}

public void dispatchCreate() {
      mHost.mFragmentManager.dispatchCreate();
}

public void dispatchCreate() {
      mStateSaved = false;
      mExecutingActions = true;
      moveToState(Fragment.CREATED, false);
      mExecutingActions = false;
}

void moveToState(int newState, boolean always) {
      //代码省略..
      mCurState = newState;
      //代码省略..
      if (!loadersRunning) {
         startPendingDeferredFragments();
      }
     //代码省略..
}

mCurState就是activity当前的生命周期了,然后又调用startPendingDeferredFragments()最终还是到moveToState(f, mCurState, 0, 0, false)方法了,其他生命周期同理.
moveToState代码量有点多,我就省略大部分代码了,所以只讲下create流程了.
case Fragment.CREATED:
    if (newState > Fragment.CREATED) {
        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
        if (!f.mFromLayout) {
            ViewGroup container = null;

             //mContainerId就是add(int containerId,Fragment fragment)传进来的布局id,
            if (f.mContainerId != 0) {
                if (f.mContainerId == View.NO_ID) {
                    throwException(new IllegalArgumentException(
                            "Cannot create fragment "
                                    + f
                                    + " for a container view with no id"));
                }

//mContainer.onFindViewById等同HostCallbacks.onFindViewById(int id),
//也就是FragmentActivity.this.findViewById(id)                       container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                if (container == null && !f.mRestored) {
                    String resName;
                    try {
                        resName = f.getResources().getResourceName(f.mContainerId);
                    } catch (NotFoundException e) {
                        resName = "unknown";
                    }
                    throwException(new IllegalArgumentException(
                            "No view found for id 0x"
                            + Integer.toHexString(f.mContainerId) + " ("
                            + resName
                            + ") for fragment " + f));
                }
            }
            f.mContainer = container;

            //执行onCreateView方法,
            f.mView = f.performCreateView(f.getLayoutInflater(
                    f.mSavedFragmentState), container, f.mSavedFragmentState);
            if (f.mView != null) {
                f.mInnerView = f.mView;
                if (Build.VERSION.SDK_INT >= 11) {
                    ViewCompat.setSaveFromParentEnabled(f.mView, false);
                } else {
                    f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                }

//这里把返回的view添加进activity的container中,这里引出一个问题,以前碰到过在
// onCreateView中设置View view = inflater.inflate(R.layout.fragment_page, container, //true);
//会直接蹦,原因就在这里了,因为设置为true就将子类添加进父类了,然后这里又进行一次添加操作,就抛出异常了                if (container != null) {
                    container.addView(f.mView);
                }
                if (f.mHidden) {
                    f.mView.setVisibility(View.GONE);
                }
                
                //执行onViewCreated方法
                f.onViewCreated(f.mView, f.mSavedFragmentState);

                //这里如果用户设置过registerFragmentLifecycleCallbacks,就回调对应的方法.
                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                        false);
                // Only animate the view if it is visible. This is done after
                // dispatchOnFragmentViewCreated in case visibility is changed
                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                        && f.mContainer != null;
            } else {
                f.mInnerView = null;
            }
        }

        //执行onActivityCreated方法,然后同理回调
        f.performActivityCreated(f.mSavedFragmentState);
        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
        if (f.mView != null) {
            f.restoreViewState(f.mSavedFragmentState);
        }
        f.mSavedFragmentState = null;
    }
我觉得以后多Fragment开发可能会越来越火,了解一下Fragment的基本流程,还是挺重要的吧。由于能力有限,我只是讲下Fragment的流程的一点毛皮,如有错误还望指出。
顺便推荐下一个大神写的Fragment框架:github.com/YoKeyword/F…