Viewpager和Fragment的懒加载机制

2020-07-19  本文已影响0人  Aaron大宝剑

一、背景

ViewPager默认加载当前页面,而且预加载当前页面的前后两个页面数据(即同时会加载3个页面的数据),如果3个页面都有网络请求,就会影响性能,影响用户体验,由此,懒加载就尤为重要了,可以在滑到哪个fragment的时候,该fragment再进行网络请求。

二、懒加载

所谓的懒加载,其实也就是延迟加载,就是等到该页面的UI展示给用户时,再加载该页面的数据(从网络、数据库等),而不是依靠ViewPager预加载机制提前加载两三个,甚至更多页面的数据.这样可以提高所属Activity的初始化速度,也可以为用户节省流量。

三、懒加载方案

1、通过ViewPager的setOffscreenPageLimit(int limit)

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

该方法不可行,因为查看源码发现无论怎么设置,默认预加载页面数都是1,也就是说即使limit设置为0,最终还是默认为1。

2、setUserVisibleHint(boolean isVisibleToUser)

Fragment为我们提供了一个方法setUserVisibleHint(boolean isVisibleToUser),其中的参数isVisibleToUser就是表示该Fragment的UI对于用户是否可见。

所以可以重写此方法,然后根据回调的isVisibleToUser参数来进行相关的逻辑判断,以达到懒加载的效果。如果isVisibleToUser为true的话表示当前Fragment对用户可见,此时再去加载页面数据。由于ViewPager内会装载多个Fragment,而这种懒加载机制对于各个Fragment属于共同操作,因此适合将其抽取到BaseFragment中.

但是注意:

setUserVisibleHint(boolean isVisibleToUser)方法会多次回调,而且可能会在onCreateView()方法执行完毕之前回调。如果isVisibleToUser为true,然后进行数据加载和控件数据填充,但是onCreateView()方法并未执行完毕,此时就会出现NullPointerException空指针异常.

基于以上原因,进行数据懒加载的时机需要满足两个条件:

所以在BaseFragment中用两个布尔型标记来记录这两个条件的状态.只有同时满足了,才能加载数据。

四、懒加载的实现

public abstract class BaseFragment extends Fragment {
    // 视图加载完成标志位
    private boolean isViewCreated;
    // 视图对用户可见标志位
    private boolean isVisible;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
       return inflater.inflate(getFragmentView(), container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // fragment视图加载完成,设置视图加载完成标志位
        isViewCreated = true;
        // 可以开启懒加载
        lazyLoad();
    }

    // 该方法是在onCreate方法之前调用的
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser){
            isVisible = true;
            lazyLoad();
        }else {
            isVisible = false;
        }
    }

    private void lazyLoad(){
        /**
         * 牢记懒加载的2个重要条件:
         * 1、fragment视图已经加载完成
         * 2、fragment视图对用户可见了
         *
         * 所以,根据2个标志位进行判断
         */
        if (isViewCreated && isVisible) {
            loadData();
            // 数据加载后重置标志位,避免重复加载
            isVisible = false;
            isViewCreated = false;
        }
    }

  
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        // fragment视图销毁时也重置标志位
        isVisible = false;
        isViewCreated = false;
    }

    protected abstract void loadData();
    protected abstract int getFragmentView();
}
上一篇下一篇

猜你喜欢

热点阅读