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

RecyclerView滑动删除Firestore数据遇索引越界问题求助

滑动RecyclerView条目删除Firestore数据时的索引越界与联动问题解决

问题现象

  • 滑动顶部条目时,底部条目会跟随滑动,但仅顶部条目从Firestore中被删除
  • 滑动底部条目时触发索引越界错误:java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

核心问题分析

  1. 异步操作导致数据源不一致:Firestore删除是异步任务,若用户快速滑动多个条目,旧的回调会拿着已失效的position操作修改后的foodList,直接引发索引越界
  2. 缺少视图状态重置:滑动结束后未恢复ViewHolder的初始状态,导致条目出现联动滑动异常
  3. 未处理删除失败的回滚:删除失败时,RecyclerView的条目已被划走,但数据源未更新,进一步加剧显示混乱

修复后的完整代码

1. 更新SwipeToDeleteCallback抽象类

abstract class SwipeToDeleteCallback : ItemTouchHelper.Callback() {
  
    override fun getMovementFlags(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        val swipeFlag = ItemTouchHelper.LEFT
        return makeMovementFlags(0, swipeFlag)
    }

    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        return false
    }

    // 滑动结束后重置视图状态,解决联动滑动问题
    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        ItemTouchHelper.Callback.getDefaultUIUtil().clearView(viewHolder.itemView)
    }

    // 限制滑动触发阈值,避免误操作
    override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
        return 0.5f
    }
}

2. 修复Fragment中的删除回调逻辑

val swipeToDeleteCallback = object : SwipeToDeleteCallback() {
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        val position = viewHolder.bindingAdapterPosition
        
        // 先校验位置有效性,直接拦截无效操作
        if (position < 0 || position >= foodList.size) {
            feedAdapter.notifyItemChanged(position)
            return
        }

        // 提前缓存目标数据,避免异步过程中数据源变化导致的错误
        val targetDocId = foodList[position].docId
        // 禁用视图防止重复触发删除
        viewHolder.itemView.isEnabled = false

        firestore.collection("Foods").document(targetDocId).delete()
            .addOnSuccessListener {
                foodList.removeAt(position)
                feedAdapter.notifyItemRemoved(position)
                Toast.makeText(requireContext(), "Deleted", Toast.LENGTH_LONG).show()
            }
            .addOnFailureListener { e ->
                // 删除失败时恢复条目显示
                feedAdapter.notifyItemChanged(position)
                Toast.makeText(requireContext(), e.localizedMessage, Toast.LENGTH_LONG).show()
            }
            .addOnCompleteListener {
                // 无论结果如何,恢复视图可交互状态
                viewHolder.itemView.isEnabled = true
            }
    }
}

val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback)
itemTouchHelper.attachToRecyclerView(binding.recyclerView)

关键修复点说明

  • 位置有效性校验:操作前判断position是否在foodList的合法范围内,直接拦截无效操作
  • 缓存目标数据:异步操作前先获取要删除的文档ID,不依赖后续可能变化的数据源
  • 删除失败回滚:调用notifyItemChanged将划走的条目恢复,保证视图与数据源一致性
  • 视图状态重置:通过clearView方法确保滑动结束后视图回到初始状态,解决联动滑动问题
  • 防止重复操作:滑动后禁用条目,避免用户重复触发删除逻辑

内容的提问来源于stack exchange,提问作者Mobile Development

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:33:30