Fragment的setUserVisibleHint方法实现懒加载,但setUserVisibleHint 不起作用?

      我们在做应用开发的时候,一个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的源码

 

posted @ 2016-07-17 10:45  Leevey·L  阅读(11269)  评论(1编辑  收藏  举报