DiffUtil.ItemCallback 不更新项目位置(删除后)

DiffUtil.ItemCallback doesn't update item position (after a deleting)

我使用 ListAdapter 的绑定和 DiffUtil.ItemCallback 的定义。删除项目(至少 2 个)时,我有一个 IndexOutOfBoundsException。 列表的更新有效(删除后元素的数量确实是 N-1)但不是项目的位置,保留的是调用。因此在调用 getItem(position) 时抛出异常(在 onBindViewHolder 中)。注意:getItem(position) 之前的 getItemCount() 日志显示该列表包含 N-1 个元素。 我创建了一个小的 repo:https://github.com/jeremy-giles/DiffListAdapterTest(与我的项目具有相同的配置)它重现了这个问题。

ItemAdapter class

class ItemAdapter(
    var listener: ListAdapterListener) : DataBindingAdapter<Item>(DiffCallback()) {

    class DiffCallback : DiffUtil.ItemCallback<Item>() {

        override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
           return oldItem == newItem
        }

        override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
           return oldItem == newItem
        }
    }

    override fun getItemViewType(position: Int) = R.layout.recycler_item

    override fun onBindViewHolder(holder: DataBindingViewHolder<Item>, position: Int) {
        super.onBindViewHolder(holder, position)

        holder.itemView.tv_position.text = "Pos: $position"

        holder.itemView.setOnLongClickListener {
            Timber.d("List item count: ${itemCount}, position: $position")
            listener.onLongViewClick(getItem(position), position)
        }
    }

    interface ListAdapterListener {
        fun onLongViewClick(item: Item, position: Int) : Boolean
    }
}

BindingUtils classes

abstract class DataBindingAdapter<T>(diffCallback: DiffUtil.ItemCallback<T>) :
    ListAdapter<T, DataBindingViewHolder<T>>(diffCallback) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBindingViewHolder<T> {
        val layoutInflater = LayoutInflater.from(parent.context)
        val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, viewType, parent, false)

        return DataBindingViewHolder(binding)
    }

    override fun onBindViewHolder(holder: DataBindingViewHolder<T>, position: Int) {
        holder.bind(getItem(position))
    }
}

class DataBindingViewHolder<T>(private val binding: ViewDataBinding) :
    RecyclerView.ViewHolder(binding.root) {

    fun bind(item: T) {
        binding.setVariable(BR.item, item)
        binding.executePendingBindings()
    }
}

在我的 MainActivity class 中,我使用 LiveData 来更新 recyclerView

itemViewModel.getListObserver().observe(this, Observer {
        Timber.d("List Observer, items count ${it.size}")
        itemAdapter.submitList(it.toList())
    })

在您的 onBindViewHolder 中将 'position' 的用法更新为 'holder.getAdapterPosition()':

override fun onBindViewHolder(holder: DataBindingViewHolder<Item>, position: Int) {
        super.onBindViewHolder(holder, position)

        holder.itemView.tv_position.text = "Pos: $position"

        holder.itemView.setOnLongClickListener {
            Timber.d("List item count: ${itemCount}, position: $position")
            listener.onLongViewClick(getItem(holder.getAdapterPosition()), holder.getAdapterPosition())
        }
    }