我们在做应用开发的时候,一个Activity里面可能会以viewpager(或其他容器)与多个Fragment来组合使用,而如果每个fragment都需要去加载数据,或从本地加载,或从网络加载,那么在这个activity刚创建的时候就变成需要初始化大量资源。这样的结果,我们当然不会满意。那么,能不能做到当切换到这个fragment的时候,它才去初始化呢?
答案就在Fragment里的setUserVisibleHint这个方法里。请看关于Fragment里这个方法的API文档:

该方法用于告诉系统,这个Fragment的UI是否是可见的。所以我们只需要继承Fragment并重写该方法,即可实现在fragment可见时才进行数据加载操作,即Fragment的懒加载。根据网友们提供的方法,代码如下(本人稍作修改了下):

 1 import android.os.Bundle;
2 import android.support.v4.app.Fragment;
3
 4 /**
 5  * Author: wangjie
6 * Email: tiantian.china.2@gmail.com
7 * Date: 1/23/15.
8 */
 9 public abstract class BaseLazyFragment extends Fragment {
10 private static final String TAG = BaseLazyFragment.class.getSimpleName();
11 private boolean isPrepared;
12
13     @Override
14 public void onActivityCreated(Bundle savedInstanceState) {
15 super.onActivityCreated(savedInstanceState);
16 initPrepare();
17 }
18
19
20     /**
21      * 第一次onResume中的调用onUserVisible避免操作与onFirstUserVisible操作重复
22 */
23     private boolean isFirstResume = true;
24
25     @Override
26 public void onResume() {
27 super.onResume();
28 if (isFirstResume) {
29 isFirstResume = false;
30 return;
31 }
32 if (getUserVisibleHint()) {
33 onUserVisible();
34 }
35 }
36
37     @Override
38 public void onPause() {
39 super.onPause();
40 if (getUserVisibleHint()) {
41 onUserInvisible();
42 }
43 }
44
45     private boolean isFirstVisible = true;
46 private boolean isFirstInvisible = true;
47
48     @Override
49 public void setUserVisibleHint(boolean isVisibleToUser) {
50 super.setUserVisibleHint(isVisibleToUser);
51 if (isVisibleToUser) {
52 if (isFirstVisible) {
53 isFirstVisible = false;
54 initPrepare();
55 } else {
56 onUserVisible();
57 }
58 } else {
59 if (isFirstInvisible) {
60 isFirstInvisible = false;
61 onFirstUserInvisible();
62 } else {
63 onUserInvisible();
64 }
65 }
66 }
67
68     public synchronized void initPrepare() {
69 if (isPrepared) {
70 onFirstUserVisible();
71 } else {
72 isPrepared = true;
73 }
74 }
75
76     /**
77      * 第一次fragment可见(进行初始化工作)
78 */
79     public abstract void onFirstUserVisible();
80
81     /**
82      * fragment可见(切换回来或者onResume)
83 */
84     public abstract void onUserVisible();
85
86     /**
87      * 第一次fragment不可见(不建议在此处理事件)
88 */
89     public abstract void onFirstUserInvisible();
90
91     /**
92      * fragment不可见(切换掉或者onPause)
93 */
94     public abstract void onUserInvisible();
95
96 }

如上代码,使用setUserVisibleHint方法作为回调的依据,
暴露出来让子类使用的新的生命周期方法为:

- onFirstUserVisible();
第一次fragment可见(进行初始化工作)

- onUserVisible(); 
fragment可见(切换回来或者onResume)

- onFirstUserInvisible();
第一次fragment不可见(不建议在此处理事件)

- onUserInvisible();
fragment不可见(切换掉或者onPause)

据说具体的效果是:

1. 首先加载ViewPager,回调FragmentA(第一个默认呈现的Fragment)的onFirstUserVisible(),可以在这里进行FragmentA的初始化工作,其他Fragment保持不变。

2. 用户从FragmentA滑动到FragmentB,回调FragmentA的onUserInvisible()、FragmentB的onFirstUserVisible()(因为第一次切换到FragmentB,可以在这里进行初始化工作)。

3. 用户从FragmentB滑动到FragmentC,回调FragmentB的onUserInvisible()、FragmentC的onFirstUserVisible()(因为第一次切换到FragmentC,可以在这里进行初始化工作)。

4. 用户从FragmentC滑动到FragmentB,回调FragmentC的onUserInvisible()、FragmentB的onUserVisible()(因为FragmentB之前已经被加载过)。

5. 因为到此为止,suoyou的Fragment都已经被加载过了,所以以后这3个Fragment互相任意切换,只会回调原来Fragment的onUserInvisible()和切换后的Fragment的onUserVisible()。

6. 用户处于FragmentB,关闭手机屏幕,回调FragmentB的onUserInvisible()。

7. 用户处于FragmentB,手机屏幕处关闭状态,然后开启手机屏幕解锁,只回调FragmentB的onUserVisible()。

可我TM无论怎么调试都没这个效果好吗,TMD setUserVisibleHint()就是不调用,不执行!!!

问度娘TMD都有是千篇一律的是使用fragment的setUserVisibleHint()方法实现懒加载,使用fragment的setuservisiblehint ()方法实现懒加载,使用fragment的setUserVisibleHint()方法实现懒加载;我去!!!我都快崩溃了好吗。

无果只能求助国外的网友了,竖上梯子问google(搜索 fragment setuservisiblehint not called)我的男神去了,打开第一条搜索结果,这个结果是我的另一个男神:,这就是我正想要的,国外的网友给的答案如下:

答案大致意思是:需要 FragmentPagerAdapter 显示的对setUserVisibleHint()方法的调用,查看自己的adapter原来是继承的PagerAdapter 而不是FragmentPagerAdapter,于是果断重新生成一个继承 FragmentPagerAdapter 的 adapter,

代码如下:

 1
 3 import android.support.v4.app.Fragment;
4 import android.support.v4.app.FragmentManager;
5 import android.support.v4.app.FragmentPagerAdapter;
6
 7 import java.util.ArrayList;
8 import java.util.List;
9
10 public class SimpleFragmentPagerAdapter  extends FragmentPagerAdapter {
11 private List<Fragment> listFragments;
12 private List<String> mTitleList = new ArrayList<>();//页卡标题集合
13
14     public SimpleFragmentPagerAdapter(FragmentManager fm,
15 List<Fragment> al,
16 List<String> titleList) {
17 super(fm);
18 listFragments = al;
19 mTitleList = titleList;
20 }
21
22     public SimpleFragmentPagerAdapter(FragmentManager fm) {
23 super(fm);
24 }
25
26     @Override
27 public Fragment getItem(int position) {
28 return listFragments.get(position);
29 }
30
31     @Override
32 public int getCount() {
33 return listFragments.size();
34 }
35
36     @Override
37 public int getItemPosition(Object object) {
38 return super.getItemPosition(object);
39 }
40
41     @Override
42 public CharSequence getPageTitle(int position) {
43 return mTitleList.get(position);//页卡标题
44     }
45 }

然后将该adapter赋予Viewpager ,经调试成功了,setUserVisibleHint()方法终于起作用了,懒加载也有了。

项目源码:https://github.com/Leevey/LazyLoadFragment

参考文献:

实现类似微信的延迟加载的Fragment——LazyFragment

stackoverflow:Is Fragment.setUserVisibleHint() called by the android System?

FragmentPagerAdapter.java的源码

Fragment的setUserVisibleHint方法实现懒加载,但setUserVisibleHint 不起作用?的更多相关文章

  1. Fragment的setUserVisibleHint方法实现懒加载

    public abstract class LazyFragment extends Fragment {     protected boolean isVisible;     /**       ...

  2. OC中重写set和get方法、懒加载

    在写OC程序的时候,在很多时候我们会用到重写set或者get方法,重写这两个方法大多是用于刷新数据,比如懒加载. 意思就是说当你去调用set或者get方法时,系统会去调用重写的get或者set方法,这 ...

  3. swift 基础小结02 -- VFL约束、属性的get和set方法、懒加载、方法替换

    一.属性的get和set方法          1.自定义属性的set和get方法          private(set) var _image:UIImage?     //自定义属性get,s ...

  4. iOS之weak和strong、懒加载及循环引用

    一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...

  5. 【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】

    一.Session概述 1.Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法. 2.理解Sessi ...

  6. hibernate懒加载(转载)

    http://blog.csdn.net/sanjy523892105/article/details/7071139 懒加载详解 懒加载为Hibernate中比较常用的特性之一,下面我们详细来了解下 ...

  7. 关于懒加载(lazy loading)

    懒加载---即为延迟加载,顾名思义在需要的时候才加载,这样做效率会比较低,但是占用内存低,iOS设备内存资源有限,如果程序启动使用一次性加载的方式可能会耗尽内存,这时可以使用懒加载,先判断是否有,没有 ...

  8. 【IOS学习基础】weak和strong、懒加载、循环引用

    一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...

  9. iOS开发基础-图片切换(4)之懒加载

    延续:iOS开发基础-图片切换(3),对(3)里面的代码用懒加载进行改善. 一.懒加载基本内容 懒加载(延迟加载):即在需要的时候才加载,修改属性的 getter 方法. 注意:懒加载时一定要先判断该 ...

随机推荐

  1. 关于GPL协议的理解(开源与商用、免费与收费的理解)

    编者:请特别注意看暗红色粗体标注的那几句话,总结下来有下面几点: 如果你用了我的 GPL软件,那么你的软件也必须要开源,否则就不能使用我的软件,你是否把你的软件商用和我没关系 Oracle 卖的不是软 ...

  2. 用格式工厂将mts文件转换成其它格式flv,mpg失败

    通常情况下,是由帧速率的改变引起的! 看一看你的MTS帧速率是多少,则转换成FLV时,帧速率要一样!----------  这是非常重要的!!!

  3. Jenkins CI CD

    原文:https://www.sunjianhua.cn/archives/jenkins-ci-cd.html 1.安装git 以下为简单应用,适合无gitlab服务器用户. #在git服务器(19 ...

  4. VisualStudio:如何监控 ADO.NET?

    背景 很多场景下我们都需要监控 ADO.NET,如:查看某些框架(ORM)生成的 SQL.如何在不能使用 SQL Profile 的情况下监控 SQL 呢?VS 为我们提供了一个工具,本文做一些介绍! ...

  5. 深入浅出!从语义角度分析隐藏在Unity协程背后的原理

    Unity的协程使用起来比较方便,但是由于其封装和隐藏了太多细节,使其看起来比较神秘.比如协程是否是真正的异步执行?协程与线程到底是什么关系?本文将从语义角度来分析隐藏在协程背后的原理,并使用C++来 ...

  6. Kubernetes基础:Pod的详细介绍

    本文的演练环境为基于Virtualbox搭建的Kubernetes集群,具体搭建步骤可以参考kubeadm安装kubernetes V1.11.1 集群 1. 基本概念 1.1 Pod是什么 Pod是 ...

  7. [转]cocos2d-x

    Cocos2d-x 是一个支持多平台的 2D 手机游戏引擎,使用 C++ 开发,基于OpenGL ES,基于Cocos2d-iphone,支持 WOPhone, iOS 4.1, Android 2. ...

  8. 数据库分库分表中间件:Mycat;分布式数据库;mysql的分布式事务

    官网:http://mycat.io/,里面有电子书籍可以下载:http://www.mycat.io/document/mycat-definitive-guide.pdf 旧版本下载地址:http ...

  9. 在SqlServer 中解析JSON数据 [parseJSON] 函数 数据库中 解析JSON

    使用如下: SELECT * FROM parseJSON('{ "联系人": { "姓名": "huang", "网名" ...

  10. 秒懂,Java 注解 (Annotation)你可以这样学

    转自: https://blog.csdn.net/briblue/article/details/73824058 文章开头先引入一处图片. 这处图片引自老罗的博客.为了避免不必要的麻烦,首先声明我 ...