Android Framwork开发人员中的传奇人物Dianne Hackborn在2010年将Fragment引入了Android,也就是在android3.0之后引入Fragment,他在提交信息中写道:

“将单一的Activity拆分成多个独立的部件”的想法非常好。 然而,从今天Fragment的的实际使用效果来看,这一API的实现和演变并不理想。

虽然在项目中我们经常使用Fragment,但Fragment也有局限性和缺点,让我们来看下面这个流程图:

幸运的是,您在应用中使用Fragment的时候无需了解整个生命周期的转换过程,本文将介绍一些处理Fragment生命周期的方法,它隐藏了大部分的复杂细节。

Make Take  On Fragment Lifecycle

处理Fragment生命周期的方法旨在实现两个目标:

1、使Fragment的生命周期处理逻辑尽可能类似于Activity的处理逻辑。

2、使Fragment的生命周期处理逻辑独立于Activity的生命周期。

使用类似于处理Activity的生命周期的方法来处理Fragment的生命周期,能大幅降低应用程序的整体复杂性;这意味着开发过程中的工作量会减少,维护会更容易,新团队成员熟悉项目的速度会更快,某种程度上,还可以减少bug产生的风险。

OnCreat(Bundle)

当Activity被强制销毁,之后又被自动恢复的时候,Android系统会在这一过程中销毁并重新创建Fragment。 重新创建的机制是通过使用反射的方法来调用Fragment的无参构造函数来实现的。 因此,如果您是使用带参数的构造函数来实例化Fragment,并在其中将依赖的对象传递给它,那么在保存和恢复后,所有这些依赖的对象都将被设置为null。

就像Activity一样,需要使用onCreate(Bundle)方法作为构造函数的替代者。 Fragment中依赖对象的注入和初始化就发生在这里;

与Activity的onCreate(Bundle)方法不同的是, 不得在Fragment的onCreate(Bundle)方法中执行任何与Android View相关的操作, onCreate(Bundle)方法在Fragment被Attach到Activity后仅被调用一次,它无法支持Fragment的View hierarchy的动态化;

将Activity转换为listener也发生在onCreate(Bundle)中,这将比在onAttach(Context)中抛出一个通用的ClassCastException要有意义的多;

View  onCreatView(LayoutInflater,ViewGroup,Bundle)

这个方法是Fragment独有的,这是它与Activity生命周期最显着的区别。

Activity在生命周期的转换过程中都只有同一个View hierarchy。 你在Activity的onCreate(Bundle)中初始化这个View hierarchy,然后它就会一直存在于Activity的整个生命周期,直到Activity被垃圾收集器回收为止;

然而,在Fragment在其生命周期中可以存在有多个View hierarchy,由Android系统决定何时进行替换;

每次需要创建新的View hierarchy的时候,Android系统都会调用onCreateView(LayoutInflater, ViewGroup, Bundle)方法;

重写这个方法的主要原则是:Fragment中所有持有与View hierarchy相关的对象的引用的成员变量,必须在View onCreateView(LayoutInflater,ViewGroup,Bundle)中进行初始化,如果Fragment的成员变量持有View或者相关对象的引用,须确保在此方法中初始化这些成员变量;

方法的基本的处理逻辑如下:

Fragment里每个与View hierarchy相关的成员变量都必须在此方法中初始化, 这包括列表适配器,用户交互事件的监听器等。保持Fragment里的代码可维护性的唯一方法是确保此方法在重新创建整个View hierarchy的时候会重新初始化Fragment里与之相关的成员变量,这也是为了减小内存泄漏的风险。

onStart()

Fragment的这个方法与Activity的onStart()方法具有完全相同的职责和指导原则,方法的基本的处理逻辑如下:

@Override
public void onStart() {
super.onStart(); mSomeView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleOnSomeViewClick();
}
}); mFirstDependency.registerListener(this); switch (mSecondDependency.getState()) {
case SecondDependency.State.STATE_1:
updateUiAccordingToState1();
break;
case SecondDependency.State.STATE_2:
updateUiAccordingToState2();
break;
case SecondDependency.State.STATE_3:
updateUiAccordingToState3();
break;
} if (mWelcomeDialogHasAlreadyBeenShown) {
mFirstDependency.intiateAsyncFunctionalFlowAndNotify();
} else {
showWelcomeDialog();
mWelcomeDialogHasAlreadyBeenShown = true;
}
}

这个方法里包含了Fragment的大部分功能逻辑。 保持onStart()方法在Activity和Fragment里的一致性具有很多好处。

onResume()

这个方法的处理逻辑与Activity的onResume()方法相同。

onPause()

这个方法的处理逻辑与Activity的onResume()方法相同。

onStop()

这个方法的处理逻辑同样与Activity的onStop()方法相同,在此方法中,我们可以注销点击事件的监听器,不是必须的,但是也可以减少bug的风险。

onDestroyView()

之前说必须在onCreateView(LayoutInflater,ViewGroup,Bundle)里初始化Fragment里所有持有View或者相关对象的引用的成员变量。这个要求源自于这样一个事实:Fragment的View hierarchy可以被重新创建,所以所有未在该方法中被初始化的持有View的引用对象都将被置为null;

如果这样做了,Fragment将一直持有对这些View的强引用,直到下一次调用View onCreateView(LayoutInflater,ViewGroup,Bundle)方法或者整个Fragment被销毁;

有很多建议是应该在onDestroyView()方法里将所有前面提到的成员变量设置为Null。 目的是尽快释放这些引用以允许垃圾收集器在onDestroyView()返回后立即回收它们,这样就能更快地释放与这些View相关的内存空间,但这是过早优化的经典案例,在绝大多数情况下,你并不需要这种优化,所有,我们不需要重写onDestroyView()方法。

onDestroy()

像Activity一样,您不需要在Fragment中重写此方法。

onSaveInstanceState(Bundle)

这个方法的基本的处理逻辑如下:

这个方法对应于Activity的onSaveInstanceState(Bundle)方法,所以对Activity的onSaveInstanceState(Bundle)的大多数讨论也适用于此。但请注意:此方法可能在onDestroy()之前的任何时候被调用;在许多情况下,Fragment可能会被销毁。

根据官方文件:这个方法可能在onDestroy()之前的任何时候调用。 这里有两个主要问题:

1、与Fragment相关联的View hierarchy可以被销毁而不实际保存其状态。 因此,如果您想在View onCreateView(LayoutInflater,ViewGroup,Bundle)中恢复Fragment的状态,这会加大程序崩溃的几率;

2、如果在onDestroy()之前的任何时候都可以调用onSaveInstanceState(Bundle),那么就无法保证何时才能安全地更改Fragment的状态(例如替换嵌套的Fragment)。

setRetainInstance(boolean)

Fragment具有属性retainInstance,默认值为false。 
当设备旋转时,fragment会随托管activity一起销毁并重建。

调用setRetainInstance(true)方法可保留fragment,代码如下:

已保留的fragment不会随着activity一起被销毁; 
相反,它会一直保留(进程不消亡的前提下),并在需要时原封不动地传递给新的Activity。

但是此方法建议不使用,因为此方法改变了Fragment的生命周期。

为什么Fragment如此复杂?

也许引入这种机制是为了优化内存的消耗。当Fragment不可见的时候,销毁Fragment的View hierarchy允许释放一些内存。 但另一个问题是:Fragment实现了对状态保存和恢复流程的支持;

在FragmentStatePagerAdapter并不是采用这种机制去保存和恢复Fragments的状态。

借用原作者的话:整个机制可能是一种过早的优化,它没有任何用处,反而会使得Fragment使用更复杂。

 结语 

虽然Fragment,整个机制复杂,但是与“一个界面一个Activity”的方法相比,Fragment可以提供更好的用户体验;

但是我们在使用Fragment的时候,建议在处理Fragment的生命周期时让它类似于Activity的生命周期并且独立于它,这使得Fragment的复杂性是可以管理的。

小伙伴们,你的支持是我前进的动力,动动手指,扫面二维码关注我们吧,如果您有任何补充或者想要指出本文中的任何缺陷,请给小编留言哦。

你真的了解Fragment的生命周期吗?的更多相关文章

  1. 死磕 Fragment 的生命周期

    死磕 Fragment 的生命周期 本文原创,转载请注明出处.欢迎关注我的 简书 ,关注我的专题 Android Class 我会长期坚持为大家收录简书上高质量的 Android 相关博文.本篇文章已 ...

  2. Fragment的生命周期

    Fragment的生命周期: 1. onAttach():Fragment对象跟Activity关联时 2. onCreate():Fragment对象的初始创建时 3. onCreateView() ...

  3. Fragment的生命周期(三)

    自定义lifecycleoffragment布局文件 在main_activity布局中引用自定义的fragment布局 到logcat中查看程勋运行的结果 代码如下: 自定义的fragment布局: ...

  4. 友盟页面统计 - 关于Viewpager中的Fragment的生命周期

    Activity和Fragment各自理论上的生命周期 Activity的生命周期是较为经典也最清晰的,在此不表: Fragment从出现到广泛运用也有一段时间了,其标准生命周期也仅比Activity ...

  5. fragment的生命周期及其各个周期方法的作用

    先上生命周期图: Fragment的生命周期图: 与Activity的生命周期对比图: 由于Fragment是嵌在Activity中使用的,故其生命周期也是依赖于Activity的周期的,或者说Fra ...

  6. Activity与Fragment的生命周期

    今天看到一张图,详细描述了Activity和Fragment的生命周期,好资源共享咯!

  7. Android系列之Fragment(二)----Fragment的生命周期和返回栈

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  8. Android学习笔记(六)Fragment的生命周期

    在上一篇博文中对Fragment做了简单的介绍,现在再来探讨一下Fragment的生命周期. 一.Fragment的几种状态: 与Activity类似,Fragment也有一下几种状态: · 活动状态 ...

  9. Fragment的生命周期&同一Activity下不同Fragment之间的通信

    Android开发:碎片Fragment完全解析(2) Fragment的生命周期 和Activity一样,Fragment也有自己的生命周期,理解Fragment的生命周期非常重要,我们通过代码的方 ...

随机推荐

  1. 2019.04.11 第四次训练 【 2017 United Kingdom and Ireland Programming Contest】

    题目链接:  https://codeforces.com/gym/101606 A: ✅ B: C: ✅ D: ✅ https://blog.csdn.net/Cassie_zkq/article/ ...

  2. follow up2-20190426

    406. Minimum Size Subarray 同向双指针 https://www.lintcode.com/problem/minimum-size-subarray-sum/descript ...

  3. php 使用 rabbitmq

    1,配置好rabbitmq 服务器 (参照 http://www.cnblogs.com/spicy/p/7017603.html)(我是linux) 2,新增了一个用户 并点击该用户 增加权限如下

  4. ehcache 集群使用 rmi方式 有图有真想

    来源:http://www.tuicool.com/articles/MJzYZbR ehcache 有几种方式集群 ,rmi,jgroup还有jms:这里讲一下ehcache的使用 ehcache ...

  5. Go语言学习笔记三: 常量

    Go语言学习笔记三: 常量 定义常量 常量就是在声明后不能再修改的量. const x int = 100 const y string = "abc" const z = &qu ...

  6. i.mx6 Android6.0.1分析input子系统:测试

    getevent与sendevent工具 Android系统提供了getevent与sendevent两个工具供开发者从设备节点中直接读取输入事件或写入输入事件. 在这里,我们测试音量加和音量减按键 ...

  7. nginx timeout 配置 全局timeout 局部timeout web timeout

    nginx比较强大,可以针对单个域名请求做出单个连接超时的配置. 比如些动态解释和静态解释可以根据业务的需求配置 proxy_connect_timeout :后端服务器连接的超时时间_发起握手等候响 ...

  8. [转]使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

    本文转自:http://www.cnblogs.com/fzrain/p/3552423.html 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html ...

  9. MVC缓存(一)

    //OutputCache是设置缓存,参数Duration设置缓存的过期时间,OutputCache可以加到Controller上,也可以加到Action上,但是当Controller与Action都 ...

  10. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...