ViewPager中预加载与懒加载

预加载

为了让用户在切换过程中不卡顿,安卓官方默认创建当前item时,会创建第二个item,确保用户滑动时第二个item已经被创建,保持viewpager的平滑移动的效果。所以实现了预加载。

  • viewpager.setCurrentItem(int item)
    设置当前显示第几个item
  • viewpager.setOffscreenPageLimit(int limit)
    limit参数默认是1,即使设置为0的话,默认值也为1(非当前显示页面)
    默认是预加载当前显示item的两侧的itemview
    如果是共5个item,当前显示在第3个item,则会缓存2,4的item
    如果移动到4item,则清除2item,缓存3,5item

懒加载

如果预加载多个页面的时,由于预加载的原因,多个页面同时会对网络进行请求,造成流量浪费,卡顿等问题,懒加载解决的问题就是让页面上一些信息进行延迟加载,不至于同时进行太多并发的请求等

所以引入懒加载概念

Fragment懒加载

  • setUserVisibleHint(boolean isVisibleToUser) 方法进行懒加载的控制(老办法,存在弊端)
    之前是通过回调这个方法对页面当前显示和不显示的状态监听。
    但是这个方法会在生命周期初始化执行之前就调用,是最先执行的方法,导致第一次执行时获取的boolean是false,并不是用户已经离开页面,而是页面还未初始化。
    当执行onCreate()方法后再回调setUserVisibleHint()返回的才是真实的状态值。
/** 
     * 判断是否是初始化Fragment 
     */  
    private boolean hasInitFragment = false;  
    @Override  
    public void setUserVisibleHint(boolean isVisibleToUser) {  
        super.setUserVisibleHint(isVisibleToUser);  
        //fragment中执行了onCreate方法后,isVisibleToUser为true,代表页面也已经显示
        if (isVisibleToUser) {  
            hasInitFragment = true;  
            Log.i(TAG,"界面显示");  
        } else {  
            if (hasStarted) {  
                hasInitFragment = false;  
                Log.i(TAG,"界面不显示");  
            }  
        }  
    }
  • setUserVisibleHint()方法调用缺点
    因为这个方法会在onAttach()生命周期之前最先调用,可能会造成一些控件未初始化就被调用的问题,应严格注意(比如网络请求等)
  • AndroidX下通过使用setMaxLifecycle(Fragment fragment, Lifecycle.State state)可以实现懒加载
    下文介绍总结

Viewpager中加载fragment如何实现懒加载

FragmentPagerAdapter与FragmentStatePagerAdapter构造方法增加了一个参数的传递

  • BEHAVIOR_SET_USER_VISIBLE_HINT
    通过回调setUserVisibleHint()方法,来判断fragment的状态的显示或隐藏,实现懒加载
  • BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
    通过此状态位的判断,在执行instantiateItem()方法时进行判断
    通过参数的判断,来控制fragment的生命周期函数走到哪里不再继续往下执行
    内部通过调用setMaxLifeCycle()方法实现
new ViewPagerAdapter(getSupportFragmentManager(),
                     FragmentPagerAdapter.BEHAVIOR_SET_USER_VISIBLE_HINT);
new ViewPagerAdapter(getSupportFragmentManager(),
                     FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
//根据mBehavior的状态位进行判断
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
    fragment.setUserVisibleHint(false);
}        
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
    mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}

Fragment中setMaxLifecycle使用总结

  • Lifecycle.State五种状态解释
  • INITIALIZING 初始状态
  • CREATED 已创建状态
  • ACTIVITY_CREATED 完全创建,但是没有started
  • STARTED 创建并启动,可见不可操作
  • RESUMED 创建启动并可操作

把生命周期方法从

onCreate -> onCretateView -> 
    onStart -> onResume -> onPause -> 
    	onStop -> onDestoryView -> onDestory

视为从小到大排序;

生命周期状态CREATED->STARTED->RESUMED视为从小到大排序;

  • CREATED状态

CREATED即已创建状态,狭义的理解是生命周期方法走到onCreate,如果当前fragment状态已大于CREATED,则会使fragment生命周期方法走到onDestoryView,如果小于CREATED,则走到onCreate;所以CREATED有两种情况;

  • STARTED状态

同理,STARTED状态也有两种情况,如果当前fragment状态已大于STARTED,则会使fragment生命周期方法走到onPause,如果小于CREATED,则走到onStart

  • RESUMED状态

RESUMED表示的状态比较特殊,只代表onResume状态,无论大到小还是小到大,最终都是停留到onResume状态;

setMaxLifecycle这个方法貌似也只在FragmentPagerAdapter和FragmentStatePagerAdapter的构造方法传入的参数有用到,查看其它的文章时好像并没有看到对这个方法的调用,所以关于每个状态的详细使用暂时就不去过多记录了

总结

在AndroidX包下使用的懒加载方案通过使用FragmentPagerAdapter与FragmentStatePagerAdapter构造方法的第二个参数控制。

在调用构造方法时传入下面的参数,在onResume()方法中去执行延迟加载的操作
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT