Fragment源码分析

版权声明:本文为博主原创文章,转载请标明出处,谢谢 https://blog.csdn.net/shensky711/article/details/53171248

转载请标明出处:http://blog.csdn.net/shensky711/article/details/53171248
本文出自: 【HansChen的博客】

概述

Fragment表示 Activity 中的行为或用户界面部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个 Fragment。您可以将 Fragment 视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除 Fragment。
Fragment 必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有 Fragment 也会暂停;当 Activity 被销毁时,所有 Fragment 也会被销毁。 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个 Fragment,如添加或移除它们。 当您执行此类 Fragment 事务时,您也可以将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生 Fragment 事务的记录。 返回栈让用户可以通过按返回按钮撤消 Fragment 事务(后退)。

当您将 Fragment 作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且 Fragment 会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明Fragment,将其作为 <fragment> 元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,Fragment 并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的 Fragment 用作 Activity 的不可见工作线程。

本文将通过分析源码,对 Fragment 的创建、销毁以及生命周期做一个更深入的认识。

建议读者在看这篇文章的时候,先看下Fragment事务管理源码分析,对Fragment管理类先有一个比较清楚的认识。

分析入口

    /**
     * 构造并显示Fragment
     *
     * @param containerViewId 容器控件id
     * @param clz             Fragment类
     */
    protected void showFragment(@IdRes int containerViewId, Class<? extends Fragment> clz) {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();//开始事务管理
        try {
            Fragment f = clz.newInstance();
            ft.add(containerViewId, f, clz.getName());//添加操作
            ft.commit();//提交事务
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

上面的代码就是动态地往containerViewId里添加一个Fragment并让它显示出来,可以看到,这个涉及到Fragment的事务管理,详细可以参考Fragment事务管理源码分析,这里就不再阐述了。

代码分析

BackStackRecord#run

调用了commit之后,真正执行的地方是在BackStackRecord的run方法:

    public void run() {

        ......

        if (mManager.mCurState >= Fragment.CREATED) {
            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
            calculateFragments(firstOutFragments, lastInFragments);
            beginTransition(firstOutFragments, lastInFragments, false);
        }
        //遍历链表,根据cmd事务类型依次处理事务
        Op op = mHead;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
                    //添加一个新的Fragment
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                }
                break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    if (mManager.mAdded != null) {
                        for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
                            Fragment old = mManager.mAdded.get(i);
                            if (old.mContainerId == containerId) {
                                if (old == f) {
                                    op.fragment = f = null;
                                } else {
                                    if (op.removed == null) {
                                        op.removed = new ArrayList<Fragment>();
                                    }
                                    op.removed.add(old);
                                    old.mNextAnim = op.exitAnim;
                                    if (mAddToBackStack) {
                                        old.mBackStackNesting += 1;
                                    }
                                    mManager.removeFragment(old, mTransition, mTransitionStyle);
                                }
                            }
                        }
                    }
                    if (f != null) {
                        f.mNextAnim = op.enterAnim;
                        mManager.addFragment(f, false);
                    }
                }
                break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.exitAnim;
                    mManager.removeFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.exitAnim;
                    mManager.hideFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.showFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_DETACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.exitAnim;
                    mManager.detachFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.attachFragment(f, mTransition, mTransitionStyle);
                }
                break;
                default: {
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                }
            }

            op = op.next;
        }

        mManager.moveToState(mManager.mCurState, mTransition,
                mTransitionStyle, true);

        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }

因为我们调用的是add操作,所以执行的代码片段是:

    case OP_ADD: {
        Fragment f = op.fragment;
        f.mNextAnim = op.enterAnim;
        mManager.addFragment(f, false);
    }
    break;

参数解释:

  • op.fragment:showFragment中创建的Fragment实例,并且现在Fragment的mTag、mFragmentId、mContainerId已被初始化过了
  • op.enterAnim:入场动画,可以先不管
  • mManager:FragmentManagerImpl实例

FragmentManagerImpl#addFragment

    public void addFragment(Fragment fragment, boolean moveToStateNow) {
        //已添加的Fragment列表
        if (mAdded == null) {
            mAdded = new ArrayList<Fragment>();
        }

        //设置Fragment的mIndex,并把Fragment添加到mActive列表
        makeActive(fragment);

        //判断是否被detach。默认为false
        if (!fragment.mDetached) {
            if (mAdded.contains(fragment)) {
                throw new IllegalStateException("Fragment already added: " + fragment);
            }
            //把Fragment添加到mAdded列表
            mAdded.add(fragment);
            //设置Fragment标记位
            fragment.mAdded = true;
            fragment.mRemoving = false;
            //判断是否需要刷新菜单
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            //在这次分析中moveToStateNow为false,moveToState方法在本方法外层方法中调用
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }

addFragment里面把Fragment加入mActive和mAdded列表,并且设置标记为fragment.mAdded为true,fragment.mRemoving为false。
执行完ADD操作后,执行moveToState,moveToState顾名思义,就是把Fragment变为某种状态

    //mManager.mCurState的状态很重要,我们下面会分析它现在处于什么状态
    mManager.moveToState(mManager.mCurState, mTransition,
            mTransitionStyle, true);

    //添加本次操作到回退栈中
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }

Fragment状态

我们知道Fragment的生命周期是依赖于Activity的,比如Activity处于onResume,那么Fragment也会处于onResume状态,这里的参数mManager.mCurState对应的状态有:

    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.

mCurState的初始状态是Fragment.INITIALIZING,那么在BackStackRecord中调用moveToState的时候,mCurState是什么值呢?它是会受Activity生命周期影响而变化的,我们来看下FragmentActivity的代码

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        //绑定FragmentManager
        mFragments.attachHost(null /*parent*/);

        super.onCreate(savedInstanceState);
        ... ...

        //分发Fragment的create事件
        mFragments.dispatchCreate();
    }
    public void dispatchCreate() {
        mHost.mFragmentManager.dispatchCreate();
    }

    public void dispatchCreate() {
        mStateSaved = false;
        //注意这里设置了新的state
        moveToState(Fragment.CREATED, false);
    }

    void moveToState(int newState, boolean always) {
        moveToState(newState, 0, 0, always);
    }

    void moveToState(int newState, int transit, int transitStyle, boolean always) {

        ... ...
        //给mCurState赋值
        mCurState = newState;
        ... ...
    }

在onCreate中把mCurState变为Fragment.CREATED状态了,Activity的其他生命周期方法回调的时候,也会改变这个状态,大致整理如下:

  • onCreate:Fragment.CREATED
  • onStart:Fragment.ACTIVITY_CREATED–>Fragment.STARTED (Fragment.ACTIVITY_CREATED只会在Activity创建之后触发一次,Fragment.STARTED每次onStart的时候都会触发)
  • onResume:Fragment.RESUMED
  • onPause:Fragment.STARTED
  • onStop:Fragment.STOPPED
  • onDestroy:Fragment.INITIALIZING

下面是一张状态迁移图:
这里写图片描述

所以随着Activity生命周期的推进,Activity内所有Fragment的生命周期也会跟着推进。从Activity创建到显示出来,最后会处于onResume状态,那么我们这次就直接分析当前Activity处于onResume调用之后的情形好了。所以假定现在mCurState为Fragment.RESUMED

让我们继续跟踪FragmentManagerImpl

FragmentManagerImpl#moveToState

    void moveToState(int newState, int transit, int transitStyle, boolean always) {
        if (mHost == null && newState != Fragment.INITIALIZING) {
            throw new IllegalStateException("No activity");
        }

        if (!always && mCurState == newState) {
            return;
        }

        mCurState = newState;
        if (mActive != null) {
            boolean loadersRunning = false;
            //遍历所有Active状态的Fragment,改变所有Fragment的状态
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null) {
                    //关键代码
                    moveToState(f, newState, transit, transitStyle, false);
                    if (f.mLoaderManager != null) {
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                    }
                }
            }

            if (!loadersRunning) {
                startPendingDeferredFragments();
            }

            //让Activity刷新Menu
            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
                mHost.onInvalidateOptionsMenu();
                mNeedMenuInvalidate = false;
            }
        }
    }

设置最新的mCurState状态,通过上面的分析,我们知道newState等于Fragment.RESUMED。遍历mActive列表中保存的Fragment,改变Fragment状态,这里又调用了一个moveToState方法,这个方法就是真正回调Fragment生命周期的地方

    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {

        // Fragments被detach或Fragment没有添加到mAdded列表的话,设置目标Fragment的新状态为CREATED状态,此次分析中不会进入这个分支
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
        //此次分析中f.mRemoving为false
        if (f.mRemoving && newState > f.mState) {
            // While removing a fragment, we can't change it to a higher state.
            newState = f.mState;
        }
        // 是否延时启动
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
            newState = Fragment.STOPPED;
        }

        if (f.mState < newState) {
            //此次命中的分支
            ......

            //根据Fragment当前的状态,选择case的分支。需要注意的是,这里的switch case是没有break语句的。这种设计可以让Fragment把自身的状态依次推进到目标状态
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (f.mSavedFragmentState != null) {
                        ......
                    }
                    f.mHost = mHost;
                    //mParent是在FragmentActivity的onCreate方法中调用attachHost传进来的,传进来的是空值
                    f.mParentFragment = mParent;
                    f.mFragmentManager = mParent != null
                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
                    f.mCalled = false;
                    //【Fragment生命周期】onAttach回调,里面会把mCalled设置为true
                    f.onAttach(mHost.getContext());
                    if (!f.mCalled) {
                        throw new SuperNotCalledException("Fragment " + f
                                + " did not call through to super.onAttach()");
                    }

                    if (f.mParentFragment == null) {
                        //让Activity可以监听到Fragment的attach
                        mHost.onAttachFragment(f);
                    } else {
                        f.mParentFragment.onAttachFragment(f);
                    }

                    //f.mRetaining默认为false
                    if (!f.mRetaining) {
                        //关键代码,内部会调用【Fragment生命周期】onCreate
                        f.performCreate(f.mSavedFragmentState);
                    } else {
                        f.restoreChildFragmentState(f.mSavedFragmentState, true);
                        f.mState = Fragment.CREATED;
                    }
                    f.mRetaining = false;

                    //Fragment是否定义在Layout文件的<fragment>标签中的,本次栗子为代码动态添加Fragment,所以为false
                    if (f.mFromLayout) {
                        // For fragments that are part of the content view
                        // layout, we need to instantiate the view immediately
                        // and the inflater will take care of adding it.
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mView.setSaveFromParentEnabled(false);
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }
                    //注意,这里没有break
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        if (!f.mFromLayout) {
                            //开始创建Fragment的view
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(""));
                                }

                                //调用Activity的findViewById方法查找控件
                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    ......
                                }
                            }
                            f.mContainer = container;
                            //关键代码,内部会调用【Fragment生命周期】onCreateView,并返回Fragment中new出的视图
                            f.mView = f.performCreateView(f.getLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    //设置入场动画
                                    Animator anim = loadAnimator(f, transit, true,
                                            transitionStyle);
                                    if (anim != null) {
                                        anim.setTarget(f.mView);
                                        setHWLayerAnimListenerIfAlpha(f.mView, anim);
                                        anim.start();
                                    }
                                    //把Fragment的view加入到父控件
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) f.mView.setVisibility(View.GONE);

                                //【Fragment生命周期】onViewCreated回调
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                            }
                        }

                        //关键代码,内部会调用【Fragment生命周期】onActivityCreated
                        f.performActivityCreated(f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        f.mState = Fragment.STOPPED;
                    }
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        //关键代码,内部会调用【Fragment生命周期】onStart
                        f.performStart();
                    }
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        //关键代码,内部会调用【Fragment生命周期】onResume
                        f.performResume();
                        // Get rid of this in case we saved it and never needed it.
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            //state降级处理
            ......
        }

        if (f.mState != newState) {
            f.mState = newState;
        }
    }

这段代码逻辑还是比较长,我把注释写在代码里了。可以看到,这个代码写得很巧妙,通过switch case控制,可以一层一层地把Fragment的生命周期推进下去,比如当前fragnemt的state是Fragment.STARTED,那么它就只会执行performResume,如果Fragment的状态是Fragment.INITIALIZING,那么就会从switch的最开始依次执行下来,把Fragment的生命周期onAttach–>onResume依次调用。
简要说明下上面的代码:

  • mHost是FragmentHostCallback抽象类的实例,它的实现类是Activity的HostCallbacks
  • mParent为null
  • mHost.getContext()获取的context就是宿主Activity实例
  • Fragment中创建的View会自动通过container.addView(f.mView)添加到父控件中

很多Fragment的生命周期是通过Fragment的performXxx()方法去调用的,比如:

    void performCreate(Bundle savedInstanceState) {
        ......
        onCreate(savedInstanceState);
        ......
    }

    View performCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        ......
        return onCreateView(inflater, container, savedInstanceState);
    }

    void performActivityCreated(Bundle savedInstanceState) {
        ......
        onActivityCreated(savedInstanceState);
        ......
    }

    void performStart() {
        ......
        onStart();
        ......
    }

    void performResume() {
        ......
        onResume();
        ......
    }

Fragment状态的降级操作

有些童鞋们可能会有疑问,上面只分析到了onAttach->onResume生命周期的回调,那onPause、onDestroy等方法又是什么时候执行的呢?我们再看下刚才的代码

    if (f.mState < newState) {
        ......
    } else if (f.mState > newState) {
        //state降级处理
        ......
    }

答案就是在else if分支里面,比如当Acivity锁屏的时候,就Activity生命周期会自动回调onPause,从而触发dispatchPause,在里面调用moveToState(Fragment.STARTED, false);
由于Fragment当前的状态是RESUMED状态,大于newState,所以就会走else if的分支,触发相应的生命周期方法。else if分支的逻辑和state升级的差不多,这里就再进行分析了

生命周期

这里写图片描述
最后,放张官网上公布的Fragment生命周期图,通过代码分析,我们发现代码的中生命周期的调用顺序和图中确实是一致的

总结

本文大致地从源码的角度分析了Fragment创建、生命周期回调的过程,如果读者对Fragment的removereplacehidedetachattach等操作有兴趣的话,可以自行分析,核心代码主要在BackStackRecord类的run方法以及FragmentManagerImpl的moveToState方法中。

阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页