Fragment笔记

1.FragmentMananger 与 FragmentActivity 的关系.

        val firstFragment = TestFragmentFirst()
        val secondFragment = TestFragmentSecond()
        val thirdFragment = TestFragmentThird()

        supportFragmentManager
            .beginTransaction()
            .add(R.id.container,secondFragment)
            .replace(R.id.container,thirdFragment)
            .remove(thirdFragment)
            .remove(secondFragment)
            .add(R.id.container,firstFragment)
            .commit()

这段代码应该都很熟悉了吧,创建了三个 fragment 然后调用 supportFragmentManager 开启事务,进行添加,替换,移除,提交操作.
但是,这个 supportFragmentManager 是如何得到的呢?按照常理我们觉得应该是在 FragmentActivity 创建初始化的时候创建的,然后直接调用 getSupportFragmentManager() 就可以直接拿到了.我们点进去看一下

  FragmentActivity.Java
    /**
     * Return the FragmentManager for interacting with fragments associated
     * with this activity.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }

发现并不是这样,这个方法的实现是委托给了mFragments,也就是 FragmentController ,而这个对象是在 FragmentActivity 创建的时候一并初始化的,并且我们搜索一下这个 mFragments 就会发现在 FragmentActivity 的生命周期当中,都调用了 mFragments.dispatch...() 相应的方法,
比如在 onCreate 中调用了 mFragments.dispatchCreate(); 再来看看 FragmentActivity 的 import ,发现也没有跟 Fragment 相关的引入,也就是说 FragmentActivity 之所以能完成对 Fragment 相应的管理,它是委托给了 FragmentContorller mFragments.

2.这里有个问题,为什么要这么做呢,而不是用 FragmentActivity 直接去操作 FragmentMananger?

说了这么多 FragmentContorller ,我们来看看这个类吧

FragmentContorller.Java
    /**
     * Returns a {@link FragmentManager} for this controller.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() {
        return mHost.mFragmentManager;
    }

可以看到也并没有具体的实现,而是转发给了 FragmentHostCallback<?> mHost; 跟进一下FragmentHostCallback,

FragmentHostCallback.java
/**
 * Integration points with the Fragment host.
 * <p>
 * Fragments may be hosted by any object; such as an {@link Activity}. In order to
 * host fragments, implement {@link FragmentHostCallback}, overriding the methods
 * applicable to the host.
 */
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    @Nullable private final Activity mActivity;
    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    private final int mWindowAnimations;
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
.......
.......
}

可以看到直接创建了 FragmentMananger 对象,看一下类头文档:
Fragment可以被任何对象持有,最常见的就是 activity,但是这并不以为着 Fragment 只能在 activity 中运行,只要一个宿主它实现了 FragmentHostCallback,提供一些 Fragment 运行时的能力,那么它就可以作为 Fragment 的宿主.
而 FragmentActivity 就是实现了 FragmentHostCallback,从这里我们发现,虽然在我们的认知中 FragmentActivity 是专门进行 Fragment 管理的宿主,但是它也是仅仅创建了一个 FragmentContorller,实现了一个 HostCallbacks 接口,就可以完成对 Fragment 的管理中作了,
假如以后出现了一个新的宿主,也可以承载 Fragment 的运行,它只要创建一个 FragmentController,实现 HostCallback 就可以了,所以设计这个 FragmentContoller 和 HostCallback 的原因,就是为了屏蔽宿主对 Fragment 的直接引用,从而拓展了 Fragment 的应用场景,而不单单局限与 Activity,加大了代码的拓展性.

3.Fragment 的生命周期是怎么赋予的?ragment 的 View 是如何被添加到 Activity 的 ViewGroup 之中的?

从新回到开始的那段代码, 我们来看看 FragmentTransaction,这是一个能够操作事务的对象(事务:就是一次性能够添加多个操作,比如上面的 add(),replace(),remove(),这些操作要么全部成功,要么全部不成功),来看看 beginTransaction() ,它是 FragmentMananger 里面的方法,我们直接去看它的实现类,

FragmentManangerImpl.java
    @NonNull
    @Override
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

我们看到它的实现类还不是这里,而是new 了 BackStackRecord 并传递了一个FragmentManager 对象,来看看这个类是个什么情况

BackStackRecord.java
/**
 * 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;

    boolean mCommitted;
    int mIndex = -1;

也就是说这个 BackStackRecord 就是 Fragment 回退栈中的一个元素,每个元素也可以理解成一个事务,因为它继承了 FragmentTransaction,这个设计的目的是为了操作回退栈的时候能逆向执行事务,从而实现 Fragment 的出栈操作.

不过我们并没有看到生命周期和添加veiw相关的东西,
接着往下看就到了add(),replace(),remove() 这些操作,这里面又发生了写什么?

add()

FragmentTransaction.java
    /**
     * Calls {@link #add(int, Fragment, String)} with a null tag.
     */
    @NonNull
    public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }

看到调用了 doAddOp(containerViewId, fragment, null, OP_ADD) 方法,这里的 Op 就是 operation(操作)的意思,最后一个参数 OP_ADD ,说明是一个添加的操作,跟进一些这个方法

FragmentTransaction.java
    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        final Class<?> fragmentClass = fragment.getClass();
        final int modifiers = fragmentClass.getModifiers();
        if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers){...}

        if (tag != null) {...}
        if (containerViewId != 0) {...}

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

上面是一些异常的判断,最下面有一个 addOp(new Op(opcmd, fragment)) 方法,它把 opcmd(就是上面的 OP_ADD 和 fragment 封装成了一个 Op 对象.跟进 addOp 方法

FragmentTransaction.java
    void addOp(Op op) {
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }

mOps 是一个集合,然后把 op 添加到了这个集合里面,为什么这么做呢?因为一次事务里面可能会有多个操作,所以要存储起来,等待事务执行的时候统一执行.下面也就没有什么了,继续看下一个方法

replace()

FragmentTransaction.java
    /**
     * Calls {@link #replace(int, Fragment, String)} with a null tag.
     */
    @NonNull
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }

嗯...调用了内部的 replace ,继续看

FragmentTransaction.java
    @NonNull
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
            @Nullable String tag)  {
        if (containerViewId == 0) {
            throw new IllegalArgumentException("Must use non-zero containerViewId");
        }
        doAddOp(containerViewId, fragment, tag, OP_REPLACE);
        return this;
    }

可以看到也调用了 doAddOp(),只不过最后一个参数变成了 OP_REPLACE.后面就跟 add() 方法一样了.好,我们继续下一个方法 remove();

remove()

FragmentTransaction.java
    @NonNull
    public FragmentTransaction remove(@NonNull Fragment fragment) {
        addOp(new Op(OP_REMOVE, fragment));

        return this;
    }

可以看到,这里就直接调用了 addOp() 方法,创建了一个 Op 对象,并传递了一个 OP_REMOVE

总结一下:这些操作仅仅是 opcmd 参数不同,最后都是调用了 addOp() 方法,把本次操作存储到了一个合集当中,这种设计方法叫做方法的收拢,有利于最后一道的统一封装和处理
不过呢,还是没有看到生命周期和添加view

这里只是大致的说了一下,这里面还有好多的东西,比如 BackStackRecord ,有待研究吧...

刚开始的那段代码还剩一个 commit() 我们没有看了,点击去看一下.这个方法呢,是FragmentTransaction 里的一个抽象方法,不知道是否还记得 BackStackRecord 这个类,上面提到过的它继承了 FragmentTransaction,是 FragmentManager 执行操作的事务单元,一次 commit 就会产生一个 BackStackRecord 记录,而在一个 BackStackRecord 记录中有一个 OP 列表。而 commit() 方法的实现正是在 BackStackRecord 里面,
我们看一下.

BackStackRecord.java
    @Override
    public int commit() {
        return commitInternal(false);
    }

这里面只有一个 commitInternal(false) 方法,这个参数它的作用是当一个事务真正开始执行之前是否对宿主状态进行检查,而 false 是检查,我们继续跟进.

BackStackRecord.java
    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) {...}
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

开始是一些判断,allocBackStackIndex() 这个方法是为BackstackRecorder也即FragmentTransaction分配一个index,这里就不细说了,最后面发现调用了 mManager.enqueueAction(this, allowStateLoss); 方法,把刚才的那个参数传了过去,继续跟进.

FragmentManagerImp.java
    /**
     * 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();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {...}
            if (mPendingActions == null) {...}
            mPendingActions.add(action);
            scheduleCommit();
        }
    }

可以看到第一个判断,用到了上面说到的那个参数,里面的实现也是一目了然,就不贴代码了,最后看是否调用了 activity 的 onSaveinstance 和 是否处于 onStop 状态,这里也就是避免当 activity 要销毁或者回收的时候去调用了 fragment 的操作,有兴趣的可以自己看一下.而这个方法的描述我们看到是,添加一个事务(也就是一个上面提到的BackStackRecord )到 pending actiion(一个存放runnable的集合) 队列中去,我们来看一下最后两句话,它把传递过来的事务添加到了一条等待队列中去.原因是这里的 commit() 是属于异步事务,然后执行了 scheduleCommit();

这里插小知识点
FragmentTransaction的4中提交方式
*commit(); 如果在宿主执行了 onSaveInstanceState 之后再执行该操作,会抛出异常.属于异步事务.
*commitAllowingStateLoss(); 如果再宿主执行了 onSaveInstanceState() 之后再执行该操作,不会去检查宿主状态,不会抛出异常,但该操作不会被
activity 记录,恢复时也就没办法恢复这些提交的操作,所以该操着使用不重要的事务,同属于异步事务.
*commitNow(); 会立刻执行当前提交的 transaction 事务,属于同步事务
*commitNowAllowingStateLoss(); 具备以上两者的特性,即使同步执行,也不会检查宿主的状态,有可能该操着不会被正确恢复.

上面说到执行了scheduleCommit(),继续跟进.

FragmentManagerImp.java
    /**
     * Schedules the execution when one hasn't been scheduled already. This should happen
     * the first time {@link #enqueueAction(OpGenerator, boolean)} is called or when
     * a postponed transaction has been started with
     * {@link Fragment#startPostponedEnterTransition()}
     */
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    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);
                updateOnBackPressedCallbackEnabled();
            }
        }
    }

根据方法名和注释可以看到要开始执行队列中的事务了,而我们正好也看到了mHost.getHandler().post(mExecCommit);它像主线程息队列 psot 了一条消息,当主线程轮询到了这条消息才会执行这个事务,当消息被轮询到的时候就是执行 run 方法,来看一下 Runnable mExecCommit

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

可以看到只执行了一个方法,execPendingActions();顾名思义,执行等待队列中的事务,跟进一下这个方法

FragmentManagerImp.java
    /**
     * 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;
        }

        updateOnBackPressedCallbackEnabled();
        doPendingDeferredStart();
        burpActive();

        return didSomething;
    }
FragmentManagerImp.java
    /**
     * Broken out from exec*, this prepares for gathering and executing operations.
     *
     * @param allowStateLoss true if state loss should be ignored or false if it should be
     *                       checked.
     */
    private void ensureExecReady(boolean allowStateLoss) {
        if (mExecutingActions) {
            throw new IllegalStateException("FragmentManager is already executing transactions");
        }

        if (mHost == null) {
            throw new IllegalStateException("Fragment host has been destroyed");
        }

        if (Looper.myLooper() != mHost.getHandler().getLooper()) {
            throw new IllegalStateException("Must be called from main thread of fragment host");
        }

        if (!allowStateLoss) {
            checkStateLoss();
        }

        if (mTmpRecords == null) {
            mTmpRecords = new ArrayList<>();
            mTmpIsPop = new ArrayList<>();
        }
        mExecutingActions = true;
        try {
            executePostponedTransaction(null, null);
        } finally {
            mExecutingActions = false;
        }
    }

首先是一个 ensureExecReady(true) 判断,这个方法里面会对 mExecutingActions 进行判断,如果是 false 就会抛出 FragmentManager is already executing transactions 这个异常,并且判断完成之后 mExecutingActions = true;
每次新提交的事务都会调用到execPendingActions()这个方法,在同一个FragmentManager中,如果第一个commit事务没有执行完毕,
就又提交一个新事务那么就会判断mExecutingActions 这个变量,mExecutingActions 为true代表还有未处理完毕的事务,
那么下个事务提交时mExecutingActions 为true就会抛出传说中的"FragmentManager is already executing transactions"异常
接下来是一个 while 循环,

generateOpsForPendingActions(mTmpRecords, mTmpIsPop) 这个方法它有两个作用,
1.刚刚添加到等待队列中的事务,添加到 mTmpRecords 的集合中,
2.记录本次操作时入栈操作还是出栈操作,把这个布尔值添加到mTmpIsPop 的集合中

进入 while 循环之后就会执行 removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop) 方法,

removeRedundantOperationsAndExecute 这个方法也有两个作用
1.去掉每个事务中的冗余操作,比如先添加,后移除.
2.执行剩下的事务

我们来看看是如何执行的,

FragmentManagerImp.java
/**
     * Executes a subset of a list of BackStackRecords, all of which either allow reordering or
     * do not allow ordering.
*/
    private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
                                                     ArrayList<Boolean> isRecordPop) {
        .........
        省略部分代码
        .........
        for (int recordNum = 0; recordNum < numRecords; recordNum++) {
            final boolean canReorder = records.get(recordNum).mReorderingAllowed;
            if (!canReorder) {
                // execute all previous transactions
                if (startIndex != recordNum) {
                    executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                }
                // execute all pop operations that don't allow reordering together or
                // one add operation
                int reorderingEnd = recordNum + 1;
                if (isRecordPop.get(recordNum)) {
                    while (reorderingEnd < numRecords
                            && isRecordPop.get(reorderingEnd)
                            && !records.get(reorderingEnd).mReorderingAllowed) {
                        reorderingEnd++;
                    }
                }
                executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
                startIndex = reorderingEnd;
                recordNum = reorderingEnd - 1;
            }
        }
        if (startIndex != numRecords) {
            executeOpsTogether(records, isRecordPop, startIndex, numRecords);
        }
    }

上面的代码与我们的问题无关,不搭理他,看这个 for 循环,对传递进来的 records 里面的事务进行一个遍历,解释一下 canReorder 这个参数的作用.

    final boolean canReorder = records.get(recordNum).mReorderingAllowed;
    看下 mReorderingAllowed 的解释是什么.
    /*
     * For example, if two transactions are executed
     * together, one that adds a fragment A and the next replaces it with fragment B,
     * the operations will cancel and only fragment B will be added. That means that
     * fragment A may not go through the creation/destruction lifecycle.
     * @param reorderingAllowed {@code true} to enable optimizing out redundant operations
     *                          or {@code false} to disable optimizing out redundant
     *                          operations on this transaction.
     */
    @NonNull
    public FragmentTransaction setReorderingAllowed(boolean reorderingAllowed) {
        mReorderingAllowed = reorderingAllowed;
        return this;
    }
  
有点多,大致取了一下
参数的解释,是否对一条事务中重复的冗余的操作进行优化,默认值是 false,也明白了为什么 if (!canReorder) 取了个非
再来看看这个方法的介绍,
两条事务一起执行,其中一个添加了一个 fragment A , 另一个用 fragment B去替换了它,那么这个添加 A 的操作会被取消,仅仅只有将 Fragment B 
的这个操作会被执行,与此同时 fragment A 的生命周期也就不会被执行,

然后调用 executeOpsTogether 依次去执行事务里面的所有操作.

这里留个疑问,if (startIndex != recordNum) 是什么作用,导致executeOpsTogether 这个方法写了三遍?

我们来看看 executeOpsTogether 是怎么执行的吧,既然是执行事务,找了一下,发现了 FragmentTransition.startTransitions 就是它了

FragmentManagerImpl.java
    private void executeOpsTogether(ArrayList<BackStackRecord> records,
                                    ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
         .........
        省略部分代码
        .........

        if (!allowReordering) {
            FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                    false);
        }
         .........
        省略部分代码
        .........
    }

继续跟进一下

FragmentTransition.java 
 static void startTransitions(FragmentManagerImpl fragmentManager,
            ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
            int startIndex, int endIndex, boolean isReordered) {
      .....
      .....
        for (int i = startIndex; i < endIndex; i++) {
            final BackStackRecord record = records.get(i);
            final boolean isPop = isRecordPop.get(i);
            if (isPop) {
                calculatePopFragments(record, transitioningFragments, isReordered);
            } else {
                calculateFragments(record, transitioningFragments, isReordered);
            }
        }
      .....
      .....
    }

它对传进来的事务集合 records 进行了一个遍历,遍历的同时会取出本次的操作是不是一个出栈的操作,这里我们写的是一个入栈的操作,
所以我们点击 calculateFragments(record, transitioningFragments, isReordered); 里面看看.

FragmentTransition.Java
    public static void calculateFragments(BackStackRecord transaction,
            SparseArray<FragmentContainerTransition> transitioningFragments,
            boolean isReordered) {
        final int numOps = transaction.mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final BackStackRecord.Op op = transaction.mOps.get(opNum);
            addToFirstInLastOut(transaction, op, transitioningFragments, false, isReordered);
        }
    }

这个方法的作用就是把我们本次事务里面的操作拿出来依次去执行,可以看到执行的时候调用了
addToFirstInLastOut(transaction, op, transitioningFragments, false, isReordered);好的,点进去看一下.

FragmentTransition.Java
 private static void addToFirstInLastOut(BackStackRecord transaction, BackStackRecord.Op op, SparseArray<FragmentContainerTransition> transitioningFragments, boolean isPop,
          boolean isReorderedTransaction) {
  ........
            /*
             * Ensure that fragments that are entering are at least at the CREATED state
             * so that they may load Transitions using TransitionInflater.
             */
            FragmentManagerImpl manager = transaction.mManager;
            if (fragment.mState < Fragment.CREATED && manager.mCurState >= Fragment.CREATED
                    && !transaction.mReorderingAllowed) {
                manager.makeActive(fragment);
                manager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
            }
  ........
  }

这个方法也有两个作用
1.计算这个事务 (transaction) 当中所有的操作它对应的是添加还是删除还是隐藏等等,然后把它们添加到 transitioningFragments 这个集合当中等待执行
2.对传递过来的这个 op 操作,对应的 fragment 逐一执行它们的生命周期.也就是 manager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
来看看这个方法是怎么执行的吧.
注意一下这里的参数,有一个 Fragment.CREATED,点一下可以看到有这么几种状态.

Fragment.java
    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // Fully created, not started.
    static final int STARTED = 3;          // Created and started, not resumed.
    static final int RESUMED = 4;          // Created started and resumed.

好,回到 moveToState

FragmentManagerImpl.java
    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                     boolean keepActive) {
     ......
        if (f.mState <= newState) {
           .....
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {

                    ......
    
                        f.performAttach();
                        if (f.mParentFragment == null) {
                            mHost.onAttachFragment(f);
                        } else {
                            f.mParentFragment.onAttachFragment(f);
                        }
                        dispatchOnFragmentAttached(f, mHost.getContext(), false);

                        if (!f.mIsCreated) {
                            dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                            f.performCreate(f.mSavedFragmentState);
                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                        } else {
                            f.restoreChildFragmentState(f.mSavedFragmentState);
                            f.mState = Fragment.CREATED;
                        }
                    }
                    // fall through
                case Fragment.CREATED:
                    // We want to unconditionally run this anytime we do a moveToState that
                    // moves the Fragment above INITIALIZING, including cases such as when
                    // we move from CREATED => CREATED as part of the case fall through above.
                    if (newState > Fragment.INITIALIZING) {
                        ensureInflatedFragmentView(f);
                    }
                 .....
    }

看这句话 if (f.mState <= newState) ,判断当前的生命周期的状态是不是小于它期望到达的那个生命周期的状态,
在下面的 switch 里面会对fragment当前的生命周期进行一个判断,第一个 case Fragment.INITIALIZING:
fragment 默认的生命周期状态时 init,所以默认就会进入第一个 case,我们看的是生命周期,所以找一下跟生命周期有关的,
f.performAttach(); 发现这个东西,点进去看了一下,果然调用了 fragment 的 onAttach(mHost.getContext()); 方法,这也就是 onAttach 生命周期了.

Fragment.java
void performAttach() {
        mChildFragmentManager.attachController(mHost, new FragmentContainer() {
        ......
        onAttach(mHost.getContext());
        ......
    }

回到 moveToState ,继续往下看, f (!f.mIsCreated) {.....}
判断了一下 fragment 是否被创建,点击 f.performCreate(f.mSavedFragmentState);

Fragment.java
    void performCreate(Bundle savedInstanceState) {
        mChildFragmentManager.noteStateNotSaved();
        mState = CREATED;
        mCalled = false;
        mSavedStateRegistryController.performRestore(savedInstanceState);
        onCreate(savedInstanceState);
        mIsCreated = true;
      ......
    }

里面的确发现了 fragment 的 onCreate(savedInstanceState);方法
并且把state 设置成了 created, mState = CREATED;

继续回到 moveToState switch 我们发现这个switch 里面是没有 break 的,好,进行下一个,看这个方法 ensureInflatedFragmentView(f); 点进去,哎? 找到了 f.performCreateView

FragmentManagerImpl.java
    void ensureInflatedFragmentView(Fragment f) {
        if (f.mFromLayout && !f.mPerformedCreateView) {
            f.performCreateView(f.performGetLayoutInflater(
                    f.mSavedFragmentState), null, f.mSavedFragmentState);
......
        }
    }

跟进一下

Fragment.java
 void performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
......
        mView = onCreateView(inflater, container, savedInstanceState);
......
    }

看到了这个 onCreateView 方法, mView = onCreateView(inflater, container, savedInstanceState);
再跟进一下

Fragment.java
    @Nullable
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        if (mContentLayoutId != 0) {
            return inflater.inflate(mContentLayoutId, container, false);
        }
        return null;
    }

if (mContentLayoutId != 0) {
return inflater.inflate(mContentLayoutId, container, false);
}
可以看到,它把传递过来的view 添加到了容器上面去了
实际上无论是因为事务的执行,从而去更改 fragment 生命周期的状态,还是因为 activity 状态的改变从而去更改 fragment 生命周期的状态,
最后都会去执行 moveToState 方法,来变动 fragment 生命周期的状态.

4.还有个问题,Fragment 是如何在宿主销毁的时候进行存储,又如何在宿主恢复的时候进行恢复的?

对于activity 而言,因为系统内存不足导致页面被回收,或者因为屏幕旋转导致页面被销毁,会执行 onSaveInstanceState 这个方法,
因为跟 fragment 有关,我们进到 FragmentActivisty 中看看,在这里可以看到有一个 mFragments.saveAllState() 方法,

FragmentActivity.java
    /**
     * Save all appropriate fragment state.
     */
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
    ......
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
   ......
    }

我们知道这个 mFragments 就是 FragmentController,点进这个方法发现它转发给了 FragmentManager

FragmentController.java
   @Nullable
    public Parcelable saveAllState() {
        return mHost.mFragmentManager.saveAllState();
    }

继续跟进一下
看看 Parcelable saveAllState() 这个方法的实现,实际上它在存储数据和保存状态的时候是把 fragment 所有的状态,所有的数据分装成了一个
FragmentManagerState 对象,
active 记录了当前页面正处于活跃正处于活跃状态下的 fragment 集合,
added 记录了所有当前已经被添加但是有可能不被显示的 fragment 集合,
backStack 记录了 fragment 的回退堆栈
这些封装成了 FragmentManagerState 对象,而 FragmentManagerState 实现了 Parcelable 接口,所以才能在 onSaveInstanceState 当中以 parcelable 的形式存入 Bundle 对象当中,也就是上面的 outState.putParcelable(FRAGMENTS_TAG, p);

FragmentManagerImpl.java
    Parcelable saveAllState() {
......

        FragmentManagerState fms = new FragmentManagerState();
        fms.mActive = active;
        fms.mAdded = added;
        fms.mBackStack = backStack;
......
    }

Fragment 的恢复是在 FragmentActivity 的 onCreate 当中,首先判断 savedInstanceState 是否为空,如果不为空说明 activity 的重建是因为系统的原因被销毁了,
然后进行了存储,恢复的时候又把这个数据给传递进来了,然后通过 FRAGEMNT_TAG 这个 key 获取 Parcelable 对象,

FragmentActivity.java
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);

        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreSaveState(p);
         .....
           }
      .....
    }

然后调用 mFragments.restoreSaveState(p); 这个方法
跟进一下,它由委托给了 FragmentMananger

FragmentController.java
    public void restoreSaveState(@Nullable Parcelable state) {
......
        mHost.mFragmentManager.restoreSaveState(state);
    }

继续跟进一下
这里把 Parceable 对象直接转换成了 FragmentManagerState 对象,上面提到,发生状态存储的时候,把 FragmentManager 中的数据封装成了
FragmentMangerState 对象,所以恢复的时候可以进行强转,下面的这一顿操作就是把之前存储的数据在逆向读取出来,然后更新各个 Fragment 对象,太长了就省略一下吧.

FragmentMawnagerImpl.java
  void restoreSaveState(Parcelable state) {
        // If there is no saved state at all, then there's nothing else to do
        if (state == null) return;
        FragmentManagerState fms = (FragmentManagerState)state;
     ......
     ......
    }

这里面是恢复数据,并没有发现恢复 Fragment 生命周期,在回到 FragmentActivity 中的 onCreate 方法当中,来到最后我们看到 mFragments.dispatchCreate();
点进去看一下,发现mHost.mFragmentManager.dispatchCreate();

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

继续点击去, dispatchStateChange(Fragment.CREATED); 参数 nextState 传递了一个 CREATE,

FragmentManagerImpl.java
    public void dispatchCreate() {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.CREATED);
    }

跟进,
我们看到它接着调用了 moveToState(nextState, false); 当然,跟上面的 moveToState 不是一个方法

FragmentManagerImpl.java
    private void dispatchStateChange(int nextState) {
.....
            moveToState(nextState, false);
......
    }

在 moveToState 这里它遍历了之前添加到屏幕上的 Fragment 的集合,然后调用 moveFragmentToExpectedState(f);
把这些 Fragment 的生命周期都更新到正确的状态.

FragmentManagerImpl.java
 void moveToState(int newState, boolean always) {
        if (mHost == null && newState != Fragment.INITIALIZING) {
.....
        for (int i = 0; i < numAdded; i++) {
            Fragment f = mAdded.get(i);
            moveFragmentToExpectedState(f);
        }

        // Now iterate through all active fragments. These will include those that are removed
        // and detached.
        for (Fragment f : mActive.values()) {
            if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                moveFragmentToExpectedState(f);
            }
        }
......
    }

在 moveFragmentToExpectedState 里面我们看到了我们熟悉的 moveToState

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

推荐阅读更多精彩内容