2020-06-20

自定义Fragment实现懒加载功能

本示例使用的android sdk编译版本是26.0.2,Fragment使用的是support-v4包中的。这里介绍的懒加载效果是指Fragment在FragmentPagerAdapter这种场景下的实现(关于通过FragmentManager方式添加Fragment到Activity中实现懒加载效果这里暂不介绍)。先看实现效果,动态图安排上!


lazy_load.gif

爬坑指南

常说的懒加载一般是指Fragment可见的时候才加载数据,以前一直没搞懂Fragment懒加载怎么实现的,只知道跟Fragment的setUserVisibleHint方法有关,关键Fragment还有一个onHiddenChanged方法,当时认为这两个方法需要配合使用才能实现懒加载效果(东西多了才好操作吗!蠢啊),于是动手开始干,又是打日志又是断点调试,忙活一天把自己搞的迷迷糊糊的,反而越弄思路越乱。最后绕了一圈决定从源码入手,查看到底每个方法咋执行的,最后还是源码香啊!

核心分析

本着精简的原则,就不在这里介绍源码的探索之旅了,一切以最快、最简单的原则讲清楚懒加载效果实现原理。首先声明:这里介绍的懒加载效果跟onHiddenChanged(boolean hidden)无关,跟setUserVisibleHint(boolean isVisibleToUser)紧密相关。为简化内容,下面用vp代替ViewPager。

  1. fragment 可见和不可见 状态切换时会调用setUserVisibleHint(boolean isVisibleToUser),可见时isVisibleToUser=true,不可见时isVisibleToUser=false。
  2. vp第一个fragment被实例化时方法执行顺序:setUserVisibleHint(false)—>setUserVisibleHint(true)—>onAttach—>onCreate—>onCreateView—>onViewCreated—>onActivityCreated—>onStart—>onResume。
  3. 由于vp的预加载机制,第二个fragment会被提前实例化,方法执行顺序:setUserVisibleHint(false)—>onAttach—>onCreate—>onCreateView—>onViewCreated—>onActivityCreated—>onStart—>onResume。
  4. 当vp有多个fragment时,如果点击TabLayout切换到另一个未被实例化的fragment时,要显示的那个fragment方法执行顺序跟第2步相同。
  5. vp中已经被实例化过的fragment划出预加载范围时,方法执行顺序:onPause—>onStop—>onDestroyView。
  6. vp中已经被实例化过的fragment从预加载范围外划进预加载范围时,方法执行顺序:onCreateView—>onViewCreated—>onActivityCreated—>onStart—>onResume。

注:fragment实例化是指fragment对象被创建;vp(设置的适配器:FragmentPagerAdapter)中的fragment在滑出预加载范围时视图会被销毁,但是实例还在。

实现思路

  1. 首先需要fragment可见,这个可以在setUserVisibleHint来判断。
  2. 其次是视图需要构建完毕,这个可以在onCreateView中判断。
  3. 当fragment视图由销毁再到重建,这个时候不再重新加载数据,只需要利用缓存数据重新绑定View即可。

下面贴出代码,来了,来了...

public abstract class LazyLoadFragment extends Fragment {

    /**
     * 初始化数据必需是可见状态、视图构建完毕,数据自动加载过一次后就不进行再次自动加载(被动加载允许)视图销毁后再次创建的话才重新绑定数据
     * 该实现需要三个值判断:视图构建完毕否、页面可见否、数据加载过否、
     */
    private boolean isVisibleToUser = false;//视图是否可见
    private boolean viewRebuild = true;//页面是否为重建
    private boolean alreadyLoaded = false;//是否已经加载过数据

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        initData();
    }

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

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        viewRebuild = true;
        findView(view);
        initListener();
        initData();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    private void initData() {
        if (isVisibleToUser && viewRebuild && !alreadyLoaded) {
            alreadyLoaded = true;
            viewRebuild = false;
            firstLoad();
            return;
        }
        if (isVisibleToUser && viewRebuild) {
            viewRebuild = false;
            rebindData();
        }
    }

    protected abstract int getContentView();//添加布局文件

    protected abstract void findView(View container);//初始化view

    protected abstract void initListener();//设置监听

    protected abstract void firstLoad();//第一次加载数据

    protected abstract void rebindData();//重新绑定数据
}

这里我把懒加载功能的fragment封装了一下,大家使用的时候可以直接继承这个类就可以了。下面贴出实现demo地址:https://github.com/AndroidFirstDeveloper/DevelopProject

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。