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

如何修复RecyclerView Adapter中onRowMoved函数的索引越界异常

RecyclerView拖拽移动触发IndexOutOfBoundsException异常排查与修复

我在实现RecyclerView拖拽移动功能时,Adapter的onRowMoved函数触发了java.lang.IndexOutOfBoundsException异常,崩溃日志如下:

Fatal Exception: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 8
       at jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
       at jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
       at jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
       at java.util.Objects.checkIndex(Objects.java:359)
       at java.util.ArrayList.get(ArrayList.java:434)
       at java.util.Collections.swap(Collections.java:548)
       at com....newProduct.NewProductImagesAdapter.onRowMoved(NewProductImagesAdapter.kt:208)
       at com....newProduct.NewProduct$createImagesAdapter$touchHelper$1.onMove(NewProduct.kt:927)
       at androidx.recyclerview.widget.ItemTouchHelper.moveIfNecessary(ItemTouchHelper.java:891)
       at androidx.recyclerview.widget.ItemTouchHelper$2.onTouchEvent(ItemTouchHelper.java:390)
       at androidx.recyclerview.widget.RecyclerView.dispatchToOnItemTouchListeners(RecyclerView.java:3515)
       at androidx.recyclerview.widget.RecyclerView.onTouchEvent(RecyclerView.java:3713)
       at android.view.View.dispatchTouchEvent(View.java:14879)

当前实现的代码:

val touchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {

    ...

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

})

fun onRowMoved(
    fromViewHolder: RecyclerView.ViewHolder,
    toViewHolder: RecyclerView.ViewHolder
): Boolean {
    val fromPosition = fromViewHolder.bindingAdapterPosition
    val toPosition = toViewHolder.bindingAdapterPosition
    val imagesSize = this.images.size

    if (fromPosition < imagesSize && toPosition < imagesSize) {
        if (fromPosition < toPosition) {
            for (i in fromPosition until toPosition) {
                Collections.swap(this.images, i, i + 1)
            }
            notifyItemMoved(fromPosition, toPosition)
        } else {
            for (i in fromPosition downTo toPosition + 1) {
                Collections.swap(this.images, i, i - 1)
            }
            notifyItemMoved(toPosition, fromPosition)
        }

        Handler().postDelayed({
            notifyDataSetChanged()
        }, 1000)
        return true
    }
    return false
}

问题分析

崩溃日志明确指出索引-1越界,说明fromPosition或toPosition的值为-1。bindingAdapterPosition在ViewHolder已被回收、或对应数据源项已被删除时,会返回-1。当前代码只判断了位置小于集合长度,未校验位置是否≥0,导致无效位置进入数据交换逻辑触发异常。

另外,循环调用Collections.swap移动元素效率较低;延迟调用notifyDataSetChanged完全多余——notifyItemMoved已能精准通知RecyclerView更新UI,全局刷新反而会破坏拖拽流畅性。


修复方案

  1. 先校验fromPosition和toPosition的有效性,必须同时满足≥0且<imagesSize,且两个位置不相同,否则直接返回false
  2. 简化数据移动逻辑:直接移除原位置元素并插入到目标位置,替代循环swap
  3. 移除不必要的notifyDataSetChanged调用

修改后的代码:

val touchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {

    ...

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

})

fun onRowMoved(
    fromViewHolder: RecyclerView.ViewHolder,
    toViewHolder: RecyclerView.ViewHolder
): Boolean {
    val fromPosition = fromViewHolder.bindingAdapterPosition
    val toPosition = toViewHolder.bindingAdapterPosition
    val imagesSize = this.images.size

    // 校验位置有效性,排除-1、超出范围或相同位置的情况
    if (fromPosition in 0 until imagesSize && toPosition in 0 until imagesSize && fromPosition != toPosition) {
        // 直接移动元素,替代循环swap
        val movedItem = images.removeAt(fromPosition)
        images.add(toPosition, movedItem)
        // 精准通知UI更新
        notifyItemMoved(fromPosition, toPosition)
        return true
    }
    return false
}

内容的提问来源于stack exchange,提问作者Oğuzhan Türkmen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 00:27:12