recyclerview 适配器如何知道调用 onCreateViewHolder?
Posted
技术标签:
【中文标题】recyclerview 适配器如何知道调用 onCreateViewHolder?【英文标题】:How does the recyclerview adapter know to call onCreateViewHolder? 【发布时间】:2022-01-01 13:40:19 【问题描述】:我刚刚看到了 Recyclerview 适配器的这个示例类,我对它如何知道仅通过将 Item 对象添加到列表中来调用 onCreateViewHolder、onBindViewHolder 等感到有点困惑?
它与notifyItemInserted(items.size - 1)
行有关吗?
是每当调用此方法时,都会为该项目调用 onCreateViewHolder 方法,还是?
适配器:
class ListAdapter (
private val items: MutableList<Item>
) : RecyclerView.Adapter <ListAdapter.ListViewHolder>()
class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder
return ListViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.list_items, parent, false)
)
override fun onBindViewHolder(holder: ListViewHolder, position: Int)
val currItem = items[position]
holder.itemView.apply
tv_item.text = currItem.title
cb_item.isChecked = currItem.checked
crossItem(tv_item, currItem.checked)
cb_item.setOnCheckedChangeListener _, isChecked ->
crossItem(tv_item, isChecked)
currItem.checked = !currItem.checked
items.removeAll item ->
item.checked
notifyDataSetChanged()
override fun getItemCount(): Int
return items.size
private fun crossItem (itemText: TextView, checked: Boolean)
if (checked)
//dk wtf paint flags is
itemText.paintFlags = itemText.paintFlags or STRIKE_THRU_TEXT_FLAG
//else remove
else
itemText.paintFlags = itemText.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
fun addItem (item: Item)
items.add (item)
notifyItemInserted(items.size - 1)
物品类别:
data class Item (
val title: String,
var checked: Boolean = false
)
【问题讨论】:
【参考方案1】:每当适配器需要为 RecyclerView 提供一个新的视图来绘制时,它都会检查它的池中是否有一个未使用的 ViewHolder。如果没有,它会调用onCreateViewHolder()
,以便创建一个。然后它为来自任一源的 ViewHolder 调用 onBindViewHolder()
,以便可以在添加到布局之前准备包含的视图。
如果您调用notify
方法之一,则会触发它刷新受影响的项目行。它将所有已删除的行返回到 ViewHolder 池,然后按照上述步骤获取新行所需的视图。如果您使用notify...changed
方法,则只需对适用的行使用onBindViewHolder()
。当您使用核选项notifyDataSetChanged()
时,它会将所有项目返回到池中。
当 RecyclerView 首次显示时,或者当布局调整大小时,这些操作可能会触发显示更多行的需要。当您滚动列表时,滚动出屏幕的项目将返回到 ViewHolder 池中,而当新项目滚动到视图中时,需要从池中创建或获取 ViewHolder,如上所述。
顺便说一句,这看起来很难看,因为即使只删除了一些项目,它也会刷新整个列表:
items.removeAll item ->
item.checked
notifyDataSetChanged()
我建议这样做,以便您获得良好的过渡:
for (i in items.indices.reversed())
if (items[i].checked)
items.removeAt(i)
notifyItemRemoved(i)
我反向迭代,因此在您迭代和删除项目时,删除的索引是稳定的。
【讨论】:
【参考方案2】:override fun getItemCount(): Int
return items.size
这个函数是关键,它通过知道总共有多少来知道创建多少和绑定多少。创建的ViewHolder
s 的数量更多取决于屏幕上一次可以容纳多少View
s。
当您有不同的视图类型时,这会变得更加复杂,因为随着视图类型的变化,有时它必须创建比一开始所需的更多的ViewHolder
s。
notify... functions
只是让Adapter
知道它需要“重新查看”List
。
【讨论】:
以上是关于recyclerview 适配器如何知道调用 onCreateViewHolder?的主要内容,如果未能解决你的问题,请参考以下文章
离线时Recyclerview不调用onCreateViewHolder
如何使用 DiffUtil 更新 RecyclerView 适配器
当调用 RecyclerView 适配器的“notifyDataSetChanged()”时,RecyclerView 抛出“java.lang.Throwable: addInArray”
在 RecyclerView 适配器 notifyDataSetChanged() 之后未调用 onBindViewHolder