文章目录
前言
本文记录笔者学习Fragment生命周期的心路历程
一、Fragment生命周期概述
在这一部分中,我们单纯以Fragment为观察对象,观察其生命周期
在Android开发平台的官方文档中,对Fragment的生命周期有如下的描述
尽管 Fragment 的生命周期与其拥有的活动相关联,但它在标准活动生命周期上也有自己的缺陷。它包括基本的活动生命周期方法,例如onResume(),但与活动交互和 UI 生成相关的方法也很重要。
Fragment(与用户交互)的一系列核心生命周期方法是:
- onAttach(Activity)一旦Fragment与其活动相关联时调用。
- onCreate(Bundle)调用以进行Fragment的初始创建。
- onCreateView(LayoutInflater, ViewGroup, Bundle)创建并返回与片段关联的视图层次结构。
- onActivityCreated(Bundle)告诉Fragment它的活动已经完成了它自己的Activity.onCreate().
- onViewStateRestored(Bundle)告诉Fragment其视图层次结构的所有已保存状态都已恢复。
- onStart()使片段对用户可见(基于其包含的活动正在启动)。
- onResume()使片段开始与用户交互(基于其包含的活动被恢复)。
当一个Fragment不再被使用时,它会经历一系列反向回调:
- onPause()片段不再与用户交互,因为它的活动被暂停或片段操作正在活动中修改它。
- onStop()片段不再对用户可见,因为它的活动正在停止或片段操作正在活动中修改它。
- onDestroyView()允许片段清理与其视图关联的资源。
- onDestroy()调用以对片段的状态进行最终清理。
- onDetach()在片段不再与其活动相关联之前立即调用。
放一张目前网上能找到的相对完整的生命周期如下
(相对完整),因为看过Google最新关于Fragment生命周期描述的uu就应该知道这篇生命周期的描述是不完整的,但是大体思路可以看看
这里给出如下案例进行阐述
启动
onAttach() -------> onCreate() [Fragment]-------> onCreateView() ------>onCreate()[Activity]->onActivityCreated->onViewCreated() -----> onStart()-------> onStart()(Activity) -------->onResume()(Activity) --------> onResume()
退出
onPause[Activity]->onPause[Fragment]->onStop[Activity]->onStop[Fragment]->onDestroy[Activity]->onDestroyView[Fragment]->onDestroy[Fragment]->onDetach[Fragment]
二、Fragment生命周期细述
1.onCreate(Bundle)
我们一般使用Fragment的无参构造函数,尽管我们可以通过自己定义书写Fragment的有参构造函数,但是这样做很容易导致不可预见的bug
当Activity被强制销毁,之后又被自动恢复的时候,Android系统会在这一过程中销毁并重新创建Fragment。
重新创建的机制是通过使用反射的方法来调用Fragment的无参构造函数来实现的。
因此,如果您是使用带参数的构造函数来实例化Fragment,并在其中将依赖的对象传递给它,那么在保存和恢复后,所有这些依赖的对象都将被设置为null。
因此,就像Activity一样,您需要使用onCreate(Bundle)方法作为构造函数的替代者。
Fragment中依赖对象的注入和初始化就发生在这里。
Fragment相关逻辑源码如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getInjector().inject(this); // inject dependencies
if (savedInstanceState != null) {
mWelcomeDialogHasAlreadyBeenShown = savedInstanceState.getBoolean(SAVED_STATE_WELCOME_DIALOG_SHOWN);
}
mActivityAsListener = (ActivityAsListener) requireActivity();
}
2.onCreateView(LayoutInflater, ViewGroup, Bundle)
看到这个方法,大多数人都会有疑惑的地方就是,为何Fragment不像Activity那样在onCreate()方法中初始化View呢,这里引用另外一位博主的解释
Activity在生命周期的转换过程中都只有同一个View hierarchy。 你在Activity的onCreate(Bundle)中初始化这个View hierarchy,然后它就会一直存在于Activity的整个生命周期,直到Activity被垃圾收集器回收为止。 您可以手动更改Activity的View hierarchy的组成,Android系统是不会为您做任何事情的。
然而,Fragment在其生命周期中可以存在有多个View hierarchy,由Android系统决定何时进行替换。
换句话说,你可以在程序运行的时候动态改变Fragment的View hierarchy,现在你应该清楚为什么不能在Fragment的onCreate(Bundle)中操作View了吧。 onCreate(Bundle)方法在Fragment被Attach到Activity后仅被调用一次,它无法支持Fragment的View hierarchy的动态化。
每次需要创建新的View hierarchy的时候,Android系统都会调用onCreateView(LayoutInflater, ViewGroup, Bundle)方法。 您的工作是创建View hierarchy并将其初始化为正确的状态,然后将它作为该方法的返回值,之后它就会被Android系统接管。
重写这个方法的主要原则是:Fragment中所有持有与View hierarchy相关的对象的引用的成员变量,必须在View onCreateView(LayoutInflater,ViewGroup,Bundle)中进行初始化。 换句话说,如果Fragment的成员变量持有View或者相关对象的引用,请确保在此方法中初始化这些成员变量,这非常重要。
换句话说,onCreateView()存在的意义就是使得Fragment可以动态改变其View hierarchy
3.onStart()
参照Activity的onStart()方法
4.onResume()
参照Activity
5.onPause()
参照Activity的onPause()方法
6.onStop()
这个方法的处理逻辑同样与Activity的onStop()方法相同。其基本的处理逻辑如下所示:
相关源码如下
@Override
public void onStop() {
super.onStop();
mSomeView.setOnClickListener(null);
mFirstDependency.unregisterListener(this);
}
在这里需要完成两件事
1.取消Activity的相关注册
2.取消点击事件
之所以这样做,可以参照以下的解释
1:
如果在onPause()方法里调用mFirstDependency.unregisterListener(this),那么Activity将不会收到相关异步流程完成的通知。因此,它不能让用户感知到这一事件,从而完全违背了多窗口模式的设计初衷,这不是一种好的处理方式。
如果在onDestroy()方法里调用mFirstDependency.unregisterListener(this),这同样不是一种好的处理方式。
当应用被用户推到后台(例如,点击“home”按钮)时,Activity的onStop()将被调用,从而使得其返回到“已创建”状态,这个Activity可以在几天甚至几周的时间内保持这个状态。
如果这时候mFirstDependency产生了连续的事件流,那么在这几天甚至几周的时间里,Activity可以都处理这些事件,即使用户在这段时间内从未真正与它交互过。这将是对用户电池寿命的不负责任的浪费,而且在这种情况下,应用消耗的内存会逐渐增多,应用进程被OOM(Out
Of Memory)Killer杀死的可能性也会增大。
因此,在onPause()和onDestroy()里调用mFirstDependency.unregisterListener(this)都不是一种好的处理方式,您应该在onStop()中执行此操作。
2:
关于2的解释,主要是用户使用APP的连续性和解决Activity停止后事件仍然进行分发的结果
7.onDestroy():
不需要覆盖重写这个方法,这个方法完全只是相关资源的回收
8.onSaveInstanceState(Bundle):
此方法用于保存一些临时的状态,在这个方法里你位移需要做的就是将你想保存的状态存入Bundle数据结构中:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SAVED_STATE_WELCOME_DIALOG_SHOWN, mWelcomeDialogHasAlreadyBeenShown);
}
在这里,有个陷阱,如果你在这个方法执行完之后,提交Fragment事务,那么应用程序会抛出IllegalStateException异常而导致崩溃。
你需要知道的一点是onSaveInstanceState(Bundle)将在onStop()之前被调用。
好消息是,经过多年的努力,谷歌终于意识到了这个bug。 在新版本的Android中,==onStop()将在onSaveInstanceState(Bundle)==之前被调用。
总结
以上就是Fragment生命周期的分享和整理