最近在写代码的时候发现封装好的类竟然没有可使用懒加载Fragment,结果viewpager切换时候因为缓存数据都不刷新而导致了很多问题。去网上找的懒加载总是不尽人意,偶然间发现微博的好像很好使,就想模仿的写一个试试。首先得先写出一个LazyFragment,再去结合其他的。
下面进入正题
1.首先我们得知道懒加载是在加载啥?
这个问题显得很愚蠢。但是想一下,懒加载到底是加载数据和视图
,还是数据
呢??(一开始我也想过这个问题。。。)当然是数据
啦,你怎么能阻止视图的加载呢!你是无法阻止Fragment的生命周期函数的执行的,所以只能让当前显示的Fragment加载数据,不显示不加载数据
2.怎么能知道当前页面是显示的这个Fragment呢?
在源码中有两个方法可以使用
在viewpager和fragment模式使用的
public void setUserVisibleHint(boolean isVisibleToUser) {}
和
在add+show+hide模式使用
public void onHiddenChanged(boolean hidden) {}
那么就先简单的试试看这两个方法好了
我写了一个Viewpager+Fragment模式的,缓存数量offscreenPageLimit为1
。
当打开app时,我们可以看到主页BadHomeFragment
的setUserVisibleHint()方法
执行了两次
!先返回false不可见,再返回true可见。而且不管在哪个Fragment中setUserVisibleHint()
都跑得比生命周期快

当切换到第二个Fragment

切回去主页Fragment,当已经跑过生命流程的Fragment再次显示时,只会走setUserVisibleHint()
(先忽略onHiddenChange方法)

这样的话,我们大概可以想到,我根据setUserVisibleHint()的可见状态
去加载数据不就完事了吗?
所以我们先这样写

在子Fragment中的loadData中调用接口获取数据,然后给控件赋值

结果就是!报错!!说你的控件为null,我都可见了为啥为null呢。因为在进入app时setUserVisibleHint
在生命周期前面,Fragment都没有加载布局,当然为null啦

那我加个变量判断一下布局有没有加载好不就行了?

结果呢?主页Fragment没有执行onLoadData
方法,点击TwoFragment
却执行了,为什么呢,因为setUserVisibleHint
更早啊,而TwoFragment
已经初始化过了,点击过去的时候才能正常加载数据。

所以我们必须在生命周期中再分发一次加载数据的事件,把加载数据提成一个方法

再来看看从开启app到点击到第三个Fragment的日志,大家都正常的加载了数据,好像还挺正常的

那再试试从第一个页面跳转到最后一个页面吧,会发现中间有些页面莫名的就调用了StopLoadData
函数???这显然有问题的,看来不能只是简单的用可见状态来分发了

我们在好好想一下,LoadData
是Fragment可见的时候调用,
StopLoadData
是Fragment不可见的时候调用。其实这样说并不完全,应该是从不可见状态到可见状态的时候
加载数据,可见状态到不可见状态的时候
停止。所以我们得用一个变量记录一下可见状态

可以看到在切换方面,分发的事件已经是正常的了
注意要在onStop
把currentVisibleStatus状态重置!

以上就是我们网上常见的懒加载了,但是在这里留下两个问题
- 在跳转到其他页面回来时,会怎么样?
- 在子Fragment中又有一个viewpager+Fragment又会怎么样?
哎,太长了,下次再写吧,有什么不对的,欢迎大家指正~
网友评论