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

这个函数是关键,它通过知道总共有多少来知道创建多少和绑定多少。创建的ViewHolders 的数量更多取决于屏幕上一次可以容纳多少Views。

当您有不同的视图类型时,这会变得更加复杂,因为随着视图类型的变化,有时它必须创建比一开始所需的更多的ViewHolders。

notify... functions 只是让Adapter 知道它需要“重新查看”List

【讨论】:

以上是关于recyclerview 适配器如何知道调用 onCreateViewHolder?的主要内容,如果未能解决你的问题,请参考以下文章

离线时Recyclerview不调用onCreateViewHolder

如何更新 RecyclerView 适配器数据

如何使用 DiffUtil 更新 RecyclerView 适配器

如何在 recyclerview 适配器中填充这些数据?

当调用 RecyclerView 适配器的“notifyDataSetChanged()”时,RecyclerView 抛出“java.lang.Throwable: addInArray”

在 RecyclerView 适配器 notifyDataSetChanged() 之后未调用 onBindViewHolder