前言
本文会从头开始一步一步带你去写一个LazyFragment,根据写的过程中一步一步记录,你也可以自己试一试,跟着一起写写。最后也根据遇到的问题去完善了,网上搜的都是不完善的,还是自己写一个吧!
懒加载是在加载啥?
这个问题显得很愚蠢。但是想一下,懒加载到底是加载数据和视图
,还是数据
呢??(一开始我也想过这个问题。。。)当然是数据
啦,你怎么能阻止视图的加载呢!你是无法阻止Fragment的生命周期函数的执行的,所以只能让当前显示的Fragment加载数据,不显示不加载数据
怎么能知道当前页面是显示的这个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数据应该会变,所以分发一下
文章图片
在子Fragment中又有一个viewpager+Fragment又会怎么样?
这里去除掉了其他log,为了看起来清楚点
【Android模仿微博的LazyFragment懒加载】我给TowFragment加了一个viewpager,里面有TowFragment1和2
进入App可以看到,爹都还没显示,儿子先加载了数据?
文章图片
而且在之后的切换底部Tab,TowFragment里面的两个儿子都无动于衷,只有刚打开App时加载了,连停止加载的方法都没调用到,根本就没有事件分发到儿子那里去
文章图片
所以我们必须要再做一些根据父亲和儿子的状态再做一些判断 先解决第一个问题,父Fragment还没显示,子Fragment就加载了数据。这个问题很简单,我们只需要在分发加载数据的事件时,
判断一下是否有父Fragment,且是否可见。
就可以了根据Fragment源码中的这个方法,可以解决上面的问题
文章图片
比如,父Fragment不可见时直接退出方法,不准分发
文章图片
但是还有一个问题存在,就是不管怎么切换,子Fragment都不会分发加载或停止加载数据的事件。这是为啥??
从一开始我们可以看到,在进入HomeFragment时,子Fragment也会分别
调用两次setUserVisibleHint方法
,在进入前就把自己的可见状态置为true。到底后面的分发事件无效了。所以我决定在进入他的父Fragment时,再去调用一次分发事件,真正的加载子Fragment的数据,比如
文章图片
可以看见切换都是正常的
文章图片
最后 今天的文章就到这里,感谢您的阅读,有问题可以在评论区留言探讨,期待与大家共同进步。喜欢的话不要忘了三连。大家的支持和认可,是我分享的最大动力。