Fragment运行机制源码分析(一)

来源:互联网 发布:linux关闭22端口 编辑:程序博客网 时间:2024/05/16 03:15

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/52822315


Fragment是Android3.0中推出的,目的是方便屏幕适配,虽然推出时间比较早,但是由于Fragment本身存在着各种Bug,并且使用起来比Activity复杂得多,所以真正掌握Fragment运行机制的同学并不多。在网上经常可以看到开发者对Fragment各种吐槽,认为在App中根本没有必要使用Fragment,因为使用View也可以完成Fragment的一样的功能,对于这种说法也不完全错,我们公司也是因为Fragment存在各种bug,从而自己写了一套类似Fragment机制的框架,并且使用起来非常简单,有bug自己也非常容易修复。但是我个人认为毕竟Fragment是google提供的,并会长期维护,所以相信以后Fragment会越来越稳定,所以我们还是有必要理解Fragment的运行机制,从而当我们使用过程中出现Bug时,我们有办法进行处理。由于Fragment是在3.0系统引入,所以对于2.x系统,如果想使用Fragment,那么需要依赖support_v4包,对于不同版本的support_v4包源码并不一样(support_v4包的源码和系统中Fragment的源码也不一定一样),本系列文章使用的support_v4版本是23.2.1.

简单介绍本系列文章目录:

  1. Fragmeng生命周期
  2. Fragment和Activity生命周期如何联动
  3. FragmentTransaction的add,replace,remove,show,hide等操作都做了什么
  4. Fragment的销毁和重建机制
  5. addToBackStack系列方法和popBackStack系列方法源码解析
  6. 无UI Fragment的使用
  7. Fragment动画机制分析

Fragment生命周期

以上内容就是本系列文章会详细介绍的,那么我们先来看看Fragment的生命周期,在具体介绍生命周期之前,我们看看官方给出的生命周期图:
这里写图片描述

从上图可以看出Fragment的生命周期和Activity的生命周期极其类似,只不过生命周期分得更加细致,例如当Activity的生命周期进入onCreate阶段时,那么该Activty中的Fragment中的onAttach,onCreate,onCreateView,onActivityCreated等方法均会被调用。不同的是,Activity的生命周期是被Android系统(严格说是AMS)管理,Fragment的生命周期是被所属Activity管理。那么Activity是如何管理Fragment的生命周期呢?他们的生命周期是如何联动起来的呢?下面我就来为您解答这两个问题。

Fragment和Activity生命周期联动机制

同样在介绍Activity如何管理Fragment生命周期之前,我们先来看一个类图。
这里写图片描述

从这种图里面我们可以获取一下信息:

  • 如果要使用Fragment,那么你的Activity需要继承FragmentActivity(本系列文章讨论的都是support库的Fragment).
  • FragmentActivity中有一个属性:mFragments,该属性类型是FragmentController.
  • FragmentController类中有一个属性mHost,类型是FragmentHostCallback,它是一个抽象类,实现者是HostCallback.
  • FragmentHostCall有两个重要的属性:mActivity和,mFragmentManager. mActivity就是前面说的FragmentActivity,而mFragmentManager是FragmentManagerImpl类型.
  • FragmentManagerImpl从名字看来就是用来管理Fragment的,它实现了FragmentManager接口,并且它有一个mHost属性,类型为FragmentHostBack.
  • FragmentActivity可以通过mFragment调用到FragmentManager里面的逻辑.
  • FragmentManager可以通过mHost调用到FragmentActivity中的逻辑.

分析完类图之后,我们知道FragmentActivity和FragmentManager之间可以通过FragmentHostCallback进行互相调用,那么接下来我们就从代码的角度看看我们是如何交互的。

代码 1:FragmentActivity的onCreate方法

    /**     * Perform initialization of all fragments and loaders.     */    @SuppressWarnings("deprecation")    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        mFragments.attachHost(null /*parent*/);        super.onCreate(savedInstanceState);        //....忽略部分代码        mFragments.dispatchCreate();    }

为了便于大家分析,我删除了onCreate中一些不相干的逻辑。可以看到在onCreate方法的第一句就调用了mFragment的attachHost方法,经过前面的分析,mFragments就是FragmentController对象,我们先来看看mFragment是如何赋值的。

代码2:FragmentActivity的mFragments属性初始化

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

从这里可以知道使用HostCallBacks对FragmentController中的mHost属性进行初始化。
接下来我们进入到FragmentController的attachHost方法看看。

代码3:FragmentController的attachHost方法

/**     * Attaches the host to the FragmentManager for this controller. The host must be     * attached before the FragmentManager can be used to manage Fragments.     */    public void attachHost(Fragment parent) {        mHost.mFragmentManager.attachController(                mHost, mHost /*container*/, parent);    }

attachHost方法远比我们想象的简单,里面就是调用了mHost.mFragmentManager的attachController方法。通过前面的分析,其实就是调用了FragmentManagerImpl的attachController方法,所以我们顺藤摸瓜,进入FragmentManagerImpl看看。

代码 4:FragmentManagerImpl 的attachController

 public void attachController(FragmentHostCallback host,            FragmentContainer container, Fragment parent) {        if (mHost != null) throw new IllegalStateException("Already attached");        mHost = host;        mContainer = container;        mParent = parent;    }

attachController方法也是相当的简单,就是对FragmentManager中的mHost,mContainer,mParent三个属性进行赋值。

到这里我们就知道FragmentActivity和FragmentManager是如何关联起来的,接下来我们看看Activity是如何管理Fragment的生命周期的。

在FragmentActivity的onCreate方法中还调用了一个方法

mFragments.dispatchCreate();

同样,我们进入到FragmentController的dispatchCreate方法
代码5 :FragmentController的dispatchCreate方法

/**     * Moves all Fragments managed by the controller's FragmentManager     * into the create state.     * <p>Call when Fragments should be created.     *     * @see Fragment#onCreate(Bundle)     */    public void dispatchCreate() {        mHost.mFragmentManager.dispatchCreate();    }

可以看到FragmentController并没有任何逻辑,仅仅是调用了FragmentManagerImpl的同名方法

代码6 :FragmentManagerImpl的dispatchCreate方法

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

dispatchCreate方法里面调用了一个叫moveToState的方法,同样,细心的同学会发现Activity的其他生命周期方法(onStart,onResume..)都会调用到FragmentManagerImpl的dispatchXXX的方法中,最终都调用到了moveToState这个方法,moveToState这个方法有多个同名的方法,最终调用的代码如下:
代码 7:FragmentManagerImpl的movetoState方法

void moveToState(int newState, int transit, int transitStyle, boolean always) {        if (mHost == null && newState != Fragment.INITIALIZING) {            throw new IllegalStateException("No host");        }        if (!always && mCurState == newState) {            return;        }        mCurState = newState;        if (mActive != null) {            boolean loadersRunning = false;            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();            }            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {                mHost.onSupportInvalidateOptionsMenu();                mNeedMenuInvalidate = false;            }        }    }

moveToState的逻辑比较清晰:

  • 使用mCurState保存传入进来的状态,例如onCreate的状态是Fragment.CREATED
  • 检查mActive列表是否为空(mActive保存的是Fragment列表),如果不为空,那么遍历此列表,然后调用另一个moveToState方法。这个moveToState就是Activity管理Fragment生命周期的核心所在。

    在分析此moveToState之前,先简单介绍Fragment的状态:

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.    int mState = INITIALIZING;

在Fragment中定义了6个状态,分包代表了当前Fragment的状态,和生命周期一一对应,每个Fragment创建时默认状态就是INITIALIZING.

代码 8 :FragmentManagerImpl中的另一个moveToState。

void moveToState(Fragment f, int newState, int transit, int transitionStyle,            boolean keepActive) {        // Fragments that are not currently added will sit in the onCreate() state.        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {            newState = Fragment.CREATED;        }        if (f.mRemoving && newState > f.mState) {            // While removing a fragment, we can't change it to a higher state.            newState = f.mState;        }        // Defer start if requested; don't allow it to move to STARTED or higher        // if it's not already started.        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {            newState = Fragment.STOPPED;        }        if (f.mState < newState) {            // For fragments that are created from a layout, when restoring from            // state we don't want to allow them to be created until they are            // being reloaded from the layout.            if (f.mFromLayout && !f.mInLayout) {                return;            }              if (f.mAnimatingAway != null) {                // The fragment is currently being animated...  but!  Now we                // want to move our state back up.  Give up on waiting for the                // animation, move to whatever the final state should be once                // the animation is done, and then we can proceed from there.                f.mAnimatingAway = null;                moveToState(f, f.mStateAfterAnimating, 0, 0, true);            }            switch (f.mState) {                case Fragment.INITIALIZING:                    if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);                    if (f.mSavedFragmentState != null) {                        f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(                                FragmentManagerImpl.VIEW_STATE_TAG);                        f.mTarget = getFragment(f.mSavedFragmentState,                                FragmentManagerImpl.TARGET_STATE_TAG);                        if (f.mTarget != null) {                            f.mTargetRequestCode = f.mSavedFragmentState.getInt(                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);                        }                        f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(                                FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);                        if (!f.mUserVisibleHint) {                            f.mDeferStart = true;                            if (newState > Fragment.STOPPED) {                                newState = Fragment.STOPPED;                            }                        }                    }                    f.mHost = mHost;                    f.mParentFragment = mParent;                    f.mFragmentManager = mParent != null                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();                    f.mCalled = false;                    f.onAttach(mHost.getContext());                    if (!f.mCalled) {                        throw new SuperNotCalledException("Fragment " + f                                + " did not call through to super.onAttach()");                    }                    if (f.mParentFragment == null) {                        mHost.onAttachFragment(f);                    }                    if (!f.mRetaining) {                        f.performCreate(f.mSavedFragmentState);                    }                    f.mRetaining = 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.mInnerView = f.mView;                            if (Build.VERSION.SDK_INT >= 11) {                                ViewCompat.setSaveFromParentEnabled(f.mView, false);                            } else {                                f.mView = NoSaveStateFrameLayout.wrap(f.mView);                            }                            if (f.mHidden) f.mView.setVisibility(View.GONE);                            f.onViewCreated(f.mView, f.mSavedFragmentState);                        } else {                            f.mInnerView = null;                        }                    }                case Fragment.CREATED:                    if (newState > Fragment.CREATED) {                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);                        if (!f.mFromLayout) {                            ViewGroup container = null;                            if (f.mContainerId != 0) {                                container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);                                if (container == null && !f.mRestored) {                                    throwException(new IllegalArgumentException(                                            "No view found for id 0x"                                            + Integer.toHexString(f.mContainerId) + " ("                                            + f.getResources().getResourceName(f.mContainerId)                                            + ") for fragment " + f));                                }                            }                            f.mContainer = container;                            f.mView = f.performCreateView(f.getLayoutInflater(                                    f.mSavedFragmentState), container, f.mSavedFragmentState);                            if (f.mView != null) {                                f.mInnerView = f.mView;                                if (Build.VERSION.SDK_INT >= 11) {                                    ViewCompat.setSaveFromParentEnabled(f.mView, false);                                } else {                                    f.mView = NoSaveStateFrameLayout.wrap(f.mView);                                }                                if (container != null) {                                    Animation anim = loadAnimation(f, transit, true,                                            transitionStyle);                                    if (anim != null) {                                        setHWLayerAnimListenerIfAlpha(f.mView, anim);                                        f.mView.startAnimation(anim);                                    }                                    container.addView(f.mView);                                }                                if (f.mHidden) f.mView.setVisibility(View.GONE);                                f.onViewCreated(f.mView, f.mSavedFragmentState);                            } else {                                f.mInnerView = null;                            }                        }                        f.performActivityCreated(f.mSavedFragmentState);                        if (f.mView != null) {                            f.restoreViewState(f.mSavedFragmentState);                        }                        f.mSavedFragmentState = null;                    }                case Fragment.ACTIVITY_CREATED:                case Fragment.STOPPED:                    if (newState > Fragment.STOPPED) {                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);                        f.performStart();                    }                case Fragment.STARTED:                    if (newState > Fragment.STARTED) {                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);                        f.performResume();                        f.mSavedFragmentState = null;                        f.mSavedViewState = null;                    }            }        } else if (f.mState > newState) {            switch (f.mState) {                case Fragment.RESUMED:                    if (newState < Fragment.RESUMED) {                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);                        f.performPause();                    }                case Fragment.STARTED:                    if (newState < Fragment.STARTED) {                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);                        f.performStop();                    }                case Fragment.STOPPED:                    if (newState < Fragment.STOPPED) {                        if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);                        f.performReallyStop();                    }                case Fragment.ACTIVITY_CREATED:                    if (newState < Fragment.ACTIVITY_CREATED) {                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);                        if (f.mView != null) {                            // Need to save the current view state if not                            // done already.                            if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {                                saveFragmentViewState(f);                            }                        }                        f.performDestroyView();                        if (f.mView != null && f.mContainer != null) {                            Animation anim = null;                            if (mCurState > Fragment.INITIALIZING && !mDestroyed) {                                anim = loadAnimation(f, transit, false,                                        transitionStyle);                            }                            if (anim != null) {                                final Fragment fragment = f;                                f.mAnimatingAway = f.mView;                                f.mStateAfterAnimating = newState;                                final View viewToAnimate = f.mView;                                anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(                                        viewToAnimate, anim) {                                    @Override                                    public void onAnimationEnd(Animation animation) {                                        super.onAnimationEnd(animation);                                        if (fragment.mAnimatingAway != null) {                                            fragment.mAnimatingAway = null;                                            moveToState(fragment, fragment.mStateAfterAnimating,                                                    0, 0, false);                                        }                                    }                                });                                f.mView.startAnimation(anim);                            }                            f.mContainer.removeView(f.mView);                        }                        f.mContainer = null;                        f.mView = null;                        f.mInnerView = null;                    }                case Fragment.CREATED:                    if (newState < Fragment.CREATED) {                        if (mDestroyed) {                            if (f.mAnimatingAway != null) {                                // The fragment's containing activity is                                // being destroyed, but this fragment is                                // currently animating away.  Stop the                                // animation right now -- it is not needed,                                // and we can't wait any more on destroying                                // the fragment.                                View v = f.mAnimatingAway;                                f.mAnimatingAway = null;                                v.clearAnimation();                            }                        }                        if (f.mAnimatingAway != null) {                            // We are waiting for the fragment's view to finish                            // animating away.  Just make a note of the state                            // the fragment now should move to once the animation                            // is done.                            f.mStateAfterAnimating = newState;                            newState = Fragment.CREATED;                        } else {                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);                            if (!f.mRetaining) {                                f.performDestroy();                            } else {                                f.mState = Fragment.INITIALIZING;                            }                            f.mCalled = false;                            f.onDetach();                            if (!f.mCalled) {                                throw new SuperNotCalledException("Fragment " + f                                        + " did not call through to super.onDetach()");                            }                            if (!keepActive) {                                if (!f.mRetaining) {                                    makeInactive(f);                                } else {                                    f.mHost = null;                                    f.mParentFragment = null;                                    f.mFragmentManager = null;                                    f.mChildFragmentManager = null;                                }                            }                        }                    }            }        }        if (f.mState != newState) {            Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "                    + "expected state " + newState + " found " + f.mState);            f.mState = newState;        }    }

可能有些同学看到这里有些晕,先喝杯茶冷静冷静,让我给你梳理一下这个方法的逻辑。
从整体来看,这个方法包含了很大的一个if..else.所以我们从16行还是看起:

if (f.mState < newState)

以Fragment.CREATE为例,此if语句成立(因为此时f.mState是INITIALIZING),所以接下来进入switch语句,为了大家看起来方便,我将switch语句重新copy一份。

switch (f.mState) {                case Fragment.INITIALIZING:                    if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);                    if (f.mSavedFragmentState != null) {                        f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(                                FragmentManagerImpl.VIEW_STATE_TAG);                        f.mTarget = getFragment(f.mSavedFragmentState,                                FragmentManagerImpl.TARGET_STATE_TAG);                        if (f.mTarget != null) {                            f.mTargetRequestCode = f.mSavedFragmentState.getInt(                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);                        }                        f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(                                FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);                        if (!f.mUserVisibleHint) {                            f.mDeferStart = true;                            if (newState > Fragment.STOPPED) {                                newState = Fragment.STOPPED;                            }                        }                    }                    f.mHost = mHost;                    f.mParentFragment = mParent;                    f.mFragmentManager = mParent != null                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();                    f.mCalled = false;                    f.onAttach(mHost.getContext());                    if (!f.mCalled) {                        throw new SuperNotCalledException("Fragment " + f                                + " did not call through to super.onAttach()");                    }                    if (f.mParentFragment == null) {                        mHost.onAttachFragment(f);                    }                    if (!f.mRetaining) {                        f.performCreate(f.mSavedFragmentState);                    }                    f.mRetaining = 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.mInnerView = f.mView;                            if (Build.VERSION.SDK_INT >= 11) {                                ViewCompat.setSaveFromParentEnabled(f.mView, false);                            } else {                                f.mView = NoSaveStateFrameLayout.wrap(f.mView);                            }                            if (f.mHidden) f.mView.setVisibility(View.GONE);                            f.onViewCreated(f.mView, f.mSavedFragmentState);                        } else {                            f.mInnerView = null;                        }                    }                case Fragment.CREATED:

通过前面的分析,第一个case就可以匹配成功,我们来详细分析这段代码:

  • 首先检查f.mSavedFragmentState是否不为null,有过开发经验的同学应该知道,只有销毁并重建才不为null,我们这里这哪是不考虑这种情况,所以第一个if语句不会走。
  • 使用FragmentManagerImpl中的属性初始化Fragment相应字段(如mHost)。
  • 调用Fragment的onAttach()
  • 调用mHost.onAttachFragment()(通过前面attachController方法可以知道mParentFragment一定是null)
  • 调用f.performCreate方法:
void performCreate(Bundle savedInstanceState) {        if (mChildFragmentManager != null) {            mChildFragmentManager.noteStateNotSaved();        }        mState = CREATED;        mCalled = false;        onCreate(savedInstanceState);        if (!mCalled) {            throw new SuperNotCalledException("Fragment " + this                    + " did not call through to super.onCreate()");        }        if (savedInstanceState != null) {            Parcelable p = savedInstanceState.getParcelable(                    FragmentActivity.FRAGMENTS_TAG);            if (p != null) {                if (mChildFragmentManager == null) {                    instantiateChildFragmentManager();                }                mChildFragmentManager.restoreAllState(p, null);                mChildFragmentManager.dispatchCreate();            }        }    }
  • performCreate方法其实就是调用了Fragment的onCreate方法
  • 调用f.performCreateView方法,其实就是调用Fragment的onCreateView方法
  • 调用f.onViewCreated()
    到这里这个case也算运行完了,是不是很简单?课时在前面分析Fragment生命周期时,不是说Activity的onCreate阶段还会调用Fragment的onActivityCreated吗?这里为什么执行到onViewCreated就结束了?我们再来回到这个case地方,你会发现这个case并没有break,也没有return ,那么以为着第二个case 也会被执行,我们看看第二个case
                case Fragment.CREATED:                    if (newState > Fragment.CREATED) {                    }                case Fragment.ACTIVITY_CREATED:

由于newState==Fragment.CREATED,所以这个case什么都不干。同样后面所有的case都会走,但是由于if语句均不满足,所以此时onActivityCreated语句并没有执行。
当最外层的if语句走完之后,会更新Fragment的状态

 if (f.mState != newState) {            Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "                    + "expected state " + newState + " found " + f.mState);            f.mState = newState;        }

所以此时Fragment的状态是Fragment.CREATED.
那么onActivityCreated什么时候执行呢?其实此方法并不是在Activity的onCreate阶段执行,而是onStart阶段执行,当你查看FragmentActivity的onStart方法时,你会看到如下代码:

@Override    protected void onStart() {        super.onStart();        if (!mCreated) {            mCreated = true;            mFragments.dispatchActivityCreated();        }        //省略部分代码        // NOTE: HC onStart goes here.        mFragments.dispatchStart();        mFragments.reportLoaderStart();    }

大家可以尝试跟踪dispatchActivityCreated方法,最终会调用Fragment的onActivityCreated。

到这里,我们就将moveToStatue的if部分分析完了,那么else部分什么时候会执行呢?其实if部分在对应Fragment从不可见到可见的生命周期方法,而else对应Fragment从可见到不可见的生命周期方法。

今天就分析到这里吧,本篇文章主要分析了Activity和Fragment在onCreate阶段生命周期的联动,以及从源码角度分析Fragment和Activity的联动机制,如果大家喜欢我的文章可以关注我的微信公众号,我会定时给大家推送技术文章….

1 0
原创粉丝点击