# RecyclerView / ListView


### RecyclerView / ListView

#### 区别

1. ListView 布局单一, RecyclerView 有横向纵向瀑布流表格等布局
2. ListView 需要实现 ArrayAdapter, RecyclerView 则是 RecyclerView.Adapter\<ViewHolder\>
3. ListView 缓存 View, 离屏缓存, 从 mScrapViews 根据 pos 获取相应的缓存 getView 之后进行 bindView
   RecyclerView 则是通过缓存 ViewHolder 实现了重用无需 bindView()
4. 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

解决方案:

1. NestedScrollView + recyclerView.isNestedScrollingEnabled = false
2. 不用scrollView, recyclerView 设置多种 itemType
3. 如果滑动方向不同, 可以考虑重写recyclerView 的 LinearLayoutManager->canScrollVertically 为false之类的方法
