ViewCacheExtension
作为 RecyclerView
中的开发者自定义缓存, 具有以下特点:
- 只有从缓存中取, 没有从缓存中读.
- 接口需要返回 View.
- 接口返回的 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
var headerView: View? = null
var list = mutableListOf<Any>()
init { 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) { if (headerView == null) { headerView = xxx } return HeaderHolder(headerView!!) } return xxx }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { if (holder is HeaderHolder) { } else { xxx } }
class HeaderHolder(itemView: View) : ViewHolder(itemView) { init { } } }
|
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) { recycler.bindViewToPosition(it, position) return it } return null } } })
recyclerView.getRecycledViewPool.setMaxRecycledViews(TYPE_AD, 0)
|
总结来说, 用这个方法写 Header 有以下几个特点:
- list 有感知, 需要保证 list 的头部是 header. 这种方式无论 Adapter Wrapper 还是自定义 Adapter 都绕不开.
- 不在
onBindViewHolder
里面每次更新数据的话, 就可以不用保持 View 和 Model 的同步(因为复用机制, 比如点了一个按钮 View 发生状态改变了, 不记录下来的话滑入滑出 View 又会恢复原来的状态)
- 因为清掉了
RecyclerPool
的缓存, 保持一个 View 性能更佳.
- 一直拥有 HeaderView 的强引用, 方便更新 HeaderView.
不同时出现在一屏的相同类型的 ViewType
- 不同时出现在一屏, 因为我觉得
ViewCacheExtension
这种自己管理缓存的使用场景, 最方便的就是只有一个缓存 View , 如果缓存的 View 多了, 那和 RecyclerPool
这种管理方式没有什么区别. 而不同时出现在一屏就可以只缓存一个 View .
- 相同类型: 这样就不用重复创建 View / ViewHolder , 这样就复用一个 View 即可.
这里举个例子就是列表中的固定位置的广告, 每次更新广告 View 里面的广告内容即可.