最近优化了项目里的列表展示, 顺便对 RecyclerView 的使用做了重新的封装, 目的是当列表的需求比较复杂的时候, 依然能够保持逻辑的清晰和解耦, 同时通过封装来使复杂列表的性能得到一定的保证
当然如果是非常简单的列表的话, 其实 Android 原生的 RecyclerView 加上 Adapter 就已经比较便捷了, 没有必要去做过度的封装了
项目 GitHub 地址: https://github.com/zhengcx/InstantRecyclerView
每一个对项目的重构或者重新封装都是出于对现状的不满, 那么我们就从这个封装项目解决了哪些问题来展开这篇博文吧
1. 解决重复的全局刷新
需要注意一下你的项目里对列表的使用, 特别是加载更多时是否都是重复的全局刷新, 这对复杂列表的性能影响较大, 你需要考虑每次刷新不去刷新那些不需要刷新的 item, 一个是对性能会有提高, 另一个页面上用户的体验也会好很多, 本项目提供了全局刷新和增量刷新的相关方法, 保证加载更多或者操作单个 item 时只局部刷新
2. 解决 header/Footer 的增删效率
RecyclerView 本身并没有提供像 ListView 那样便捷的添加 header/footer 的方法, 所以需要我们自己去实现
网上主要有两种: 一种是采用 wrap 的方式使 headerfooter 和普通 item 区别开, 而另一种方式使把 headerfooter 也当做是一种 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
最后, 希望世界上的每一个列表都丝丝如滑~~~
来源: https://juejin.im/post/5abda929f265da23826e155e