RecyclerView / ListView
目录
RecyclerView / ListView
区别
- ListView 布局单一, RecyclerView 有横向纵向瀑布流表格等布局
- ListView 需要实现 ArrayAdapter, RecyclerView 则是 RecyclerView.Adapter<ViewHolder>
- ListView 缓存 View, 离屏缓存, 从 mScrapViews 根据 pos 获取相应的缓存 getView 之后进行 bindView RecyclerView 则是通过缓存 ViewHolder 实现了重用无需 bindView()
- RecyclerView 支持局部刷新
缓存机制
RecyclerView
-
mAttachedScrap
: 第一级缓存, 相当于 ListView 的 mActiveView, 快速重用屏幕上可见的 ViewHolder -
mCacheViews
: 第二级缓存, 默认缓存 2 个 ItemView, RecycleView 从这里获取的缓存时, 如果数据源不变的情况下, 无需重新 bindView -
mViewCacheExtension
: 第三级缓存, 需要开发者实现 -
RecycledViewPool
: 通过SparseArray<ArrayList<ViewHolder>>
通过 SparseArray 实现的轻量 Map, 根据不同的 itemType 使用不同的缓存
RecyclerView 优化
分离
视图绑定和数据处理-
- 尽量只在
onBindViewHolder
中只设置数据, 数据应该在onBindViewHolder
之前计算好
- 尽量只在
分页延迟
加载, 比如说使用 Paging 组件- 减少 View 层级
- 加大 RecyclerView.
mCachedViews
的缓存 - 共享
RecycledViewPool
-
- RecyclerView.setRecycledViewPool(): 前提是子项 RecycleView 的 Adapter 是相同的
局部刷新
-
- notifyDataSetChanged()全部刷新
-
- notifyItemChanged (int)指定一个刷新
-
- notifyItemRangeChanged(int, int)指定刷新起始 个数
-
- notifyItemInserted(int) 插入一个并刷新
-
- notifyItemRemoved(int)移除一个并刷新
和 ScrollView 冲突
出现场景: 为了偷懒, 给 RecyclerView 设置 header 直接使用了ScrollView 里面嵌套了 header 和一个 RecyclerView
解决方案:
- NestedScrollView + recyclerView.isNestedScrollingEnabled = false
- 不用scrollView, recyclerView 设置多种 itemType
- 如果滑动方向不同, 可以考虑重写recyclerView 的 LinearLayoutManager->canScrollVertically 为false之类的方法