最近做项目用到了懒加载,记录一下吧
ViewPager+Fragment的组合,用了无数遍了吧,尤其在有很多个Fragment的情况下,我们没必要把每一个Fragment都加载出来。虽然预加载可以提升一些体验,但是把我们没有看到的页面数据也加载了,大大降低了性能,浪费初始化资源。
什么是懒加载呢,说白了就是页面可见时再去加载
实现原理:
- Fragment的setUserVisibleHint()方法,此方法在onCreateView()之前执行。
- getUserVisibleHint()方法可以返回fragment是否是可见状态
- Fragment中定义两个boolean变量,分别标记是否加载过和View是否准备完毕。
关键代码:
public class LazyLoadFragment extends BaseFragment {
/** 懒加载,是否已经加载过数据, 此标志位只变化一次 */
private boolean isLazyLoaded;
/** 页面View是否准备完毕 */
private boolean isViewPrepared;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
isViewPrepared = true;
onLazyLoad();
}
@Override
public void onDestroyView() {
super.onDestroyView();
isViewPrepared = false;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
onLazyLoad();
}
/**
*此方法只会执行一次
*/
private void onLazyLoad() {
// 同时满足这三个条件,才会去加载数据
if (getUserVisibleHint() && isViewPrepared && !isLazyLoaded) {
isLazyLoaded = true;
// todo 加载数据
}
}
}
这里有两个问题:
1、为什么onLazyLoad()会在两个地方执行?
我们知道ViewPager默认显示第一页,然后不设置setOffscreenPageLimit()的情况下,会默认加载下一页,而setUserVisibleHint()是在onCreateView()之前执行的。
假设有5个Fragment
- 刚开始Fragment1和Fragment2先加载,因为setUserVisibleHint()的时候Fragment1的View还没有初始化完毕,所以Fragment1最终会执行onActivityCreated()方法中的onLazyLoad()去加载数据。而Fragment2并不可见,所以Fragment2并没有加载数据。
- 然后我们再切换到Fragment2,Fragment3会执行初始化,因为Fragment2在刚才已经初始化了,View已经初始化完毕,isViewPrepared标志位变化为true,Fragment2会直接执行setUserVisibleHint()中的onLazyLoad()方法去加载数据。
- 然后我们直接切换到fragment5,因为之前fragment5并没有初始化,所以它也会执行onActivityCreated()方法中的onLazyLoad()去加载数据。
在onActivityCreated()中执行onLazyLoad():在初始化第一个Fragment或者直接切换到没有初始化过的Fragment时
在setUserVisibleHint()中执行onLazyLoad():在切换到相邻的Fragment时,此Fragment之前已经初始化过View
2、onDestroyView()中为什么要把isViewPrepared置为false?
这个问题我切身遇到过,还是5个Fragment
刚开始初始化Fragment1和Fragment2,直接切换到Fragment5,然后再切换到Fragment2,直接程序崩溃
日志搞一下:
在切换到Fragment5之后,其实ViewPager就把Fragment1和Fragment2的View销毁了,执行了onDestroyView()方法,但是此时Fragment2的isViewCreated=true,所以在切换过去时执行了setUserVisibleHint()方法中的onLazyLoad(),而此时View都是null,如果加载数据在网络请求之前有直接对View操作的代码那就直接程序崩溃了。
总结
懒加载其实也没什么,理解了原理就觉得很容易了。