AndroidX更新后ViewPager懒加载的前世今生

本文探讨了在AndroidX更新后,如何处理ViewPager的懒加载问题。原来依赖于setUserVisibleHint()的方法已过期,建议使用FragmentTransaction.setMaxLifecycle()方法。介绍了BEHAVIOR_SET_USER_VISIBLE_HINT和BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT两种行为模式,以及如何在BaseFragment和子类中实现懒加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:最近开始新项目,计划转战到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有点儿东西,要不你也赶紧试试,究极变化一下!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值