ViewPager懒加载与Fragment懒加载

ViewPager懒加载与Fragment懒加载

什么是懒加载

懒加载是说白了就是延迟加载,对于数据和UI就是在需要的时候再加载展示给用户,什么是需要的时候对于UI来说就是要展示这个UI给用户的时候,在ViewPager与Fragment结合使用的时候就是在Fragment为当前要展示的界面时就是需要的时候

再次也说一下预加载的概念,预加载就是在当前并不需要之后的某个时间需要的加载模式,常用的地方有ART的预加载,ListView的预加载

ViewPager加载当前与相邻item方法为populate(),有mOffscreenPageLimit属性控制前后加载,mOffscreenPageLimit改变可以使用setOffscreenPageLimit(int limit)方法进行设置,看一下方法的源码

public void setOffscreenPageLimit(int limit) {
	if (limit < DEFAULT_OFFSCREEN_PAGES) {
        Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
                + DEFAULT_OFFSCREEN_PAGES);
        limit = DEFAULT_OFFSCREEN_PAGES;
    }
    if (limit != mOffscreenPageLimit) {
        mOffscreenPageLimit = limit;
        populate();
    }
}

可以发现如果设置的limit小于DEFAULT_OFFSCREEN_PAGES的话limit会被置换成DEFAULT_OFFSCREEN_PAGES的值,DEFAULT_OFFSCREEN_PAGES的值为1。

通过上面的介绍我们可以知道,简单的通过setOffscreenPageLimit(int limie)方法无法进行ViewPager的懒加载。因此我们需要在Fragment上做文章。

Fragment提供了一个setUserVisibleHint(boolean isVisibleToUser)方法,其中的参数isVisibleToUser就是标识该Fragment对用户是否可见

/**
 * Set a hint to the system about whether this fragment's UI is currently visible
 * to the user. This hint defaults to true and is persistent across fragment instance
 * state save and restore.
 * /
public void setUserVisibleHint(boolean isVisibleToUser) {
    if (!mUserVisibleHint && isVisibleToUser && mState < STARTED
            && mFragmentManager != null && isAdded()) {
        mFragmentManager.performPendingDeferredStart(this);
    }
    mUserVisibleHint = isVisibleToUser;
    mDeferStart = mState < STARTED && !isVisibleToUser;
    if (mSavedFragmentState != null) {
        // Ensure that if the user visible hint is set before the Fragment has
        // restored its state that we don't lose the new value
        mSavedUserVisibleHint = mUserVisibleHint;
    }
}

通过源码和注释可以知道,该方法实现了FragmentManager的延迟启动Fragment动作和保存状态动作。看注释知道Fragment的UI对用户是否可见的状态该百年时,系统都会回调此方法。

因此我们做延迟加载的话可以在setUserVisibleHint(boolean isVisibleToUser)方法上做文章,但是这个方法有一个坑,在第一次的时候ViewPager会先调用adapter的setUserVisibleHint(boolean isVisibleToUser)方法后调用onCreateView方法,所以做延迟加载需要符合两个条件,onCreateView执行完,setUserVisibleHint方法的参数为true。

因此可以重写两个方法,onViewCreated和setUserVisibleHint。

private var isViewCreated = false
private var isUIVisible = false

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    isViewCreated = true
    lazyLoad()
}

override fun setUserVisibleHint(isVisibleToUser: Boolean) {
    super.setUserVisibleHint(isVisibleToUser)
    isUIVisible = isVisibleToUser
    if (isUIVisible)
        lazyLoad()
}

fun lazyLoad() {
    if (isViewCreated && isUIVisible) {
        isViewCreated = false
        isUIVisible = false
    }
}

至此,ViewPager与Fragment结合使用的懒加载就结束了

下面为扩展知识

为什么通过setUserVisibleHint可以知道当前Fragment是否显示,如何实现的。

我们要想知道这个,需要先知道ViewPager是如何加载adapter中的数据的。我们知道ViewPager是使用的经典的适配器模式进行编写的,它的配套适配器是PagerAdapter,这是一个抽象类,直接继承自Object。该类中有一个setPrimaryItem方法,此方法在ViewPager的populate方法中会调用,populate相信很多人都会,是对于页面的创建与销毁,如果当前的iteminfo不为null则会触发Adapter.setPrimaryItem方法,此方法会传入当前iteminfo的object,对于PagerAdapter就是instantiateItem方法返回的Object,但是在PagerAdapter中setPrimaryItem并没有实现逻辑,但是在FragmentPagerAdapter和FragmentStatePagerAdapter中实现了setPrimaryItem的逻辑,如下

@Override
@SuppressWarnings("ReferenceEquality")
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

将传进来的object强转成Fragment,判断与当前的mCurrentPrimaryItem是否是一个,如果不是调用mCurrentPrimaryItem的setMenuVisibility和setUserVisibleHint方法,传入false,告知mCurrentPrimaryItem移除界面,并调用传入的Fragment的上述两个方法,告知其显示在界面中,最后将传入的fragment设置给mCurrentPrimaryItem进行保存。

多读源码有助成长!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值