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

如何在RecyclerView中正确使用DiffUtils更新ArrayList,解决点击列表崩溃问题

问题原因及修复方案

核心崩溃原因

你在点击事件中直接使用了onBindViewHolder传入的静态position参数:
onBindViewHolder的position是item绑定瞬间的位置,当你通过DiffUtils更新列表(比如搜索过滤后列表长度变短、item位置发生变化),已绑定过的item内部存储的position不会同步更新,此时点击就会拿到过期的位置索引,访问列表时触发IndexOutOfBoundsException。
而notifyDataSetChanged()会强制重绘所有item,所有item的position都会重新绑定为最新值,所以不会出现崩溃。

其他潜在问题

  1. areItemsTheSame的判断字段不合理:你当前用updatedAt作为item唯一标识,若存在多个语言项的更新时间相同,会导致DiffUtils判断item是否为同一个的逻辑出错,引发列表更新异常。建议使用唯一业务字段(比如languageCode语言编码)作为判断依据。
  2. 额外冗余逻辑:onBindViewHolder中判断背景的条件position == 0 && position % 2 == 0存在冗余,position == 0天然满足position % 2 ==0,可以简化。

修复代码

1. 修改Adapter点击事件的取值逻辑

把点击事件里的静态position替换为holder.adapterPosition,这个方法会实时返回item当前的最新位置:

override fun onBindViewHolder(holder: LanguageSelectionVH, position: Int) {
    val model = languageModelList[position]
    holder.binding.languageCard.apply {
        // 简化背景判断逻辑
        setCardBackgroundColor(
            if (position % 2 == 0) ContextCompat.getColor(context, R.color.main_blue)
            else ContextCompat.getColor(context, R.color.main_green)
        )
    }
    holder.binding.nativeLanguageText.text = model.languageNativeName
    holder.binding.originalLanguageText.text = model.languageName
    holder.itemView.setOnClickListener {
        // 用实时位置代替静态position
        val currentPos = holder.adapterPosition
        // 加边界判断,避免ViewHolder已经被回收时拿不到有效位置
        if (currentPos != RecyclerView.NO_POSITION) {
            itemClick.langClick(currentPos)
        }
    }
}

2. 修改DiffUtils的item唯一判断逻辑

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
    // 用唯一的语言编码作为判断相同item的依据
    return oldList[oldItemPosition].languageCode == newList[newItemPosition].languageCode
}

3. 额外注意事项

每次调用setData传入的newLanguageModelList必须是新的ArrayList实例,不要和Adapter内部持有的languageModelList是同一个引用,否则DiffUtils计算新旧列表差异时会因为指向同一个集合导致计算错误。


内容的提问来源于stack exchange,提问作者Suman Radhakrishnan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:06:03