Android基础——控件的混合生命周期

    xiaoxiao2021-03-25  113

    一Activity下的Fragment生命周期 FragmentManager动态管理Fragment的生命周期 1Fragment自身生命周期2Fragment自身生命周期对View生命周期的影响 二Activity ViewPager Fragment View的生命周期 1启动Activity2滑动Fragment翻页21直观地比较FragmentPagerAdapter和FragmentStatePagerAdapter的区别3退出Activity 三小结

    一、Activity下的Fragment生命周期

    Android官方给出:基本情况下Activity与Fragment的生命周期对应关系如下图: 图1.0 静态布局情况下fragment与Activity的生命周期对应图

    这个生命周期的严格对应关系成立条件为:fragment通过静态布局的方式插入到Activity的布局中。但是通过FragmentManager动态管理的时候就有些许差别了。


    * FragmentManager动态管理Fragment的生命周期:*


    这里演示的是动态加载的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)Fragment自身生命周期

    阶段一:启动时 A-onCreate() F1-onAttach() F1-onCreate() F2-onAttach() F2-onCreate() F1-onCreateView() F1-onViewCreated() F1-onActivityCreated() F2-onCreateView() F2-onViewCreated() F2-onActivityCreated()\ F1-onStart() F2-onStart() A-onStart() A-onResume() F1-onResume() F2-onResume() A-onAttachedToWindow() 阶段二:按Home/菜单键 F1-onPause() F2-onPause() A-onPause() F1- onSaveInstanceState() F2-onSaveInstanceState() A-onSaveInstanceState() F1-onStop() F2-onStop() A-onStop() 阶段三:从阶段二返回 A-onRestart() F1-onStart() F2-onStart() A-onStart() A-onResume() F1-onResume() F2-onResume() 阶段四:直接按下Back键返回 F1-onPause() F2-onPause() A-onPause() F1-onStop() F2-onStop() A-onStop() F1-onDestroyView() F1-onDestroy() F1-onDetach() F2-onDestroyView() F2-onDestroy() F2-onDetach() A-onDestroy() A-onDetachedFromWindow()。

    可以看出,与图1.0所示的生命周期对应基本一样。

    (2)Fragment自身生命周期对View生命周期的影响

    任何一个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()时触发。


    二、Activity+ ViewPager+ Fragment+ View的生命周期


    ViewPager也是一个View,Fragment根ViewPager的结合其实也是通过FragmentManager来管理的,因此归结来说还是通过动态加载的方式来管理Fragment的生命周期。

    假设: 含有ViewPager的Activity:A; Fragment:F1、F2、F3、F4,通过FM交ViewPagerAdapter。 嵌在Fragment中的View:V1、V2、V3、V4

    (1)启动Activity:

    //Activity的启动 A-onCreate()——> A-onStart()——> A-onResume()——> A-onAttachedToWindow()——> //不一样的是在ViewPager显示后才加载Fragment //按照getItem中的顺序加载 F1-onAttach()——> F1-onCreate()——> F2-onAttach()——> F2-onCreate()——> //加载F1视图 F1-onCreateView()——> V1-onFinishInflate()——> V1-onAttachedToWindow()——> F1-onViewCreated()——> F1-onActivityCreated()——> F1-onStart()——> F1-onResume()——> //加载F2视图 F2-onCreateView()——> V2-onFinishInflate()——> V2-onAttachedToWindow()——> F2-onViewCreated()——> F2-onActivityCreated()——> F2-onStart()——> F2-onResume()——> //按照F1、F2的顺序绘制V1、V2 V1-onMeasure()——> V2-onMeasure()——> V1-onLayout()——> V2-onLayout()

    从上面我们可以看出 第一,与fragment被添加至Acvitity的时候不一样,fragment的构造是在Activity调用onAttachedToWindow()之后; 第二,预先加载了一个fragment,并且生命周期执行到了onResume()。

    (2)滑动Fragment翻页:

    关于这个的全部情况就不放在上面了,下面的例子是使用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()

    (2.1)直观地比较FragmentPagerAdapter和FragmentStatePagerAdapter的区别

    网上挖出来的图,很直观。 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(); } }

    (3)退出Activity:

    退出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。

    转载请注明原文地址: https://ju.6miu.com/read-17114.html

    最新回复(0)