5

Android模仿微博的LazyFragment懒加载

 2 years ago
source link: https://segmentfault.com/a/1190000041081825
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文会从头开始一步一步带你去写一个LazyFragment,根据写的过程中一步一步记录,你也可以自己试一试,跟着一起写写。最后也根据遇到的问题去完善了,网上搜的都是不完善的,还是自己写一个吧!

懒加载是在加载啥?

这个问题显得很愚蠢。但是想一下,懒加载到底是加载数据和视图,还是数据呢??(一开始我也想过这个问题。。。)当然是数据啦,你怎么能阻止视图的加载呢!你是无法阻止Fragment的生命周期函数的执行的,所以只能让当前显示的Fragment加载数据,不显示不加载数据

怎么能知道当前页面是显示的这个Fragment呢?

在源码中有两个方法可以使用

在viewpager和fragment模式使用的
public void setUserVisibleHint(boolean isVisibleToUser) {}
在add+show+hide模式使用
public void onHiddenChanged(boolean hidden) {}

那么就先简单的试试看这两个方法好了 我写了一个Viewpager+Fragment模式的,缓存数量offscreenPageLimit为1

当打开app时

我们可以看到主页BadHomeFragmentsetUserVisibleHint()方法执行了两次!先返回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,为了看起来清楚点

我给TowFragment加了一个viewpager,里面有TowFragment1和2

进入App可以看到,爹都还没显示,儿子先加载了数据?

而且在之后的切换底部Tab,TowFragment里面的两个儿子都无动于衷,只有刚打开App时加载了,连停止加载的方法都没调用到,根本就没有事件分发到儿子那里去

所以我们必须要再做一些根据父亲和儿子的状态再做一些判断 先解决第一个问题,父Fragment还没显示,子Fragment就加载了数据。这个问题很简单,我们只需要在分发加载数据的事件时,判断一下是否有父Fragment,且是否可见。就可以了

根据Fragment源码中的这个方法,可以解决上面的问题

比如,父Fragment不可见时直接退出方法,不准分发

但是还有一个问题存在,就是不管怎么切换,子Fragment都不会分发加载或停止加载数据的事件。这是为啥??

从一开始我们可以看到,在进入HomeFragment时,子Fragment也会分别调用两次setUserVisibleHint方法,在进入前就把自己的可见状态置为true。到底后面的分发事件无效了。

所以我决定在进入他的父Fragment时,再去调用一次分发事件,真正的加载子Fragment的数据,比如

可以看见切换都是正常的

今天的文章就到这里,感谢您的阅读,有问题可以在评论区留言探讨,期待与大家共同进步。喜欢的话不要忘了三连。大家的支持和认可,是我分享的最大动力。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK