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

RecyclerView滑动删除后点击Undo触发ArrayIndexOutOfBoundsException求助

问题分析

崩溃根源有两个核心问题:

  1. ViewHolder位置失效:执行撤销操作时,原ViewHolder已被RecyclerView回收,viewHolder.absoluteAdapterPosition返回-1,直接触发数组越界。
  2. 恢复逻辑错误:restoreItem方法里尝试用listArray[pos]获取已删除的元素,此时该位置的元素早已不存在,即使位置有效也会报错。
修复方案

步骤1:修改适配器,保存被删除的元素与位置

在适配器中新增临时变量存储被删数据,同时更新删除和恢复的逻辑:

// 适配器类内添加变量(替换Any为你的实际数据类型,比如Expense)
private var deletedItem: Any? = null
private var deletedPosition: Int = -1

fun removeItem(pos: Int) {
    deletedItem = listArray.removeAt(pos) // 保存被删除的元素
    deletedPosition = pos // 保存被删除的位置
    notifyItemRemoved(pos)
}

fun restoreItem() {
    // 先判断临时数据是否有效,避免重复触发异常
    if (deletedPosition != -1 && deletedItem != null) {
        listArray.add(deletedPosition, deletedItem!!)
        notifyItemInserted(deletedPosition)
        // 恢复完成后清空临时变量
        deletedItem = null
        deletedPosition = -1
    }
}

步骤2:修改Snackbar的Undo动作,直接调用无参恢复方法

不再依赖ViewHolder的位置(已失效),直接调用适配器中维护了正确数据的恢复方法:

val onSwipe = object : OnSwipe(this) {
    override fun onSwiped(viewHolder: ViewHolder, direction: Int) {
        when (direction) {
            ItemTouchHelper.RIGHT -> {
                val position = viewHolder.absoluteAdapterPosition
                // 先判断位置有效性,避免无效删除
                if (position != -1) {
                    adapter.removeItem(position)
                    Snackbar.make(binding.rv, "Deleted", Snackbar.LENGTH_SHORT)
                        .apply {
                            setAction("Undo") {
                                adapter.restoreItem()
                            }
                            show()
                        }
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Антон Кузнецов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:05:23