recyclerView 中的 diffutil 回调无法正常工作

diffutil callback in recyclerView doesn't work perfectly

我正在尝试在不使用

的情况下在 RecyclerView 列表中添加一些搜索

notifyDataSetChanged()

而不是使用

diffutil.callback()

但问题是它正确更改了列表,但没有正确更改 UI

这是我的代码,我会解释它

class RecordsAdapter : RecyclerView.Adapter<RecordsAdapter.ViewHolder>() {

    var adapterList = listOf<CustomerModel>()

    var modelList = listOf<CustomerModel>()
        set(value) {
            adapterList = value
            field = value
        }

    private var modelListFiltered = listOf<CustomerModel>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
        ViewHolder(CustomerCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(adapterList[position])
    }

    override fun getItemCount(): Int = adapterList.size

    fun filter(isFiltered: Boolean, filterSearch: String) {
        if (isFiltered) {
            val filter = modelList
                .filter {
                    it.name.contains(filterSearch) || it.id.contains(filterSearch)
                }

            modelListFiltered = filter
        }

        adapterList = if (isFiltered) modelListFiltered else modelList

        val diff = CartDiffUtil(
            if (isFiltered) modelList else modelListFiltered,
            if (isFiltered) modelListFiltered else modelList
        )

        DiffUtil.calculateDiff(diff).dispatchUpdatesTo(this)
    }

    inner class ViewHolder(private var binding: CustomerCellBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(model: CustomerModel) {
            binding.let {
                it.model = model
                it.executePendingBindings()
            }
        }
    }
}

class CartDiffUtil(private val oldList: List<CustomerModel>, private val newList: List<CustomerModel>) : DiffUtil.Callback() {

    override fun getOldListSize() = oldList.size

    override fun getNewListSize() = newList.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
    oldList[oldItemPosition].id == newList[newItemPosition].id

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
    oldList[oldItemPosition] == newList[newItemPosition]
}

所以我正在调用过滤器函数进行过滤,如果有任何过滤器,我将发送两个参数,第二个是搜索。

现在这个场景出现这个问题

0。搜索“”

1.搜索“测试 2”

2。搜索“测试 4”

3.搜索“测试 2”

4.搜索“”

正如您在图片中看到的,当我在“测试 4”之后搜索“测试 2”时,它一直显示“测试 4”,即使我清除了搜索,它也会给我两个单元格“测试 4”而不是一个“测试 2”和一个“测试 4”

希望我的问题很清楚。

谢谢。

我猜你对三个列表属性的处理会导致某些情况,即 DiffUtil 前后可能存在相同的列表实例,因此无法成功比较它们。

此外,当您想使用 DiffUtil 时,使用 ListAdapter 比 RecyclerView.Adapter 更容易。请注意,当您使用 ListAdapter 时,您使用的是 ItemCallback 而不是 Callback。 ItemCallback 更简单。

尝试这样做,只有 modelList 并且当它或过滤器更改时,您确定新列表是什么并将其提交给 ListAdapter 并让它处理更改。

class RecordsAdapter : ListAdapter<CustomerModel, RecordsAdapter.ViewHolder>(CustomerModelCallback) {

    var modelList = listOf<CustomerModel>()
        set(value) {
            field = value
            resync()
        }

    private var filterText: String = ""
    private var isFiltered: Boolean = false

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
        ViewHolder(CustomerCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(adapterList[position])
    }

    fun filter(isFiltered: Boolean, filterText: String = "") {
        this.isFiltered = isFiltered
        this.filterText = filterText
        resync()
    }

    private fun resync() {
        val newList = when {
            isFiltered && filterText.isNotEmpty() -> 
                modelList.filter {
                    it.name.contains(filterSearch) || it.id.contains(filterSearch)
                }
            else -> modelList
        }

        submitList(newList)
    }

    // view holder...
}

object CustomerModelCallback : DiffUtil.ItemCallback<CustomerModel>() {
    override fun areItemsTheSame(oldItem: CustomerModel, newItem: CustomerModel): Boolean =
        oldItem.id == newItem.id

    override fun areContentsTheSame(oldItem: CustomerModel, newItem: CustomerModel): Boolean =
        oldItem == newItem
}