首页 > 解决方案 > Android SortedList 拖动并重新排序项目抛出 IndexOutOfBoundsException:检测到不一致。无效的视图支架适配器 positionViewHolde

问题描述

我在使用sortedList实现回收视图时遇到问题。我需要为此回收视图实现拖动和重新排序功能,我使用“ItemTouchHelper.Callback()”来处理向上/向下移动

 class SimpleItemTouchHelperCallback(private val mAdapter: ItemTouchHelperAdapter) :
        ItemTouchHelper.Callback() {

    override fun onMove(
            recyclerView: RecyclerView,
            source: RecyclerView.ViewHolder,
            target: RecyclerView.ViewHolder
        ): Boolean {
            if (source.itemViewType != target.itemViewType) {
                return false
            }

            val fromPosition = source.adapterPosition
            val toPosition = target.adapterPosition
            dragFrom = fromPosition
            dragTo = toPosition

            Timber.d(">> SimpleItemTouchHelperCallback ->>> onMove fromPosition = $fromPosition | toPosition = $toPosition")

            // Notify the adapter of the move
            mAdapter.onItemMove(dragFrom, dragTo)
            return true
        }


        override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {

            super.clearView(recyclerView, viewHolder)
            viewHolder.itemView.alpha = ALPHA_FULL
            if (viewHolder is ItemTouchHelperViewHolder) {
                // Tell the view holder it's time to restore the idle state
                val itemViewHolder = viewHolder as ItemTouchHelperViewHolder
                itemViewHolder.onItemClear()

                // To detect when an interaction with an element is over
                if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
                    mAdapter.dragAndDropCompleted(dragFrom, dragTo)
                }
                dragFrom = -1
                dragTo = -1
            }
        }

    }

//===========
class ShoppingListRecyclerListAdapter(
    private val onItemClickListener: OnItemClickListener,
    private val userCheckedInToStore: Boolean
) : RecyclerView.Adapter<BaseShoppingListViewHolder>(), ItemTouchHelperAdapter {

    private var sortedItemList: SortedList<ShoppingListEntry>

 override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
  var dragFromItem = sortedItemList[fromPosition]
        var dragToItem = sortedItemList[toPosition]

        if (dragFromItem is UnCheckedFreeTextItem && dragToItem is UnCheckedFreeTextItem) {


 val dragFromItemSortIndex = dragFromItem.freeTextShoppingItem.sortIndex
            val dragFromItemName = dragFromItem.freeTextShoppingItem.itemName


            dragFromItem.freeTextShoppingItem.sortIndex =
                dragToItem.freeTextShoppingItem.sortIndex

            dragToItem.freeTextShoppingItem.sortIndex = dragFromItemSortIndex

            dragToItem.modify = true
            dragFromItem.modify = true


            dragFromItem.freeTextShoppingItem.itemName =
                dragToItem.freeTextShoppingItem.itemName

            dragToItem.freeTextShoppingItem.itemName = dragFromItemName


            dragItemSet.add(dragToItem)
            dragItemSet.add(dragFromItem)

            sortedItemList.beginBatchedUpdates()
            //sortedItemList.recalculatePositionOfItemAt(fromPosition)
            sortedItemList.updateItemAt(fromPosition, dragFromItem)

            //sortedItemList.recalculatePositionOfItemAt(toPosition)
           sortedItemList.updateItemAt(toPosition, dragToItem)

             //sortedItemList.recalculatePositionOfItemAt(fromPosition)
             //sortedItemList.recalculatePositionOfItemAt(toPosition)
            //sortedItemList.updateItemAt(fromPosition, dragToItem)
            sortedItemList.endBatchedUpdates()

}


 }
}

当用户长按一个项目并开始移动时出现异常

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{c026f4 position=6 id=39, oldPos=6, pLpos:-1 scrap [attachedScrap] 
tmpDetached no parent} androidx.recyclerview.widget.RecyclerView{1991c2a VFED.V... ......ID 0,364-1080,1980 #7f0a01db app:id/shoppingListView}, 
adapter:com.adingk.lib.ui.shoppinglist.ShoppingListRecyclerListAdapter@741fa1b, layout:androidx.recyclerview.widget.LinearLayoutManager@d2de7b8, 
context:com.adingk.lib.ui.shoppinglist.ManageShoppingListActivity@76ea334
      at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5715)
      at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5898)
      at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
      at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
      at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
      at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
      at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
      at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
      at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3875)
      at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3639)
      at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
      at android.view.View.layout(View.java:21927)
      at android.view.ViewGroup.layout(ViewGroup.java:6260)

标签: androidkotlinandroid-recyclerviewandroid-viewholderitemtouchhelper

解决方案


而不是使用updateItemAttry to use notifyItemMoved(fromPosition, toPosition)which is 提供的方法RecyclerView.Adapter

override fun onItemMove(fromPosition: Int, toPosition: Int) {
    notifyItemMoved(fromPosition, toPosition)
}

推荐阅读