RecyclerView核心要点
RecyclerView是什么?
a flexible view for providing
a limited window into
a large data set

ListView的局限
- 只有纵向列表一种布局
- 没有支持动画的 API
- 接口设计和系统不一致
setOnItemClickListener()setOnItemLongClickListener()setSelection()
- 没有强制实现
ViewHolder - 性能不如
RecyclerView
RecyclerView的优势
- 默认支持
Linear,Grid,Staggered Grid三种布局 - 友好的
ItemAnimator动画API - 强制实现
ViewHolder - 解耦的架构设计
- 相比
ListView更好的性能
LayoutManager支持的布局

RecyclerView的重要组件

RecyclerView Demo
ViewHolder究竟是什么?
- View holder 和 item view 是什么关系?一对一?一对多?多对多?
- View holder 解决的是什么问题?
- View holder 的 ListView item view 的复用有什么关系
没有实现view hodler的getView()
1 | public class SimpleListViewAdapter extends BaseAdapter{ |
没有复用item view
实现了view holder的getView()
1 | public class SimpleListViewAdapter extends BaseAdapter{ |
Item view和view holder一一对应

View holder最佳实践
1 | static class UserViewHolder extends RecyclerView.ViewHolder{ |
RecyclerView缓存机制
ListView缓存图示一

ListView缓存图示二

RecyclerView缓存图示一

RecyclerView缓存图示二

ViewCacheExtension Example
- 广告卡片
- 每一页一共有4个广告
- 这些广告短期内不会发生变化
- 每次滑入一个广告卡片,一般情况下都需要重新绑定
Cache只关心position,不关心view typeRecycledViewPool只关心view type,都需要重新绑定- 在
ViewCacheExtension里保持4个广告Card缓存
注意:列表中 item/广告的 impression 统计
ListView通过getView()统计RecyclerView通过onBindViewHolder()统计?可能错误!- 通过
onViewAttachedToWindow()统计
RecyclerView性能优化策略
在onBindViewHolder里设置点击监听?
onBindViewHodler里设置点击监听器会导致重复创建对象
1 | public class SimpleAdapter extends RecyclerView.Adapter{ |
改成在onCreateViewHolder里设置点击监听!
View-ViewHolder-View.OnClickListener三者一一对应
1 | public class SimpleAdapter extends RecyclerView.Adapter{ |
使用LinearLayoutManager.setInitialPrefetchItemCount()
- 用户滑动到横向滑动的
item RecyclerView的时候,由于需要创建更复杂的RecyclerView以及多个子view,可能会导致页面卡顿 - 由于
RenderThread的存在,RecyclerView会进行prefetch LinearLayoutManager.setInitialPrefetchItemCount(横向列表初次显示时可见的item个数)- 只有
LinearLayoutManager有这个API - 只有嵌套在内部的
RecyclerView才会生效
- 只有
RecyclerView.setHasFixedSize()
1 | //伪代码 |
如果
Adapter的数据变化不会导致RecyclerView的大小变化 –》RecyclerView.setHasFixedSize(true)
多个 RecyclerView 共用 RecycledViewPool

共用 RecycledViewPool 代码
1 | RecyclerView.RecycledViewPool recycledViewPool = new RecyclerView.RecycledViewPool(); |
DiffUtil
- DiffUtil is a utility class that can calculate the difference between two lists and output a list of update operations that converts the first list into the second one.
- 局部更新方法
notifyItemXXX()不适用于所有情况 notifyDataSetChange()会导致整个布局重绘,重新绑定所有ViewHolder,而且会失去可能的动画效果DiffUtil适用于整个页面需要刷新,但是有部分数据可能相同的情况
1 | public abstract static class Callback{ |
DiffUtil.Callback逻辑
1 | public class UserDiffCallback extends DiffUtil.Callback{ |
1 | public class UserDiffCallback extends DiffUtil.Callback{ |
1 | public class ShowcaseRVAdapter extends RecyclerView.Adapter<ShowcaseRvAdapter.UserViewHolder>{ |
1 | public class ShowcaseRVAdapter extends RecyclerView.Adapter<ShowcaseRvAdapter.UserViewHolder>{ |
在列表很大的时候异步计算diff
- 使用
Thread/Handler将DiffResult发送到主线程 - 使用
RxJava将calculateDiff操作放到后台线程 - 使用 Google 提供的
AsyncListDiffer(Executor)/ListAdapterAsyncListDiffer / ListAdapter代码示例 - https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer
- https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter
为什么ItemDecoration可以绘制分割线?

Overlay Divider 代码
1 | public class OverlayDivider extends RecyclerView.ItemDecoration{ |
ItemDecoration 还可以做什么?
- Drawing dividers between items
- Highlights

- Visual grouping boundaries
