ViewCacheExtension-Usage

ViewCacheExtension 作为 RecyclerView 中的开发者自定义缓存, 具有以下特点:

  1. 只有从缓存中取, 没有从缓存中读.
  2. 接口需要返回 View.
  3. 接口返回的 View 必须绑定了 ViewHolder .

就应用来说, 我觉得有两个合适的场景

Header 场景


先介绍一下代码示例

Adapter 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class MainAdapter : Adapter<ViewHolder>() {

val TYPE_HEADER = 0
val TYPE_NORMAL = 1

// 定义 HeaderView 强引用
var headerView: View? = null

// 列表数据
var list = mutableListOf<Any>()

init {
// 插入 Header Model
list.add(0, headerModel)
}

override fun getItemCount(): Int {
return list.size
}

override fun getItemViewType(position: Int): Int {
return if (list[position] is HEADER) TYPE_HEADER else TYPE_NORMAL
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
if (viewType == TYPE_HEADER) {
// 如果 HeaderView 为空, 就创建, 否则直接使用
if (headerView == null) {
headerView = xxx
}
return HeaderHolder(headerView!!)
}
return xxx
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is HeaderHolder) {
// 什么都不做
} else {
xxx
}
}

// Header ViewHolder
class HeaderHolder(itemView: View) : ViewHolder(itemView) {
init {
// 初始化 HeaderView
}
}
}

RecyclerView 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
recyclerView.setViewCacheExtension(object: ViewCacheExtension() {
override fun getViewForPositionAndType(recycler: Recycler, position: Int, type: Int): View? {
adapter.headerView?.let {
if (type == TYPE_HEADER) {
// 手动调用 bind
recycler.bindViewToPosition(it, position)
return it
}
return null
}
}
})

// 不缓存广告类型
recyclerView.getRecycledViewPool.setMaxRecycledViews(TYPE_AD, 0)

总结来说, 用这个方法写 Header 有以下几个特点:

  1. list 有感知, 需要保证 list 的头部是 header. 这种方式无论 Adapter Wrapper 还是自定义 Adapter 都绕不开.
  2. 不在 onBindViewHolder 里面每次更新数据的话, 就可以不用保持 View 和 Model 的同步(因为复用机制, 比如点了一个按钮 View 发生状态改变了, 不记录下来的话滑入滑出 View 又会恢复原来的状态)
  3. 因为清掉了 RecyclerPool 的缓存, 保持一个 View 性能更佳.
  4. 一直拥有 HeaderView 的强引用, 方便更新 HeaderView.

不同时出现在一屏的相同类型的 ViewType


  1. 不同时出现在一屏, 因为我觉得 ViewCacheExtension 这种自己管理缓存的使用场景, 最方便的就是只有一个缓存 View , 如果缓存的 View 多了, 那和 RecyclerPool 这种管理方式没有什么区别. 而不同时出现在一屏就可以只缓存一个 View .
  2. 相同类型: 这样就不用重复创建 View / ViewHolder , 这样就复用一个 View 即可.

这里举个例子就是列表中的固定位置的广告, 每次更新广告 View 里面的广告内容即可.