最近项目中用到ViewPager+Fragment的形式构造UI,由于ViewPager的实现机制会先为后面未显示的Fragment提前加载数据,这样会造成没必要的重复请求,浪费用户浏览量。所以就需要用到懒加载。
而所谓的懒加载是指在Fragment的UI对用户可见时再加载数据,那怎么实现懒加载呢?通常的想法是查看Fragment的方法有没有当用户可见时调用的,通过翻阅官方文档找到一个方法可以解决我们的问题。public void setUserVisibleHint(boolean isVisibleToUser) 下面是官方对这个方法的注解:
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.
我们可以通过isVisibleToUser参数的值来判断是否已经对用户可见了,true表示对用户可见,false表示对用户不可见。那么setUserVisibleHint是在什么时候调用呢,下面是我写了个ViewPager+Fragment的demo所打印的日志
通过两个fragment的日志对比我们会发现setUserVisibleHint方法的调用时机并不确定,在第一个Fragment中是在onCreateView之前调用,而在第二个Fragment中是在onCreateView之后调用,这里之所以提到onCreateView是因为Fragment的视图是在onCreateView方法中创建的。如果直接在setUserVisibleHint的参数为true时加载数据,就会有一种可能,网络数据加载完后Fragment的视图还没创建,这时候我们无法把数据放置到view当中,如果代码写的不严谨的话程序会直接崩溃。
这时候我们就需要维护一个参数mViewCreated用来标识视图是否已经创建,只有当用户可见并且视图已经创建时才加载数据。这时候可以封装如下代码:
现在让我们回到fragment1日志图,会发现第一个Fragment的setUserVisibleHint调用时机都是在onCreateView之前,所以这样封装会造成一个问题,第一个Fragment的数据没有加载。那该如何处理呢?我们做以下修改,在onActivityCreated同样加载一遍数据。这样可以保证第一个Fragment和后面的Fragment都加载到数据,而由于setUserVisibleHint为true的调用时机后面的Fragment不会重复加载数据。我们做如下修改:
基本上写到这里就已经结束了,但通过使用我们发现一个问题,Fragment每次可见时都会加载一边数据,我们省流量的初衷并没有实现,下面我们做了如下修改:通过维护参数mLoadFinished来判断是否已经加载过数据,完整代码如下
之所以暴露出去个setLoadDataSuccess是为了防止数据没有加载成功。