You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RecyclerView调用notifyDataSetChanged后长按item勾选Checkbox错位问题

问题根因
  1. 未存储条目选中状态:你仅在交互时修改了当前Holder中Checkbox的选中属性,没有用独立的数据结构记录每个位置的选中状态。当调用notifyDataSetChanged()触发全量刷新、或者滑动列表触发ViewHolder复用时,系统会直接复用Holder上一次渲染的UI状态,导致选中错位。当元素少于等于5个时,列表一屏可以完全展示,不需要复用ViewHolder,所以运行正常;超过5个后触发复用逻辑,就会出现误勾选的问题。
  2. 代码存在冗余隐患:你在Adapter全局声明了binding变量,每次onCreateViewHolder创建新Holder时都会覆盖这个全局变量,虽然当前逻辑使用Holder内部存储的binding操作不会直接引发bug,但这个写法不规范,后续修改逻辑很容易出错。
修复方案

首先新增一个集合存储已选中的位置,同时在onBindViewHolder中主动给Checkbox赋值选中状态,交互时先修改数据源再刷新UI,删除全局冗余的binding变量,修改后代码如下:

class RecyclerAdapter(private val listActivity: ListActivity) : RecyclerView.Adapter<RecyclerAdapter.Holder>() {

    var checkboxesVisibility = false
    val dummyArrayFails = arrayOf("000", "111", "222", "333", "444", "555")
    // 新增存储选中位置的集合
    private val checkedPositions = mutableSetOf<Int>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        // 局部声明binding,不要用全局变量
        val binding = ActivityListItemRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }

    override fun getItemCount(): Int = dummyArrayFails.size

    override fun onBindViewHolder(holder: Holder, position: Int) {
        val item = dummyArrayFails[position]
        holder.bindItem(item)
        // 主动设置可见性和选中状态,避免复用错乱
        holder.binding.checkbox.visibility = if (checkboxesVisibility) View.VISIBLE else View.GONE
        holder.binding.checkbox.isChecked = checkedPositions.contains(position)

        holder.itemView.setOnLongClickListener {
            if (!checkboxesVisibility) {
                checkboxesVisibility = true
                // 先修改数据,不要直接改Holder的控件状态
                checkedPositions.add(position)
                notifyDataSetChanged()
                true
            } else {
                false
            }
        }
        holder.itemView.setOnClickListener {
            if (!checkboxesVisibility) {
                // 其他业务逻辑
            } else {
                // 先修改数据
                if (checkedPositions.contains(position)) {
                    checkedPositions.remove(position)
                } else {
                    checkedPositions.add(position)
                }
                notifyDataSetChanged()
            }
        }
    }

    class Holder(internal val binding: ActivityListItemRowBinding) : RecyclerView.ViewHolder(binding.root) {
        var item = String()
        fun bindItem(item: String) {
            this.item = item
            binding.itemPlaceHolder.text = item
        }
    }
}

另外你提到去掉显隐逻辑直接显示Checkbox就不会错位,是因为这种场景下你没有触发notifyDataSetChanged全量刷新,且没有滑动列表触发复用,一旦滑动或者刷新同样会出现错位问题。

内容的提问来源于stack exchange,提问作者Linus Karlsson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 13:27:03