最近优化了项目里的列表展示,顺便对RecyclerView的使用做了重新的封装,目的是当列表的需求比较复杂的时候,依然能够保持逻辑的清晰和解耦,同时通过封装来使复杂列表的性能得到一定的保证。
当然如果是非常简单的列表的话,其实Android原生的RecyclerView加上Adapter就已经比较便捷了,没有必要去做过度的封装了。
项目GitHub地址: https://github.com/zhengcx/InstantRecyclerView
每一个对项目的重构或者重新封装都是出于对现状的不满,那么我们就从这个封装项目解决了哪些问题来展开这篇博文吧。
1.解决重复的全局刷新
需要注意一下你的项目里对列表的使用,特别是加载更多时是否都是重复的全局刷新,这对复杂列表的性能影响较大,你需要考虑每次刷新不去刷新那些不需要刷新的item,一个是对性能会有提高,另一个页面上用户的体验也会好很多,本项目提供了全局刷新和增量刷新的相关方法,保证加载更多或者操作单个item时只局部刷新。
2.解决header/Footer的增删效率
RecyclerView本身并没有提供像ListView那样便捷的添加header/footer的方法,所以需要我们自己去实现。
网上主要有两种:一种是采用wrap的方式使header、footer和普通item区别开,而另一种方式使把header、footer也当做是一种itemType来做。
这里我们采用了第二种方式,提供了便捷添加header/footer的方法,当然把header\footer当做一种itemType来看待,则当header/footer发生增删(特别是header)时,则会使列表发生全局的刷新,这里优化的点是对RecyclerView来说他的header永远只有一个,是一个ViewGroup,之后要添加或者删除一个或多个header,都只是往这个ViewGroup里增删View,将不会对整个列表产生刷新,提供性能和体验。
3. 解决列表多itemType时代码不够清晰的问题
当你的列表会存在多种复杂的itemType时,很容易时Adapter里的代码产生混乱,且不够清晰,很难拓展。我们封装的目的是:
1.让每种itemType的处理逻辑交给各自的itemDelegate去处理,实现不同itemType处理逻辑的解耦
2.让代码易于拓展,也就是说不管今后要再添加多少种itemType,都能做到非常清晰,非常便捷。
项目里通过DelegateScheduler来管理调度不同itemType的处理逻辑,使多itemType变得清晰易拓展。
4.解决状态View导致过度绘制的问题
我们的列表通常都需要好几种显示加载状态的View,比如loadingView、加载失败View、加载数据为空View。如果你的做法是在布局文件里先写好这几种View然后通过设置是否可见来控制,显然这会引起布局嵌套过渡绘制的问题,当然你可以利用ViewStub来做一些优化,但是治标不治本,当这些状态View被inflate一次后,依然会存在这种问题。
如果你把这些状态View也当做是一种itemType呢,让它与普通item一样参与回收,参与cache,是不是就可以解决这个问题,这是我目前看到想到的比较理想的方式,当然可能有更好的方式。
5.解决上拉加载更多问题
显然如果你把上拉加载更多这个功能放在你的业务代码里去监听是不合适的,我们需要封装一下,让recyclerView自动就带有这个功能,直接使用就可以了。
本项目给上拉加载更多提供了两种不同的监听方式,看个人喜好自己选择。
1.实时监听,也就是说只要用户滑动,那么就会实时监听判断要不要开始加载下一页数据,这一种的好处是让列表预加载更加实时,基本可以实时用户可以不断的下拉,使用户感知不到我们的加载过程。
2.另一种是只有当列表滚动状态发生改变时才会发起是否加载下一页数据的判断,这一种基本是用户从滑动到停止时才会发起下一页的加载。
当然两种方式提前多少个item发起预加载下一页都是可以由你自己来设置这个参数,目前默认是采用第二种方式,可以通过设置来使用第一种方式。
6. 解决item的点击事件重复绑定的问题
RecyclerView没有像ListView那样提供setOnItemCLickListener()方法来绑定item的点击事件,所以我们一般都会自己去设置这个item的点击事件,这样子很容易就把点击事件多次重复设置了。
这里封装提供了setOnItemClickListener()方法,让你可以放心的设置item点击事件,并且在回调里提供该item所绑定的数据,以及item的position,该item的类型等重要信息,可以使你在多种itemType的列表里的点击事件里正确的做各种你想做的事情。
对列表性能问题的建议
其实对于一些复杂的列表,性能问题显得尤为重要,上面说了一个是尽量去做局部刷新而不是全量刷新,一个是尽量减少过度绘制。还有一个非常重要的是每个版本都要去关注你的bindViewHolder()里的逻辑是否有耗时严重的方法或操作,列表性能出现问题,很大概率就是你的bindViewHolder()中有叫耗时操作,排查也很好排查,通过SysTrace+TraceView可以很快找到耗时的方法和性能的瓶颈,然后做针对性的优化就可以了。
项目GitHub地址: https://github.com/zhengcx/InstantRecyclerView
最后,希望世界上的每一个列表都丝丝如滑~~~
网友评论