2022-08-10 ViewPager+Fragment 关闭预加载

背景

Android开发中界面中常用的Tab+ViewPager+Fragment做多页面切换。

点击tab标签可以切换对应的ViewPager中加载的Fragment界面,并且在ViewPager中有预加载机制,比如用户选择一个个tab时,不仅加载这个tab对应的Fragment,还会加载这个tab左右两侧的Fragment,只不过这个Fragment还没有显示出来,所以用户并不可见,这个机制其实挺好用的,能增加用户的使用体验,每次进一个界面,再进旁边界面其实就可以不用等了。如果选择的是第一个tab,那么加载的就是这个Fragment,并且第2个Fragment也会加载,但是左边没有,那么就是加载2个Fragment,如果选择不是边界处(第一个和最后一个),那么就会加载其和其两侧的共3个Fragment。

但是在某些场景中我们并不需要默认的预加载,比如我选择了第1个tab,那么第2个Fragment中的数据已经加载好了,但是我在第1个Fragment中修改的数据,在第2个Fragment中也有使用,但是当我切换到底2个Fragment时,显示的数据是在修改之前的,因为这是在修改之前加载的。所以我并不想要这个预加载,想要每次进入这个Fragment时才加载数据。

方案

setOffscreenPageLimit

ViewPager提供了一个public void setOffscreenPageLimit(int limit)函数,修改预加载的量,这个预加载数量默认是1,所以每次预加载当前tab左右2侧各1个Fragment。但是当我把这个值改为0时,以为出现的是不会预加载的效果,但是结果并没有生效。

通过查看setOffscreenPageLimit()函数的源码,可以看到代码里面对参数进行了校验,如果小于默认的值,就会使用默认的值,并且这个默认的值是1,所以通过这个函数想要取消预加载没有效果。

private static final int DEFAULT_OFFSCREEN_PAGES = 1;

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();
    }
}

onResume

我们尝试通过Fragment的声明周期函数public void onResume()来处理每次界面加载的工作,但是这个函数走的是预加载的声明周期,在预加载的时候就会执行,很显然不够。

setUserVisibleHint

Fragment还有个函数public void setUserVisibleHint(boolean isVisibleToUser),重写这个函数里面的isVisibleToUser参数表示界面是否是用户可见,通过isVisibleToUser参数的真假,判断当前Fragment是否可见,这个函数与预加载机制无关,只有当前Fragment可见或者不可见的时候才会执行。

但是有个问题就是这个函数是在Fragment切换时才会执行,与Activity的切换无关,也就是说当我们在可见的Fragment中打开一个Activity,然后退出打开的Activity,setUserVisibleHint()函数并没有回调,当然这也不是我们想要的。但是发现了再Activity切换时会触发onResume()函数,这个函数的调用给了提示,我们可以将onResume()和setUserVisibleHint()结合起来使用。

onResume+setUserVisibleHint

结合起来的写法也很容易,就是同时覆写这2个函数,在setUserVisibleHint中判断如果是可见的,就用isResumed()判断当前Fragment是否加载,在onResume()函数中使用getUserVisibleHint()判断当前Fragment是否可见,也就是说当着2个条件同时满足,那么这个Fragment就是真正的可见,我们可以在这里处理你的业务。

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        if (isResumed()){
            resume();
        }
    }
}

@Override
public void onResume() {
    super.onResume();
    if (getUserVisibleHint()){
        resume();
    }
}

private void resume() {
    System.out.println("真正的可见");
}

你可能感兴趣的:(android,java,ui,android,studio,开发语言)