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. webpack/gulp的z-index被改写

    webpack方法 new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }) gulp-cssnano 方法 .pipe(cssna ...

  2. [转] Ansible 内置变量参考

    Quick reference for Ansible variables [From] https://github.com/lorin/ansible-quickref

  3. ajax防止表单自动提交

    重写表单的checkForm方法,并用if和else解决异步判断的问题. function checkForm(){ 1 var flag = false; $.ajaxSetup({async : ...

  4. IC79620: USER'S ROUTINE MAY BE TERMINATED ABNORMALLY IF SOME SYSTEMROUTINES WERE RUN IN DB2FMP BEFORE

    http://www-01.ibm.com/support/docview.wss?uid=swg1IC79620 APAR status Closed as program error. Error ...

  5. 移动端优化 && 清除移动端网站点击a标签时闪现的边框或遮罩层(CSS) && 移动端点击 && 文字不可选择

      在移动端网站,当你点击加了a标签的文字或图片时,该元素的周围会闪现一个蓝色的边框,在微信上的网站就是如此:而有的浏览器会闪现一个半透明遮罩层,比如移动端的Chrome浏览器,其实这些特效无非就是为 ...

  6. hibernate关联关系的crud之级联

    cascade级联,只会影响CRUD的CUD,不会影响读取.不设置级联,从多的一方能读出一的一方,设了级联,从一的一方,默认也不能读出多的一方. 如果两个对象之间有关联,不管是一对多,多对一,单向还是 ...

  7. java反射机制_读取properties

    代码: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 反射特点: ...

  8. 【转载】伪静态SQL注入

    伪静态,主要是为了隐藏传递的参数名,伪静态只是一种URL重写的手段,既然能接受参数输入,所以并不能防止注入.目前来看,防止注入的最有效的方法就是使用LINQ.常规的伪静态页面如下:http://www ...

  9. 132页Filter代码分析

    1.long before = System.currentTimeMillis(); long after = System.currrentTimeMillis(); 解析:这两段代码之间定义的是 ...

  10. git删除远程主机没有的tag

    可以先删除所有本地tag,然后再拉取远程上的tag git tag -l | xargs git tag -d git fetch --tags 其他方法以及查询tag的命令请见:Remove loc ...