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

来源:互联网 发布:java 初始化常量 编辑:程序博客网 时间:2024/06/06 02:00

  • 一Activity下的Fragment生命周期
    • FragmentManager动态管理Fragment的生命周期
      • 1Fragment自身生命周期
      • 2Fragment自身生命周期对View生命周期的影响
  • 二Activity ViewPager Fragment View的生命周期
    • 1启动Activity
    • 2滑动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()——>//创建FragmentF1-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、V2V1-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

//预加载第四个FragmentF4-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。

0 0
原创粉丝点击