自定义Fragment实现懒加载功能
本示例使用的android sdk编译版本是26.0.2,Fragment使用的是support-v4包中的。这里介绍的懒加载效果是指Fragment在FragmentPagerAdapter这种场景下的实现(关于通过FragmentManager方式添加Fragment到Activity中实现懒加载效果这里暂不介绍)。先看实现效果,动态图安排上!
爬坑指南
常说的懒加载一般是指Fragment可见的时候才加载数据,以前一直没搞懂Fragment懒加载怎么实现的,只知道跟Fragment的setUserVisibleHint方法有关,关键Fragment还有一个onHiddenChanged方法,当时认为这两个方法需要配合使用才能实现懒加载效果(东西多了才好操作吗!蠢啊),于是动手开始干,又是打日志又是断点调试,忙活一天把自己搞的迷迷糊糊的,反而越弄思路越乱。最后绕了一圈决定从源码入手,查看到底每个方法咋执行的,最后还是源码香啊!
核心分析
本着精简的原则,就不在这里介绍源码的探索之旅了,一切以最快、最简单的原则讲清楚懒加载效果实现原理。首先声明:这里介绍的懒加载效果跟onHiddenChanged(boolean hidden)无关,跟setUserVisibleHint(boolean isVisibleToUser)紧密相关。为简化内容,下面用vp代替ViewPager。
- fragment 可见和不可见 状态切换时会调用setUserVisibleHint(boolean isVisibleToUser),可见时isVisibleToUser=true,不可见时isVisibleToUser=false。
- vp第一个fragment被实例化时方法执行顺序:setUserVisibleHint(false)—>setUserVisibleHint(true)—>onAttach—>onCreate—>onCreateView—>onViewCreated—>onActivityCreated—>onStart—>onResume。
- 由于vp的预加载机制,第二个fragment会被提前实例化,方法执行顺序:setUserVisibleHint(false)—>onAttach—>onCreate—>onCreateView—>onViewCreated—>onActivityCreated—>onStart—>onResume。
- 当vp有多个fragment时,如果点击TabLayout切换到另一个未被实例化的fragment时,要显示的那个fragment方法执行顺序跟第2步相同。
- vp中已经被实例化过的fragment划出预加载范围时,方法执行顺序:onPause—>onStop—>onDestroyView。
- vp中已经被实例化过的fragment从预加载范围外划进预加载范围时,方法执行顺序:onCreateView—>onViewCreated—>onActivityCreated—>onStart—>onResume。
注:fragment实例化是指fragment对象被创建;vp(设置的适配器:FragmentPagerAdapter)中的fragment在滑出预加载范围时视图会被销毁,但是实例还在。
实现思路
- 首先需要fragment可见,这个可以在setUserVisibleHint来判断。
- 其次是视图需要构建完毕,这个可以在onCreateView中判断。
- 当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