说在前面:
在实际开发中,我们常常会有使用ViewPager+Fragment来实现滑动切换的需求,但是ViewPager在默认情况下是会对当前Fragment相邻单位为1 的其它Fragment进行预加载。有时候我们的需要可能不需要预加载另外两个界面,那我们就有了懒加载这个需求。(这里不对懒加载和预加载进行好坏的区分,因为在不同业务有不同的需求)
了解过ViewPager的同学们可能会知道 ViewPager有自己的设置缓存数量的方法setOffscreenPageLimit 。但是这个方法有个问题就是,他设置的缓存数量不能少于1个,当少于一个的时候会默认为1个。(这里避免篇幅太大就不贴代码了),既然ViewPager改变不了,那我们就改变Fragment!!
想要实现懒加载的需求,我们可能先准备一下Fragment在ViewPager中生命周期的调用情况,以及对setUserVisibleHint方法的了解。
Fragment在ViewPager中的生命周期 与 setUserVisibleHint
先说一下setUserVisibleHint方法吧
这个方法是在Fragment在onAttach之前就会被调用的,看名字也能猜到是用来设置对用户可见性的。
我们可以利用getUserVisibleHint()获得当前可见性,这个在后面我们实现懒加载中是比较重要的一个点。
然后就是Fragment在ViewPager中的生命周期的调用
假设有两个Fragment f0 和 f1,ViewPager默认预加载缓存为1;
那么这两个Fragment的生命周期将会是交错的,它们并不会说先加载完f0 再去缓存f1,而是交错回调,而且都会走到onResume,唯一的区别在于f0的getUserVisibleHint() 为true(f0为可见),而f1为false。并且当我们滑到f1时,也只会执行setUserVisibleHint方法
上面这个也是为什么我们能简单的通过判断生命周期来进行懒加载。
具体的生命周期日志可以自己去打印一下,加深印象。
开始我们的实现
先明确我们的需求:只有滑到该Fragment时才去加载数据
public class LazyloadFragment extends baseFragment {
private boolean isViewPrepared; // 标识fragment视图已经初始化完毕
private boolean hasFetchData; // 标识已经触发过懒加载数据
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
lazyFetchDataIfPrepared(); //经过了预加载页面, 然后展示
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewPrepared = true; //标识View加载完成
lazyFetchDataIfPrepared(); //当首次进入到ViewPager指定的首页时,该首页并没有预加载。所以现在得再次调用
}
//需要注意的是 onViewcreated方法并不在生命周期中,只是在onCreateView执行后会被调用
/**
* 懒加载方法,获取数据什么的放到这边来使用,在切换到这个界面时才进行网络请求
*/
private void lazyFetchDataIfPrepared() {
// 用户可见fragment && 没有加载过数据 && 视图已经准备完毕
if (getUserVisibleHint() && !hasFetchData && isViewPrepared) {
hasFetchData = true; //已加载过数据
lazyInit();
}
}
/**
* 执行需要懒加载的方法
* 子类必须实现
*/
abstract void lazyInit() {
}
@Override
public void onDestroyView() {
super.onDestroyView();
hasFetchData = false;
isViewPrepared = false;
}
}
这里我们为什么要标识View是否加载呢? 是因为在onCreateView方法被调用之前setUserVisibleHint方法就被调用了,如果这里不进一步判断View是否加载完成,那就会报Null。
为什么要在onViewCreated再调用一次呢? 这是因为ViewPager首页首次进入并没有预加载,view加载完成标识为flase,在setUserVisibleHint方法中就不会加载数据了,所以要再次调用。
那不会造成重复获取数据吗?我们这里考虑到了,所以使用了数据加载完成标识符,只有加载符为false才会成功调用。
总得来说数据加载必须满足三点 :fragment可见、view加载完成、数据未加载。