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?