带你从源码理解Fragment机制

作者: Anderson大码渣 | 来源:发表于2018-05-20 22:34 被阅读296次

    相信大家平时用到很多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

    相关文章

      网友评论

      • 蒲导:看完整个过程还是略显生硬,可能是真的有点复杂吧

      本文标题:带你从源码理解Fragment机制

      本文链接:https://www.haomeiwen.com/subject/nclxjftx.html