帶你從源碼理解Fragment機制

相信大家平時用到很多Fragment, 手機平板的代碼共用,各種東西的復(fù)用,用Fragment也很方便。如今Fragment遍布在我們的APP里面,今天此文將講解Activity是如何Fragment機制聯(lián)動的,以及各個生命周期是如何走的,因為,說實話,F(xiàn)ragment的生命周期足夠復(fù)雜,我們需要知道它的各個生命周期是如何被調(diào)用的。

今天涉及到的類(本文基于Android8.1源碼):
// Activity類, AMS控制的生命周期都是回調(diào)給Activity
frameworks/base/core/java/android/app/Activity.java
// Fragment,被實現(xiàn)對象,被回調(diào)生命周期對象
frameworks/base/core/java/android/app/Fragment.java
// FragmentController 其實是一個代理類,代理FragmentManager那些方法
frameworks/base/core/java/android/app/FragmentController.java
// FragmentHostCallback 這是一個抽象類,需要主體實現(xiàn),里面實現(xiàn)一些Fragment機制中所不能實現(xiàn)的功能,比如請求權(quán)限,這些都需要主體來實現(xiàn)
frameworks/base/core/java/android/app/FragmentHostCallback.java
// Fragment的管理類,被FragmentHostCallback持有,負(fù)責(zé)控制Fragment的狀態(tài),真正做操作的類
frameworks/base/core/java/android/app/FragmentManager.java

Fragment體系類介紹

我們從Activity下手, 從getFragmentManager來看,我們是去從FragmentController中獲取的FragmentManager。

public class Activity extends... {

    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

    /**
     * Return the FragmentManager for interacting with fragments associated
     * with this activity.
     */
    public FragmentManager getFragmentManager() {
        return mFragments.getFragmentManager();
    }

    // 在這里實現(xiàn)FragmentHostCallback所無法實現(xiàn)的那些功能,列如activituy跳轉(zhuǎn)的數(shù)據(jù)結(jié)果等
    class HostCallbacks extends FragmentHostCallback<Activity> {
      ...
    }
}

從FragmentController的源碼可以看到,構(gòu)造方法的參數(shù)為: FragmentHostCallback且,這是唯一的變量。
然后其他方法都是代理, 都調(diào)用的是mHost.mFragmentManager中的同名方法。
代碼如下:

public class FragmentController {
    private final FragmentHostCallback<?> mHost;

    /**
     * Returns a {@link FragmentController}.
     */
    public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
        return new FragmentController(callbacks);
    }

    private FragmentController(FragmentHostCallback<?> callbacks) {
        mHost = callbacks;
    }

    // 調(diào)用mHost.mFragmentManager的同名方法
    public void dispatchResume() {
        mHost.mFragmentManager.dispatchResume();
    }

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

     ....
}

我們在前面看Activity初始化FragmentControl的時候,會傳FragmentHostCallback類,

那么mHost.mFragmentManager是什么呢,其是FragmentManagerImpl類,這個是FragmentManger的一個內(nèi)部類,也繼承于FragmentManger, 并且實現(xiàn)了LayoutInflaterFactory接口。是個做實事的家伙。

public abstract class FragmentHostCallback<E> extends FragmentContainer {
    private final Activity mActivity;
    final Context mContext;
    private final Handler mHandler;
    final int mWindowAnimations;
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
    private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;
    /** Whether or not fragment loaders should retain their state */
    private boolean mRetainLoaders;
    /** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
    private LoaderManagerImpl mLoaderManager;
    private boolean mCheckedForLoaderManager;
    /** Whether or not the fragment host loader manager was started */
    private boolean mLoadersStarted;

    public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
        this(null /*activity*/, context, handler, windowAnimations);
    }
    ...
  }

FragmentManagerImpl類是最核心的類,F(xiàn)ragment由其管理,各種安全檢查也由其做。代碼如下

final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
    static final String TAG = "FragmentManager";

    ArrayList<OpGenerator> mPendingActions;
    boolean mExecutingActions;

    int mNextFragmentIndex = 0;
    SparseArray<Fragment> mActive;
    final ArrayList<Fragment> mAdded = new ArrayList<>();
    ArrayList<BackStackRecord> mBackStack;
    ArrayList<Fragment> mCreatedMenus;

    // Must be accessed while locked.
    ArrayList<BackStackRecord> mBackStackIndices;
    ArrayList<Integer> mAvailBackStackIndices;

    ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
    final CopyOnWriteArrayList<Pair<FragmentLifecycleCallbacks, Boolean>>
            mLifecycleCallbacks = new CopyOnWriteArrayList<>();

    int mCurState = Fragment.INITIALIZING;
    FragmentHostCallback<?> mHost;
    FragmentContainer mContainer;
    Fragment mParent;
    Fragment mPrimaryNav;

    boolean mNeedMenuInvalidate;
    boolean mStateSaved;
    boolean mDestroyed;
    String mNoTransactionsBecause;
    boolean mHavePendingDeferredStart;

    // Temporary vars for removing redundant operations in BackStackRecords:
    ArrayList<BackStackRecord> mTmpRecords;
    ArrayList<Boolean> mTmpIsPop;
    ArrayList<Fragment> mTmpAddedFragments;

    // Temporary vars for state save and restore.
    Bundle mStateBundle = null;
    SparseArray<Parcelable> mStateArray = null;

    // Postponed transactions.
    ArrayList<StartEnterTransitionListener> mPostponedTransactions;

    // Prior to O, we allowed executing transactions during fragment manager state changes.
    // This is dangerous, but we want to keep from breaking old applications.
    boolean mAllowOldReentrantBehavior;

    // Saved FragmentManagerNonConfig during saveAllState() and cleared in noteStateNotSaved()
    FragmentManagerNonConfig mSavedNonConfig;

我們可以看到,里面有各種狀態(tài)位保存,回退棧等,都在這個類里面記錄。

到這里我們應(yīng)該知道Fragment體系的幾個類是干嘛的了。接下從一個方法來看看Fragment的事務(wù)如何處理。

Fragment事務(wù)

我們一般使用Fragment是按照下面這樣使用的,開啟一個事務(wù),最后commit

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
  transaction.replace(R.id.main_fragment_container, homeFragment);
   transaction.commit();

我們來看下beginTransaction方法的實現(xiàn)

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

可以見到,其返回了一個BackStackRecord類,那么這個類是繼承于FragmentTransaction的

/**
 * @hide Entry of an operation on the fragment back stack.
 */
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
    static final String TAG = FragmentManagerImpl.TAG;

    final FragmentManagerImpl mManager;

    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    static final int OP_SET_PRIMARY_NAV = 8;
    static final int OP_UNSET_PRIMARY_NAV = 9;

    // 鏈表節(jié)點
    static final class Op {
        int cmd;      // 表明動作
        Fragment fragment;  //被操作的Fragment
        int enterAnim;  // 進入動畫
        int exitAnim;   // 退出動畫
        int popEnterAnim;  // 彈入動畫
        int popExitAnim;   // 彈出動畫

        Op() {
        }

        Op(int cmd, Fragment fragment) {
            this.cmd = cmd;
            this.fragment = fragment;
        }
    }

    ArrayList<Op> mOps = new ArrayList<>();  
    int mEnterAnim;
    int mExitAnim;
    int mPopEnterAnim;
    int mPopExitAnim;
    int mTransition;
    int mTransitionStyle;
    boolean mAddToBackStack;
    boolean mAllowAddToBackStack = true;
    String mName;
    boolean mCommitted;
    int mIndex = -1;
    boolean mReorderingAllowed;

    ArrayList<Runnable> mCommitRunnables;

    int mBreadCrumbTitleRes;
    CharSequence mBreadCrumbTitleText;
    int mBreadCrumbShortTitleRes;
    CharSequence mBreadCrumbShortTitleText;

    ArrayList<String> mSharedElementSourceNames;
    ArrayList<String> mSharedElementTargetNames;

我們從其add方法來看

public FragmentTransaction add(Fragment fragment, String tag) {
    doAddOp(0, fragment, tag, OP_ADD);
    return this;
}

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    if (mManager.getTargetSdk() > Build.VERSION_CODES.N_MR1) {
        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) {
        ....
        fragment.mTag = tag;
    }

    if (containerViewId != 0) {
        ...
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }

    addOp(new Op(opcmd, fragment));
}

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

可以看到,其將整個操作封裝成了一個Op并將其添加到mOps列表里面去。這個列表是我們在上面定義的,一個鏈表。

這個流程到這其實就結(jié)束了,接下來我們會調(diào)用 commit方法。
commit里面調(diào)用FragmentManager的enqueueAction方法

public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) {
        throw new IllegalStateException("commit already called");
    }
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Commit: " + this);
        LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
        PrintWriter pw = new FastPrintWriter(logw, false, 1024);
        dump("  ", null, pw, null);
        pw.flush();
    }
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);  //調(diào)用FragmentManager的enqueueAction方法
    return mIndex;
}

FragmentManager中將操作添加進pendingAction中

/**
 * Adds an action to the queue of pending actions.
 *
 * @param action the action to add
 * @param allowStateLoss whether to allow loss of state information
 * @throws IllegalStateException if the activity has been destroyed
 */
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();  // 這邊會檢查狀態(tài),若activity已經(jīng)走了onSaveInstanceStatus,這邊會拋出異常
    }
    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) {
            mPendingActions = new ArrayList<>();
        }
         // 將commit處理操作放置到mPendingActions列表中
        mPendingActions.add(action);
        scheduleCommit();
    }
}

接下來開啟執(zhí)行的runnable,進行調(diào)度動作

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

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

這樣會調(diào)用到Runnable中的execPendingActions()方法

/**
 * Only call from main thread!
 */
public boolean execPendingActions() {
    ensureExecReady(true);

    boolean didSomething = false;
    // 進入死循環(huán), generateOpsForPendingActions會判斷當(dāng)前是否還有任務(wù)
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            // 去掉多余任務(wù),并執(zhí)行任務(wù)
            // 執(zhí)行任務(wù)的時候,會去挨個調(diào)用BackStackRecord中的expandOps方法。里面會執(zhí)行之前的Ops
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            // 清理多余任務(wù)
            cleanupExec();
        }
        didSomething = true;
    }

    doPendingDeferredStart();
    burpActive();

    return didSomething;
}

我們看一下 removeRedundantOperationsAndExecute里面調(diào)用BackStackRecord中的expandOps方法的邏輯,在這里就負(fù)責(zé)取出各個事務(wù)進行操作。

Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
     //遍歷鏈表挨個取出動作進行執(zhí)行
     for (int opNum = 0; opNum < mOps.size(); opNum++) {
         final Op op = mOps.get(opNum);
         switch (op.cmd) {
             case OP_ADD:
             case OP_ATTACH:
                 added.add(op.fragment);
                 break;
             case OP_REMOVE:
             case OP_DETACH: {
                 added.remove(op.fragment);
                 if (op.fragment == oldPrimaryNav) {
                     mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.fragment));
                     opNum++;
                     oldPrimaryNav = null;
                 }
             }
             break;
             case OP_REPLACE: {
                 final Fragment f = op.fragment;
                 final int containerId = f.mContainerId;
                 boolean alreadyAdded = false;
                 for (int i = added.size() - 1; i >= 0; i--) {
                     final Fragment old = added.get(i);
                     if (old.mContainerId == containerId) {
                         if (old == f) {
                             alreadyAdded = true;
                         } else {
                             // This is duplicated from above since we only make
                             // a single pass for expanding ops. Unset any outgoing primary nav.
                             if (old == oldPrimaryNav) {
                                 mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
                                 opNum++;
                                 oldPrimaryNav = null;
                             }
                             final Op removeOp = new Op(OP_REMOVE, old);
                             removeOp.enterAnim = op.enterAnim;
                             removeOp.popEnterAnim = op.popEnterAnim;
                             removeOp.exitAnim = op.exitAnim;
                             removeOp.popExitAnim = op.popExitAnim;
                             mOps.add(opNum, removeOp);
                             added.remove(old);
                             opNum++;
                         }
                     }
                 }
                 if (alreadyAdded) {
                     mOps.remove(opNum);
                     opNum--;
                 } else {
                     op.cmd = OP_ADD;
                     added.add(f);
                 }
             }
             break;
             case OP_SET_PRIMARY_NAV: {
                 // It's ok if this is null, that means we will restore to no active
                 // primary navigation fragment on a pop.
                 mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
                 opNum++;
                 // Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
                 oldPrimaryNav = op.fragment;
             }
             break;
         }
     }
     return oldPrimaryNav;
 }

Fragment的生命周期回調(diào)

對于Fragment的生命周期,很多人都理解不懂,畢竟生命周期過多,從源碼看,應(yīng)該會好很多。我們看下Activity是如何回調(diào)Fragment的生命周期的。

Activity源碼中:

protected void onCreate(@Nullable Bundle savedInstanceState) {
 ...
   //調(diào)用FragmnentController的 dispatchCreate方法
    mFragments.dispatchCreate();
}

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

FragmentManager中

public void dispatchCreate() {
    mStateSaved = false;
    dispatchMoveToState(Fragment.CREATED);
}

private void dispatchMoveToState(int state) {
    if (mAllowOldReentrantBehavior) {
        moveToState(state, false);
    } else {
        try {
            mExecutingActions = true;
            moveToState(state, false);
        } finally {
            mExecutingActions = false;
        }
    }
    execPendingActions();
}

最后會調(diào)到:
這個方法特別長,

static final int INVALID_STATE = -1;   // Invalid state used as a null value.
static final int INITIALIZING = 0;     // Not yet created.
static final int CREATED = 1;          // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3;          // Fully created, not started.
static final int STARTED = 4;          // Created and started, not resumed.
static final int RESUMED = 5;          // Created started and resumed.

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    switch (f.mState) {
         case Fragment.INITIALIZING:   //里面會回調(diào)onAttach
              ...
              f.onAttach(mHost.getContext());
              break;
         case Fragment.CREATED:
              f.mView = f.performCreateView(f.performGetLayoutInflater(  // 回調(diào)onCreateView
                               f.mSavedFragmentState), container, f.mSavedFragmentState);
              f.onViewCreated(f.mView, f.mSavedFragmentState);      // 回調(diào)onViewCreated
              f.performActivityCreated(f.mSavedFragmentState);      // 回調(diào) onActivityCreated(savedInstanceState);
               dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);  
              if (f.mView != null) {
                  f.restoreViewState(f.mSavedFragmentState);     // 回調(diào) onViewStateRestored(savedInstanceState);
              }
              case Fragment.ACTIVITY_CREATED:
                  if (newState > Fragment.ACTIVITY_CREATED) {
                      f.mState = Fragment.STOPPED;
                  }
                  // fall through
              case Fragment.STOPPED:
                  if (newState > Fragment.STOPPED) {
                      if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                      f.performStart();                          // 回調(diào) onStart
                      dispatchOnFragmentStarted(f, false);
                  }
                  // fall through
              case Fragment.STARTED:
                  if (newState > Fragment.STARTED) {
                      if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                      f.performResume();                        // 回調(diào) onResume
                      dispatchOnFragmentResumed(f, false);
                      // Get rid of this in case we saved it and never needed it.
                      f.mSavedFragmentState = null;
                      f.mSavedViewState = null;
                  }
              ....

}

其他的生命周期也是類似的,大體都一樣

final void performPause() {
    mDoReportFullyDrawn = false;
    mFragments.dispatchPause();     // 通知Fragment onPause
    mCalled = false;
    onPause();                      //Activity自身onPause
    mResumed = false;
    if (!mCalled && getApplicationInfo().targetSdkVersion
            >= android.os.Build.VERSION_CODES.GINGERBREAD) {
        throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onPause()");
    }
    mResumed = false;
}


final void performResume() {
    performRestart();

    mFragments.execPendingActions();

    mLastNonConfigurationInstances = null;

    mCalled = false;
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this);      // 調(diào)用Activity的onResume

    // Now really resume, and install the current status bar and menu.
    mCalled = false;

    mFragments.dispatchResume();     // 調(diào)用Fragment的onResume
    mFragments.execPendingActions();

    onPostResume();
    if (!mCalled) {
        throw new SuperNotCalledException(
            "Activity " + mComponent.toShortString() +
            " did not call through to super.onPostResume()");
    }
}

通過閱讀這些源碼,我們可以總結(jié)出Fragment的生命周期如下


fragment-life.png

結(jié)尾

520這天,寫了這篇博客。。。嗯 希望大家多多進步


本文作者:Anderson/Jerey_Jobs
博客地址 : http://jerey.cn/
簡書地址 : Anderson大碼渣
github地址 : https://github.com/Jerey-Jobs

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容