带你从源码理解Fragment机制

相信大家平时用到很多Fragment, 手机平板的代码共用,各种东西的复用,用Fragment也很方便。如今Fragment遍布在我们的APP里面,今天此文将讲解Activity是如何Fragment机制联动的,以及各个生命周期是如何走的,因为,说实话,Fragment的生命周期足够复杂,我们需要知道它的各个生命周期是如何被调用的。

今天涉及到的类(本文基于Android8.1源码):
// Activity类, AMS控制的生命周期都是回调给Activity
frameworks/base/core/java/android/app/Activity.java
// Fragment,被实现对象,被回调生命周期对象
frameworks/base/core/java/android/app/Fragment.java
// FragmentController 其实是一个代理类,代理FragmentManager那些方法
frameworks/base/core/java/android/app/FragmentController.java
// FragmentHostCallback 这是一个抽象类,需要主体实现,里面实现一些Fragment机制中所不能实现的功能,比如请求权限,这些都需要主体来实现
frameworks/base/core/java/android/app/FragmentHostCallback.java
// Fragment的管理类,被FragmentHostCallback持有,负责控制Fragment的状态,真正做操作的类
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();
    }

    // 在这里实现FragmentHostCallback所无法实现的那些功能,列如activituy跳转的数据结果等
    class HostCallbacks extends FragmentHostCallback<Activity> {
      ...
    }
}

从FragmentController的源码可以看到,构造方法的参数为: FragmentHostCallback且,这是唯一的变量。
然后其他方法都是代理, 都调用的是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;
    }

    // 调用mHost.mFragmentManager的同名方法
    public void dispatchResume() {
        mHost.mFragmentManager.dispatchResume();
    }

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

     ....
}

我们在前面看Activity初始化FragmentControl的时候,会传FragmentHostCallback类,

那么mHost.mFragmentManager是什么呢,其是FragmentManagerImpl类,这个是FragmentManger的一个内部类,也继承于FragmentManger, 并且实现了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类是最核心的类,Fragment由其管理,各种安全检查也由其做。代码如下

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;

我们可以看到,里面有各种状态位保存,回退栈等,都在这个类里面记录。

到这里我们应该知道Fragment体系的几个类是干嘛的了。接下从一个方法来看看Fragment的事务如何处理。

Fragment事务

我们一般使用Fragment是按照下面这样使用的,开启一个事务,最后commit

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

我们来看下beginTransaction方法的实现

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

    // 链表节点
    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列表里面去。这个列表是我们在上面定义的,一个链表。

这个流程到这其实就结束了,接下来我们会调用 commit方法。
commit里面调用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);  //调用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();  // 这边会检查状态,若activity已经走了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();
    }
}

接下来开启执行的runnable,进行调度动作

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

这样会调用到Runnable中的execPendingActions()方法

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

    boolean didSomething = false;
    // 进入死循环, generateOpsForPendingActions会判断当前是否还有任务
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            // 去掉多余任务,并执行任务
            // 执行任务的时候,会去挨个调用BackStackRecord中的expandOps方法。里面会执行之前的Ops
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            // 清理多余任务
            cleanupExec();
        }
        didSomething = true;
    }

    doPendingDeferredStart();
    burpActive();

    return didSomething;
}

我们看一下 removeRedundantOperationsAndExecute里面调用BackStackRecord中的expandOps方法的逻辑,在这里就负责取出各个事务进行操作。

Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
     //遍历链表挨个取出动作进行执行
     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的生命周期回调

对于Fragment的生命周期,很多人都理解不懂,毕竟生命周期过多,从源码看,应该会好很多。我们看下Activity是如何回调Fragment的生命周期的。

Activity源码中:

protected void onCreate(@Nullable Bundle savedInstanceState) {
 ...
   //调用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();
}

最后会调到:
这个方法特别长,

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:   //里面会回调onAttach
              ...
              f.onAttach(mHost.getContext());
              break;
         case Fragment.CREATED:
              f.mView = f.performCreateView(f.performGetLayoutInflater(  // 回调onCreateView
                               f.mSavedFragmentState), container, f.mSavedFragmentState);
              f.onViewCreated(f.mView, f.mSavedFragmentState);      // 回调onViewCreated
              f.performActivityCreated(f.mSavedFragmentState);      // 回调 onActivityCreated(savedInstanceState);
               dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);  
              if (f.mView != null) {
                  f.restoreViewState(f.mSavedFragmentState);     // 回调 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();                          // 回调 onStart
                      dispatchOnFragmentStarted(f, false);
                  }
                  // fall through
              case Fragment.STARTED:
                  if (newState > Fragment.STARTED) {
                      if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                      f.performResume();                        // 回调 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);      // 调用Activity的onResume

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

    mFragments.dispatchResume();     // 调用Fragment的onResume
    mFragments.execPendingActions();

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

通过阅读这些源码,我们可以总结出Fragment的生命周期如下


fragment-life.png

结尾

520这天,写了这篇博客。。。嗯 希望大家多多进步


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容