前言:最近开始新项目,计划转战到AndroidX。虽然Android Support Library仍然支持,但是Android团队官方的态度也很明确,未来都会为AndroidX为主,Android Support Library已经不再建议使用,并会慢慢停止维护
viewPager为何会出现懒加载
- viewPager配合fragment,默认会加载左右两个fragment,我们称之为viewpager的预加载;有童鞋有话说,不是可以设置setOffscreenPageLimit(0)【手动滑稽】,请看下面代码片段:
public void setOffscreenPageLimit(int limit) {
if (limit < DEFAULT_OFFSCREEN_PAGES) {
// DEFAULT_OFFSCREEN_PAGES = 1,小于1时也等于1,所以setOffscreenPageLimit(0)无济于事
limit = DEFAULT_OFFSCREEN_PAGES;
}
//省略源码
}
- 这种奇葩组合导致fragment的生命周期并非严格意义一样,当预加载的fragment不可见时生命周期已经执行到了onResume();
- 那么这就导致了一个问题,如果用户没有滑到预加载的页面,直接关闭了,那不是白白浪费了用户的流量和咋们服务器的性能开销;因此,懒加载方案应运而生了。
懒加载前世到底何许人也
- fragemnt提供了一个setUserVisibleHint(boolean isVisibleToUser)方法,可以获取是否可见的状态;
- 增加一个是否可见的标志(visibleToUser),我不能让它每次可见都加载数据吧,增加一个标记位首次加载(firstload),为了确保不出问题,增加一个view创建好的标记(viewCreated);
- 下面是具体代码展示:
public abstract class BaseFragment extends Fragment {
/**
* 当前Fragment状态是否可见
*/
private boolean visibleToUser = false;
/**
* View是否已创建完成
*/
private boolean viewCreated = false;
/**
* 是否第一次加载数据
*/
private boolean firstLoad = true;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewCreated = true;
isLazyLoad();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
visibleToUser = isVisibleToUser;
isLazyLoad();
}
/**
* 判断是否开始懒加载
*/
private void isLazyLoad() {
if (visibleToUser && firstLoad && viewCreated) {
firstLoad = false;
onLazyLoad();
}
}
/**
* 懒加载
*/
protected abstract void onLazyLoad();
-
刚刚那位童鞋又坐不住了,既然setUserVisibleHint(boolean isVisibleToUser)方法里面有是否可见的标志干嘛要创建一个成员变量?isLazyLoad()方法又为什么分别要在onViewCreated()和setUserVisibleHint()各执行一次?
-
下面来一一解释:
①由于setUserVisibleHint()凌驾于所有生命周期方法之前,fragment创建时首先会执行一次,此时第一个fragment并不可见isVisibleToUser=false,紧接着又执行了一次isVisibleToUser=true,过后才会执行一系列的生命周期;此时,viewCreated还没有被置为true,setUserVisibleHint()方法中的isLazyLoad()并不会执行;让第一个fragment实现真正的执行isLazyLoad()在onViewCreated()方法里,因为此刻三个标志都置为true了;
②由于预加载的原因,第二个fragment的生命周期已经执行到了onResume(),viewCreated=true已经形成,当滑动到可见时onViewCreated(),已经不会再执行了,那么onViewCreated()中的isLazyLoad()是无法生效的;但是会触发setUserVisibleHint()方法且isVisibleToUser=true,这时此方法的isLazyLoad()生效,后面的fragment同理。
③所以,在setUserVisibleHint()和onViewCreated()方法中都需要isVisibleToUser,这才有了成员变量visibleToUser;onViewCreated()方法中的isLazyLoad()是使第一个fragment的onLazyLoad()生效,setUserVisibleHint()方法中的isLazyLoad()是使后面的fragment的onLazyLoad()生效。
-
onLazyLoad()需要在子类实现,进行具体的操作。
升级AndroidX
- 我以为前世今生都如同电视剧般,一切照搬过来后;一顿猛如虎的操作后,OK懒加载一样没问题;但是(下图):
- 很明显方法过期不推荐使用了,作为一个有强迫症的人来说不能忍,非要一探究竟,说不定还要更骚的操作;
探究懒加载今生骚气几何
- 点击进入在setUserVisibleHint()父类,有这么一句注释:@deprecated Use {@link FragmentTransaction#setMaxLifecycle(Fragment, Lifecycle.State)},意思此方法已过期使用FragmentTransaction类的setMaxLifecycle(Fragment, Lifecycle.State)方法代替;咋看上去有点儿厉害嗫,设置生命周期,其实大概也是这个意思;
- 今天不深入的究其原理,只聊在viewPager的使用,详细请看setMaxLifecycle;
- 生命周期的处理方式已经在FragmentPagerAdapter中为我们处理好了,传入对于参数使用就好了:
public FragmentPagerAdapter(@NonNull FragmentManager fm,
@Behavior int behavior) {
mFragmentManager = fm;
mBehavior = behavior;
}
- 这里需要传入一个behavior,取值有两种:
①、BEHAVIOR_SET_USER_VISIBLE_HINT:Fragment改变的时候,setUserVisibleHint方法会被调用,也就是这个参数其实是为了兼容以前的老代码,在代码中已有体现,这种就和前世一样的处理方式
@Deprecated
public FragmentPagerAdapter(@NonNull FragmentManager fm) {
this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
}
②、BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT:表示当前显示的Fragment会被执行到onResume,而其它参与预加载Fragment的生命周期都只会执行到onStart;
- 到这里就知道该如何处理懒加载了:
//adpater的构造函数中
public PagerFragmentAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
基类只需要创建一个是否第一次加载的变量在onResume()处理一下:
public abstract class BaseFragment extends Fragment {
/**
* 是否第一次加载数据
*/
private boolean firstLoad = true;
@Override
public void onResume() {
super.onResume();
//判断是否开始懒加载
if (firstLoad) {
firstLoad = false;
onLazyLoad();
}
}
/**
* 懒加载
*/
protected abstract void onLazyLoad();
同样在子类实现onLazyLoad(),完美解决懒加载,此时心情是这样的。
果然,AndroidX有点儿东西,要不你也赶紧试试,究极变化一下!