Activity和Fragment各自理论上的生命周期

  • Activity的生命周期是较为经典也最清晰的,在此不表;
  • Fragment从出现到广泛运用也有一段时间了,其标准生命周期也仅比Activity多出一些流程,如onCreateView();

  • Activity和Fragment在实际编码中必定是结合出现的,表现为Activity作为容器,装载有一个或若干个Fragment;
  • 装载多个Fragment时,经常使用TabHost和Viewpager作为载体;
  • 在实际编码中发现,Activity和Fragment的混合情况里,其生命周期的交叉可能与预想中有差别;

  • 使用如下方式加载Fragment时:

     
    1. getSupportFragmentManager()
    2. .beginTransaction()
    3. .add(R.id.fragment_container, mFragment, SHARE_PUBLIC_LIST_FRAGMENT_TAG)
    4. .commitAllowingStateLoss();
    
    
     

    其onResume和onPause执行过程为:

    • Activity - onResume
    • Fragment - onResume
    • Activity - onPause
    • Fragment - onPause

友盟-页面统计要求

  • Activity和Fragment共同体页面统计中,需要保证线性不交叉,每个onPageStart都有一个onPageEnd配对,
  • 如:onPageStart ->onPageEnd-> onPageStart -> onPageEnd -> onPageStart ->onPageEnd
  • 这样才能保证每个页面统计的正确。

Viewpager中Fragment的生命周期

  • ViewPager装载Fragment一般使用FragmentPagerAdapter或FragmentStatePagerAdapter,同样借助FragmentManager,在adapter的getItem方法中根据position制定显示的fragment
  • 由于Viewpager的缓存特点,Viewpager启动时其第一个Fragment页面及待缓存的页面都将按顺序呢开始他们的正常生命周期,走向onResume,即:
    • Viewpager所在Activity - onResume
    • Fragment1 - onResume
    • Fragment2 - onResume
    • Fragment3 - onResume
  • 由于这若干个页面的生命周期被同时催化了,影响了我们的单一判断,即无法判断“真正”显示和消失在使用者眼前的页面。

解决方案

  • 方案1:设置Viewpager的缓存机制,不缓存除当前页以外的页面数据,所见即所得,离开即销毁;
  • 此方案对需求改动较大,且较影响用户体验;

  • 方案2:重载Fragment.onHiddenChanged(boolean hidden)方法,其参数hidden代表当前fragment显隐状态改变时,是否为隐藏状态,可通过check此参数作处理;
  • 此方案局限在于本方法的系统调用时间发生在显隐状态改变时,但第一次显示时此方法并不调用;

  • 方案3:重载Fragment.setUserVisibleHint(boolean isVisibleToUser)方法,其参数isVisibleToUser顾名思义最接近我们的需求,代表页面是否“真正”对使用者显示;
  • 此方案局限在于此方法的第一次系统调用甚至早于Fragment的onCreate方法,故其第一次调用时isVisibleToUser值总为false,影响我们对生命周期顺序的判定;
    • Fragment1 - isVisibleToUser - false (多余)
    • Fragment1 - isVisibleToUser - true
    • Fragment1 - isVisibleToUser - false
    • Fragment2 - isVisibleToUser - false (多余)
    • Fragment2 - isVisibleToUser - true
    • Fragment2 - isVisibleToUser - false

实际采用的解决方案

  • 根据对产品需求的理解和用户体验的统一,选择在方案3基础上加以改进;
  • setUserVisibleHint()方法本身很接近我们的需求,它的局限点我采取了一个侵入式的解决方式:

     
    1. protected boolean isCreated = false;
    2. @Override
    3. public void onCreate(Bundle savedInstanceState) {
    4. super.onCreate(savedInstanceState);
    5. // ...
    6. isCreated = true;
    7. }
    8. /**
    9. * 此方法目前仅适用于标示ViewPager中的Fragment是否真实可见
    10. * For 友盟统计的页面线性不交叉统计需求
    11. */
    12. @Override
    13. public void setUserVisibleHint(boolean isVisibleToUser) {
    14. super.setUserVisibleHint(isVisibleToUser);
    15. if (!isCreated) {
    16. return;
    17. }
    18. if (isVisibleToUser) {
    19. umengPageStart();
    20. }else {
    21. umengPageEnd();
    22. }
    23. }
    
    
     
  • 对onCreate方法结束的一个标记即可解决问题;

  • 切记:此标记的改变请勿放在Fragment的onActivtyCreate方法中,此方法调用滞后于setUserVisibleHint的判断

One more thing

  • Viewpager装载Fragment时还有另一个坑,Viewpager的父容器(Activity或Fragment)在显隐状态改变时,如在Activity的onResume和onPause调用时,并不会主动通知Viewpager内的Fragment执行其应用的生命周期,故我们需要再增加手动强制调用两次
  • 在Activity中查询到当前的Fragment,并执行其内方法,需要借助Viewpager,并改写其PagerAdapter;
  • 我采用了此文提到的Second Solution:如何获得ViewPager当前显示的Fragment?

友盟页面统计 - 关于Viewpager中的Fragment的生命周期的更多相关文章

  1. iOS之友盟错误统计解决

    http://www.cocoachina.com/ios/20150720/12627.html http://lieyunye.github.io/blog/2013/09/10/how-to-a ...

  2. 【转】WPF中的窗口的生命周期

    原文地址:http://www.cnblogs.com/Jennifer/articles/1997763.html WPF中的窗口的生命周期 WPF中所有窗口的基类型都是System.Windows ...

  3. Envoy 代理中的请求的生命周期

    Envoy 代理中的请求的生命周期 翻译自Envoy官方文档. 目录 Envoy 代理中的请求的生命周期 术语 网络拓扑 配置 高层架构 请求流 总览 1.Listener TCP连接的接收 2.监听 ...

  4. vue生命周期图示中英文版Vue实例生命周期钩子

    vue生命周期图示中英文版Vue实例生命周期钩子知乎上近日有人发起了一个 “react 是不是比 vue 牛皮,为什么?” 的问题,Vue.js 作者尤雨溪12月4日正面回应了该问题.以下是尤雨溪回复 ...

  5. React Native 中的component 的生命周期

    React Native中的component跟Android中的activity,fragment等一样,存在生命周期,下面先给出component的生命周期图 getDefaultProps ob ...

  6. spring-第八篇之容器中的bean的生命周期

    1.容器中的bean的生命周期 spring容器可以管理singleton作用域的bean的生命周期,包括bean何时被创建.何时初始化完成.何时被销毁.客户端代码不能控制该类型bean的销毁.spr ...

  7. 动态更新ViewPager中的Fragment(替换Fragment)

    1.最近做需求,遇到一个问题,一个Fragment中包含了一个ViewPager,viewPager中包含一adapter ,adapter中包含了4个Fragment.想要动态替换第3个Fragme ...

  8. ionic中关于ionicView 的生命周期

    当我们来回切换页面时候,视图被缓存下来,不用每次再去new一个新的视图,可以大大地提高性能.当跳出一个视图后,视图的元素被保存在DOM中,它的作用域也就不在$watch的作用域内,当我们访问一个已经被 ...

  9. Android中静态变量的生命周期

    静态变量的生命周期,起始于类的加载,终止于类的释放.什么时候类会加载呢?我们知道,在app打开时,会创建一个进程,然后初始化一个dvm的实例,负责类的加载释放 和 垃圾回收等.换句话说,在进程创建之后 ...

随机推荐

  1. ffmpeg-20160714-git-bin.7z

    ESC 退出 0 进度条开关 1 屏幕原始大小 2 屏幕1/2大小 3 屏幕1/3大小 4 屏幕1/4大小 S 下一帧 [ -2秒 ] +2秒 ; -1秒 ' +1秒 下一个帧 -> -5秒 f ...

  2. Excel保护工作表

    最近见到一个Excel文件,其中的表不能选中,不能编辑,今天研究了一下 明白了其设置方法 excel中开始--格式--保护工作表--去掉所有勾选,输入保护密码  即可

  3. [NSURLConnection]分别用Post和Get方式获取网络数据并把数据显示到表格

    @interface ViewController ()<UITableViewDataSource,UITableViewDelegate> { UIButton* getButton; ...

  4. MFC Initinstance中DoModal()返回-1

    新建一个基于对话框的MFC应用程序,在App的Initinstance中调用对话框DoModal()来显示对话框,这是框架的内容,应用程序框架生成的全部是正常的. 当把我对话框的资源文件提取到一个资源 ...

  5. FileUpload控件使用初步

    FileUpload控件使用初步   FileUpload控件使用初步: 1.实现文件上传 protected void btnSubmit_click(object sender, EventArg ...

  6. 【python】入门学习(二)

    键盘读取字符串: name = input('What is your first name?').strip()print("Hello " + name.capitalize( ...

  7. 【gsl】生成随机数

    来自:http://hsxqwanting.blog.163.com/blog/static/16945437201301042830815/ 使用GSL生成随机数时的三个步骤:    (1)gsl_ ...

  8. selinux

    root@lujie ~]# vim /etc/sysconfig/selinux # This file controls the state of SELinux on the system. # ...

  9. python基础——sorted()函数

    python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...

  10. MongoDB csv文件导入导出

    1.导出到csv文件: 2.从csv导入: 数据经过csv导出导入,有一个非常隐蔽的问题,编写代码时需要注意: 先导入一条数据: 其中Price是double类型: 然后我把该条记录导出到Demo.c ...