Fragment 生命周期怎么来的?
前言
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 生命周期怎么来的?的更多相关文章
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- Android Fragment 生命周期及其API使用(建议使用自定义View替换Fragment)
我为什么不主张使用Fragment Fragment:( Fragment就相当于一个有生命周期的View,它的生命周期被所在的Activity的生命周期管理 ) 生命周期回调说明: onAttach ...
- Android之Fragment学习笔记②(Fragment生命周期)
一. Fragment生命周期图 二.Fragment生命周期方法介绍 Fragment的生命周期和activity生命周期很像,其生 ...
- Android Activity生命周期以及Fragment生命周期的区别与分析
Android Fragment生命周期图: Activity生命周期图: 对照图: Fragment生命周期分析: 1. 当一个fragment被创建的时候,它会经历以下状态. onAttach() ...
- Fragment(四)Fragment生命周期分析(转)
Fragment(四)Fragment生命周期分析 转载请注明:http://blog.csdn.net/liaoqianchuan00/article/details/24271607 例子一 ...
- Fragment生命周期与Fragment执行hide、show后的生命周期探讨
一.Fragment 生命周期中的每个方法的意义与作用: 1.setUserVisibleHint()(此方法不属于生命周期方法):设置Fragment 用户可见或不可见时调用此方法,此方法在Frag ...
- Fragment生命周期以及使用时的小问题
前言- 昨天在写UI的时候用到了FRAGMENT,发现自己对此还不是非常了解,借此机会记录一下 Fragment的生命周期- 官方生命周期图: Fragment每个生命周期方法的意义.作用- onVi ...
- Fragment 生命周期的详情
Fragment每个生命周期方法的意义.作用(注意红色的不是生命周期方法):setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法.在该方法里面可以通过调用getU ...
- Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)
使用Fragment 官方例子中显示: 例如:一个学生Fragment,需要传入studentId,进行http请求显示,那么setArguments后防止杀掉Fragment后,参数为0,显示不了数 ...
- 面试 -- fragment生命周期
Android 3.0 (Api 11)引入: Fragment具有重用,易适配(平板和手机之间的)优点: 依赖Activity,生命周期受到Activity的生命周期影响: fragment生命周期 ...
随机推荐
- nginx 无法加载css/js图片等文件 404 not fund
刚配置Nginx反向代理,Nginx可能会出现无法加载css.js或者图片等文件,这里需要在配置文件*.conf里面加上如下配置项. location ~ .*\.(js|css|png|jpg)$ ...
- selenium总结(持续更新)
1.怎么 判断元素是否存在? 如果这个元素不存在, 就会抛出NoSuchElementException,可以通过使用try catch,如果catch到NoSuchElementException ...
- 我的第一个ajax脚本
代码如下 //创建XMLHttpRequest对象 var xmlHttp=null; function creatXMLHttp(){ try{ xmlHttp = new XMLHttpReque ...
- '>>' should be '> >' within a nested template argument list
在编译关于opencv相机标定的工程的时候出现了这个问题 vector<vector<Point3f>> objectPoints; error: 'objectPoint ...
- sql优化工具--美团SQLAdvisor
美团点评SQL优化工具SQLAdvisor开源 介绍 在数据库运维过程中,优化 SQL 是 DBA 团队的日常任务.例行 SQL 优化,不仅可以提升程序性能,还能够降低线上故障的概率. 目前常用的 S ...
- Java线程和多线程(三)——线程安全和同步
线程安全在Java中是一个很重要的课题.Java提供的多线程环境支持使用Java线程.我们都知道多线程共享一些对象实例的话,可能会在读取和更新共享数据的事后产生数据不一致问题. 线程安全 之所以会产生 ...
- return_url notify_url
return_url对返回订单状态进行更新和判断,notify_url为异步调动页面,需要先判断notify_url里是否对订单数据做过处理,避免重复更新数据,然后如果用户付款成功直接关闭页面,会造成 ...
- 每天一个linux命令目录(转)
一. 文件目录操作命令: 1.每天一个linux命令(1):ls命令 2.每天一个linux命令(2):cd命令 3.每天一个linux命令(3):pwd命令 4.每天一个linux命令(4):mk ...
- 【Luogu】P3387缩点(Tarjan缩点+深搜DP)
题没什么好说的,因为是模板题.求值我用的是dfs. 不能直接在原图上dfs,因为原图上有环的话会发生一些滑稽的事情.所以我们要用Tarjan缩点.因为此题点权全为正,所以如果在图上走一个环当然可以全走 ...
- vue 组件高级用法实例详解
一.递归组件 组件在它的模板内可以递归地调用自己, 只要给组件设置name 的选项就可以了. 示例如下: <div id="app19"> <my-compone ...