前言

Fragment对于 Android 开发人员来说一点都不陌生,由于差点儿不论什么一款 app 都大量使用 Fragment,所以 Fragment 的生命周期相信对于大家来说应该都非常清晰。但绝大部分人对于其生命周期都停留在表象,知道一个 Fragment 从创建到运行再到销毁所要经过的过程。但却不知道内部怎样实现。或许有人会这样说,给你一辆摩托车,你仅仅要会骑即可。不须要拆开来看它内部的组成结构;对于这种问题,我仅仅想说,编程不仅学开车,还要学会造车,而且通过了解实现原理。能够让我们更加清晰的理解 Fragment的生命周期。往往我们通过理解来掌握的东西,是不易忘记的。

Fragment 生命周期流程图

好了。来看以下流程图来回想一下 Fragment 的生命周期

分析

要分析 Fragment 的生命周期,离不开这四个类

FragmentActivity.java
FragmentManager.java
Fragment.java
BackStackRecord.java

启动 app 首先启动的是FragmentActivity。我们就从它開始看起。在 onCreate()方法中

    @Override
protected void onCreate(Bundle savedInstanceState) {
//Fragment管理类绑定 Activity
mFragments.attachActivity(this, mContainer, null);
// Old versions of the platform didn't do this!
if (getLayoutInflater().getFactory() == null) {
getLayoutInflater().setFactory(this);
} super.onCreate(savedInstanceState); NonConfigurationInstances nc = (NonConfigurationInstances)
getLastNonConfigurationInstance();
if (nc != null) {
mAllLoaderManagers = nc.loaders;
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
}
mFragments.dispatchCreate();
}

这里的mFragments就是FragmentManager,onCreate 中主要做了两件事,一、把FragmentManager和 Activity绑定,二、 向 Fragment分发 OnCreate 方法mFragments.dispatchCreate();看到这里。不知道大家有没有疑问。这里就会运行 Fragment 的onAttach 和 onCreate 方法吗?答案显然是错误的。由于我们都知道我们在运行 add + commit的时候才会运行,那么这里的 attach 和 onCreate 做了什么事?进去看看

    public void attachActivity(FragmentActivity activity,
FragmentContainer container, Fragment parent) {
if (mActivity != null) throw new IllegalStateException("Already attached");
mActivity = activity;
mContainer = container;
mParent = parent;
}

以上代码,仅仅是对变量的赋值,所以不会触发 Fragment 中的方法。

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

貌似触发了 Fragment 中的 onCreate方法,继续看看。

    void moveToState(int newState, int transit, int transitStyle, boolean always) {
//...省略部分代码
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 (mActive != null),由于我们眼下还没有地方初始化它,所以这里显然不成立,所以 dispatchCreate 方法也没有触发Fragment 中的不论什么方法,可是这里有一个须要注意

mCurState = newState;

也就是说当前状态变成了 Fragment.CREATED

FragmentActivity 中的其它方法如 onStart、onResume 都跟 onCreate 方法一样。都没有触发 Fragment 中的方法,

但mCurState 确发生了改变,变成了最后一个状态的值—> Fragment.RESUMED;

此时 Activity 已经启动了, FragmentManager中的mCurState也已经是Fragment.RESUMED,我们都知道,当我们通过FragmentManager.beginTransaction().add().commit()这时才是正在启动一个 Fragment。通过跟踪代码,commit终于调用的代码例如以下

    public void run() {
//....省略非常多代码
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
//add 会走这里
Fragment f = op.fragment;
f.mNextAnim = enterAnim;
mManager.addFragment(f, false);
} break;
case OP_REPLACE: {
//...省略
} break;
case OP_REMOVE: {
//...省略
} break;
case OP_HIDE: {
//...省略
} break;
case OP_SHOW: {
//...省略
} break;
case OP_DETACH: {
//...省略
} break;
case OP_ATTACH: {
//...省略
} break;
default: {
//...省略
}
} op = op.next;
}
//最后会去改变状态,这里就是整个生命周期运行的关键代码
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true); if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}

上面代码非常长,省略了部分代码,仅显示关键代码,当我们在 add 和 commit 之后,Fragment 会运行mManager.addFragment(f, false);这种方法

        if (mAvailIndices == null || mAvailIndices.size() <= 0) {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
f.setIndex(mActive.size(), mParent);
mActive.add(f); } else {
//...省略
}

我们在前面就已经讲过了这个if (mActive == null) ,它是在这里初始化的,所以当我们再次运行

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

的时候,这里是能够通过的,在 commit 之后就有这样一段代码

//最后会去改变状态,这里就是整个生命周期运行的关键代码
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);

还记得mCurState的状态是什么吗?没错,就是我们前面分析的

mCurState = Fragment.RESUMED;

接下来就来看看 他是怎么moveToState

    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//...省略
if (f.mState < newState) {
//...省略
}
switch (f.mState) {
case Fragment.INITIALIZING:
//...省略
f.mCalled = false;
f.onAttach(mActivity);
//...省略
if (f.mParentFragment == null) {
mActivity.onAttachFragment(f);
} if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
//...省略
}
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.findViewById(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;
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
if (container != null) {
Animation anim = loadAnimation(f, transit, true,
transitionStyle);
if (anim != null) {
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.mResumed = true;
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();
f.mResumed = false;
}
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 (!mActivity.isFinishing() && 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;
anim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
if (fragment.mAnimatingAway != null) {
fragment.mAnimatingAway = null;
moveToState(fragment, fragment.mStateAfterAnimating,
0, 0, false);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
}
});
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();
} 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.mActivity = null;
f.mParentFragment = null;
f.mFragmentManager = null;
f.mChildFragmentManager = null;
}
}
}
}
}
} f.mState = newState;
}

代码非常多,也比較乱,这里我来简单分析一下,首先的知道这几种状态值的大小

    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.

如今是f.mState = Fragment.INITIALIZING。newState = RESUMED;

所以if (f.mState < newState)成立。特别注意在上面的代码中每个 case 语句后面都没有 break 关键字。

所以简化以后的代码是:

switch (f.mState) {
case Fragment.INITIALIZING:
f.onAttach(mActivity);
if (f.mParentFragment == null) {
mActivity.onAttachFragment(f);
}
f (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
} case Fragment.CREATED:
f.performCreateView(...)
f.onViewCreated(...)
f.performActivityCreated(...);
f.restoreViewState(...)
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
f.performStart();
case Fragment.STARTED:
f.performResume();

以上就是 Fragment 启动的全过程。看完启动。再来看看 Fragment 销毁的过程运行 remove().commit()之后会运行例如以下代码

 case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = exitAnim;
mManager.removeFragment(f, transition, transitionStyle);
} break;
    public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
if (mAdded != null) {
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
fragment.mRemoving = true;
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
transition, transitionStyle, false);
}
}

能够看到最后一句。就是改变状态的调用,而且把newState 变为

Fragment.INITIALIZING或者Fragment.CREATED。如果当前 Fragment 在前台台运行。则为Fragment.INITIALIZING,我们如果当前值为Fragment.INITIALIZING。也就是当前运行的 Fragment 为我们所要移除的 Fragment。

由于if (f.mState < newState)不成立了,所以将会运行以下代码

else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
f.performPause();
case Fragment.STARTED:
f.performStop();
case Fragment.STOPPED:
f.performReallyStop();
case Fragment.ACTIVITY_CREATED:
saveFragmentViewState(f);
f.performDestroyView();
case Fragment.CREATED:
f.performDestroy();
f.onDetach();

千万不要被Fragment.CREATED这种命名给疑惑了,。尽管这里写的是Fragment.CREATED,但它运行的确实performDestroy()

总结:

细致分析就会发现整个生命周期事实上非常easy。简单来讲,就是 addView 和 removeView 的过程,仅仅是在当中增加了其它相似 Activity 的 onStart 等方法。

最后大家能够结合源代码再看一遍!

Fragment 生命周期怎么来的?的更多相关文章

  1. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  2. Android Fragment 生命周期及其API使用(建议使用自定义View替换Fragment)

    我为什么不主张使用Fragment Fragment:( Fragment就相当于一个有生命周期的View,它的生命周期被所在的Activity的生命周期管理 ) 生命周期回调说明: onAttach ...

  3. Android之Fragment学习笔记②(Fragment生命周期)

    一. Fragment生命周期图                                  二.Fragment生命周期方法介绍 Fragment的生命周期和activity生命周期很像,其生 ...

  4. Android Activity生命周期以及Fragment生命周期的区别与分析

    Android Fragment生命周期图: Activity生命周期图: 对照图: Fragment生命周期分析: 1. 当一个fragment被创建的时候,它会经历以下状态. onAttach() ...

  5. Fragment(四)Fragment生命周期分析(转)

    Fragment(四)Fragment生命周期分析 转载请注明:http://blog.csdn.net/liaoqianchuan00/article/details/24271607   例子一 ...

  6. Fragment生命周期与Fragment执行hide、show后的生命周期探讨

    一.Fragment 生命周期中的每个方法的意义与作用: 1.setUserVisibleHint()(此方法不属于生命周期方法):设置Fragment 用户可见或不可见时调用此方法,此方法在Frag ...

  7. Fragment生命周期以及使用时的小问题

    前言- 昨天在写UI的时候用到了FRAGMENT,发现自己对此还不是非常了解,借此机会记录一下 Fragment的生命周期- 官方生命周期图: Fragment每个生命周期方法的意义.作用- onVi ...

  8. Fragment 生命周期的详情

    Fragment每个生命周期方法的意义.作用(注意红色的不是生命周期方法):setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法.在该方法里面可以通过调用getU ...

  9. Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)

    使用Fragment 官方例子中显示: 例如:一个学生Fragment,需要传入studentId,进行http请求显示,那么setArguments后防止杀掉Fragment后,参数为0,显示不了数 ...

  10. 面试 -- fragment生命周期

    Android 3.0 (Api 11)引入: Fragment具有重用,易适配(平板和手机之间的)优点: 依赖Activity,生命周期受到Activity的生命周期影响: fragment生命周期 ...

随机推荐

  1. **没有规则可以创建“XXX”需要的目标“XXX”问题的解决方案

    一.现象 我将之前Redhat9.0编译好的uboot,转到ubuntu12.04环境.在ubuntu环境下对 uboot重新编译提示错误.编译过程如下: root@hailin-virtual-ma ...

  2. Python9-模块2-序列化-day20

    序列化 什么叫序列化——将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化. 序列就是字符串 序列化的目的1.以某种存储形式使自定义对象持久化:2.将对象从一个地方传递到另一个地方.3.使程序 ...

  3. JSTL 配置

    pache Tomcat安装JSTL 库步骤如下: 从Apache的标准标签库中下载的二进包(jakarta-taglibs-standard-current.zip). 官方下载地址:http:// ...

  4. 【JavaScript 2—基础知识点】:数据类型

    导读:我发现不管是哪一门语言,都会先介绍其发展,语法规则,数据类型,流程控制等.那么,这次,就介绍一下JavaScript中的数据类型,有些看着眼熟,有些不熟.熟的也不是之前认识的,不熟的,也不见得就 ...

  5. 被忽视的控件UIToolbar

    前言 UIToolbar以前也接触过,不过没有怎么用,久而久之就忘了他的存在,今天看别人源码的时候看见了,它怎么很方便,在排列一排视图的时候不需要我们算里面的坐标就可以轻松良好的把布局做出来 代码 U ...

  6. HDU——2955Robberies(小数背包)

    Robberies Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  7. BZOJ 3227 [Sdoi2008]红黑树(tree) ——贪心 动态规划

    首先可以想到一个贪心的方法,然后一层一层的合并. 也可以采用动态规划的方式,为了写起来好写,把点数*2+1,然后发现在本机上跑不过1500的数据. 交上去居然A掉了. 贪心 #include < ...

  8. [luoguP3413] SAC#1 - 萌数(数位DP)

    传送门 gtm的数位dp! 看到好多题解,都是记忆化搜索,好像非常方便啊,但是我还是用递推好了,毕竟还是有些类似数位dp的题用递推的思路,记忆化做不了,现在多培养一下思路 首先这道题, 只看长度大于等 ...

  9. 【bzoj2115】[Wc2011] Xor【高斯消元】

    题目大意:给出一个无向有权图,找出一条从1到n的路径,使得路径上权值的异或和最大,路径可以重复走 Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条 ...

  10. JSP学习笔记(七十八):struts2中s:select标签的使用

    1.第一个例子: <s:select list="{'aa','bb','cc'}" theme="simple" headerKey="00& ...