RecyclerView滑动删除后点击Undo触发ArrayIndexOutOfBoundsException求助
问题分析
崩溃根源有两个核心问题:
- ViewHolder位置失效:执行撤销操作时,原ViewHolder已被RecyclerView回收,
viewHolder.absoluteAdapterPosition返回-1,直接触发数组越界。 - 恢复逻辑错误:
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,提问作者Антон Кузнецов
相关产品推荐
相关产品推荐

