Android官方给出:基本情况下Activity与Fragment的生命周期对应关系如下图: 图1.0 静态布局情况下fragment与Activity的生命周期对应图
这个生命周期的严格对应关系成立条件为:fragment通过静态布局的方式插入到Activity的布局中。但是通过FragmentManager动态管理的时候就有些许差别了。
这里演示的是动态加载的Fragment(通过FMManager),其实通过xml静态插入的Fragment基本生命周期根下面是一样的,有些许不同(如上图1.0⬆️)。不同的原因是Activity里面的onCreate()方法下会调用 到setContentView()加载静态布局,这个方法会按照深度优先的算法解析xml里面的View树结构,加载嵌套在里面的的Fragment以及View。而动态加载的Fragment的生命周期总体时依附于Activity,但是由于不会在 setContentView()中得到解析构造,因此生命周期前面部分(onAttach、onCreate、onCreateView、onActivityCreated()、onStart、onResume)未与用户交互的阶段,这些周期调用时机随着在Activity生命周期的不同时刻 通过FragmentManager加载会有不同的表现。
假设:Activity:A。 Fragment: F1、F2 通过FragmentManager 在onCreate()方法进行Fragment的add。
可以看出,与图1.0所示的生命周期对应基本一样。
任何一个View也是有生命周期的,从构造——>onFinishInflate()——>attachToWindow() ——>onMesure()——>onLayout()——>onDraw——>响应事件交互——>onDetachFromWindow()。
假设有两个View:V1、V2。V1在Activity A中,V2在Fragment F中。 View在xml布局中,Fragment通过FragmentManager加载。
情况一、在启动到可交互时:
//Activity创建 A-onCreate()——> //Activity的xml静态布局中,按照深度优先顺序先对view解析 V1-onFinishInflate()——> //创建Fragment F1-onAttach()——> F-onCreate()——> //创建Fragment视图 F-onCreateView()——> //解析Fragment里面的view视图 V2-onFinishInflate()——> F1-onViewCreated()——> F-onActivityCreated()——> F-onStart()——> A-onResume()——> F-onResume()——> //Activity、View将要界面将要绘制显示 A-onAttachedToWindow()——> V1-onAttachedToWindow()——> V2-onAttachedToWindow()——> //View视图绘制、按照V1、V2加载顺序 V1-onMeasure()——> V2-onMeasure()——> V1-onLayout()——> V2-onLayout()——> V1-onDraw()——> V2-onDraw()情况二、当销毁时
//Fragment生命周期跟随Activity生命周期销毁变化而变化 F-onPause()——> A-onPause()——> F-onStop()——> A-onStop()——> //Fragment视图销毁 F-onDestroyView()——> //由于Fragment是动态加载,因此view由FragmentManager管理,此时跟随Fragment视图一同销毁 V2-onDetachedFromWindow()——> F-onDestroy()——> F-onDetach()——> A-onDestroy()——> //由于V1是静态插入Activity布局文件里面,因此它的生命结束跟随Activity视图销毁而销毁 V1-onDetachedFromWindow()——> A-onDetachedFromWindow()总结:View在Activity中和在Fragment中有两个点不太一样:
inflate:简单来说,无论fragment是通过源代码FragmentManager添加还是通过xml布局插入,Activity的View在setContentView()时被Inflate,Fragment的View在onCreateView时被inflate;
onAttachedToWindow():这个View的生命周期的调用无论在fragment、Activity都一样,因为Activity才是整个界面的承载者和入口,因此Activity的onAttachedToWindow处于使得window处于前台之后,View的添加 就会调调用自身的onAttachedToWindow
onDetachFromWindow():当销毁时,情况稍微不同:如果fragment、view都在xml文件中插入,则V1、V2都在Activity的onDetachedFromWindow时触发。但是当fragment时通过FragmentManager中添加的时候,Activity的View在Activity调用onDetachedFromWindow()时会触发,而Fragment里面的View会在Fragment的onDestroyView()时触发。
ViewPager也是一个View,Fragment根ViewPager的结合其实也是通过FragmentManager来管理的,因此归结来说还是通过动态加载的方式来管理Fragment的生命周期。
假设: 含有ViewPager的Activity:A; Fragment:F1、F2、F3、F4,通过FM交ViewPagerAdapter。 嵌在Fragment中的View:V1、V2、V3、V4
从上面我们可以看出 第一,与fragment被添加至Acvitity的时候不一样,fragment的构造是在Activity调用onAttachedToWindow()之后; 第二,预先加载了一个fragment,并且生命周期执行到了onResume()。
关于这个的全部情况就不放在上面了,下面的例子是使用FragmentPagerAdapter说明的,FragmentStatePagerAdapter在是否销毁不保存Fragment上有所不同。默认情况下FragmentPagerAdapter会预加载/保留包括当前fragment的前后3个fragment(如果有的话)的状态,便于切换界面的时候更加流畅。同时,对于未保留状态的其他fragment并未销毁,只是执行到了onDestroyView()方法,将其内部的view销毁,重新返回加载的时候便会从onCreateView()进行,而不会重新调用整个生命周期。
因此对于ViewPager下的Fragment的状态保存一般在onDestroyView之前保存下来,用于下一次的初始化(FragmentStatePagerAdapter则不会销毁所有不保存状态的Fragment)。 下面的例子是使用FragmentPagerAdapter。
1、从第二个Fragment切换到第三个Fragment
//预加载第四个Fragment F4-onAttach() F4-onCreate() //销毁第一个Fragment的视图 F1-onPause() F1-onStop() F1-onDestroyView() V1-onDetachedFromWindow() //创建第一个fragment视图,继续生命周期回调 F4-onCreateView() V4-onFinishInflate() V4-onAttachedToWindow() F4-onViewCreated() F4-onActivityCreated() F4-onStart() F4-onResume() //View视图绘制 V4-onMesure() V4-onLayout() V4-onDraw()2、从第三个Fragment切换到第二个Fragment
//恢复第一个Fragment的视图 F1-onCreateView() V1-onFinishInflate() V1-onAttachToWindow() F1-onViewCreated() F1-onActivityCreated() //销毁第四个不在保存范围内的Fragment视图 F4-onPause() F4-onStop() F4-onDestroyView() V4-onDetachedFromWindow() //继续生命周期回调 F1-onStart() F1-onResume() //View视图绘制 V1-onMesure() V1-onLayout() V1-onDraw()网上挖出来的图,很直观。 FragmentPagerAdapter的Fragment管理:
FragmentStatePagerAdapter的Fragment管理:
默认情况下,ViewPager保留三个Frament的状态,但是通过setOffscreenPageLimit(int limit),可以调整预加载/缓存的数量,预先加载数 = limit,缓存数目= 2*limit +1 :
//默认的缓存页面数量(常量) private static final int DEFAULT_OFFSCREEN_PAGES = 1; //缓存页面数量(变量) private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; public void setOffscreenPageLimit(int limit) { //当我们手动设置的limit数小于默认值1时,limit值会自动被赋值为默认值1(即DEFAULT_OFFSCREEN_PAGES) if (limit < DEFAULT_OFFSCREEN_PAGES) { Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "+ DEFAULT_OFFSCREEN_PAGES); limit = DEFAULT_OFFSCREEN_PAGES; } if (limit != mOffscreenPageLimit) { //经过前面的拦截判断后,将limit的值设置给mOffscreenPageLimit,用于 mOffscreenPageLimit = limit; populate(); } }退出Activaty的时候,会按照ViewPager添加Fragment的顺序依次销毁Fragment,调用(Fragment.onDestoyView()——>View.onDetachFromWindow()——>Fragment.onDestroy()——>Fragment.onDetach(),对于未保存状态的Fragment,则直接从onDestroy()——>onDetach() )。
静态加载:xml布局内容属于静态加载,静态加载的View控件是跟随Activity的生命周期的。在Activity的setContentView()中按照深度优先的方式解析View树,创建View对象,在Fragment的onCreateView()中解析View树,然后将其view嵌至Fragment的fl_container中。静态加载的控件内容都是由Activity来管理,因此在Activity的xml布局中声明的View的detachFromWindow是在Activity调用detachFromWindow的时候调用,包括静态嵌入的fragment中的View。
动态加载:代码中加载(FMManager、addView等)属于动态加载,动态加载的方式下View的生命周期由其管理者来确定(容器ViewGroup通过addView、removeView会触发View的attachFromWindow和detachFromWindow)。这种情况下Fragment、View的生命周期都是由FragmentManager(对于View也可以是它的父容器ViewGroup)来管理,因此当Fragement销毁时,其内部的view会在它调用destroyView的时候触发detachFromWindow事件,而View会在其ViewGroup容器调用removeView的时候触发detachFromWindow。