I'm facing an issue with the implementation of the onRowMoved function within my RecyclerView adapter.
This function is responsible for handling item movements in the RecyclerView when items are dragged and dropped.
However, I'm encountering a java.lang.IndexOutOfBoundsException.
My code is:
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
}
Crash logs are following:
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)
It looks like you're using bindingAdapterPosition to get the adapter position of the ViewHolders, but keep in mind that bindingAdapterPosition can return NO_POSITION if the ViewHolder is not currently in the adapter. When you move an item, the adapter positions of the affected items might change.
fun onRowMoved(
fromViewHolder: RecyclerView.ViewHolder,
toViewHolder: RecyclerView.ViewHolder
Boolean {
val fromPosition = fromViewHolder.adapterPosition
val toPosition = toViewHolder.adapterPosition
val imagesSize = this.images.size
if (fromPosition != RecyclerView.NO_POSITION && toPosition !=
RecyclerView.NO_POSITION &&
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(fromPosition, toPosition)
}
Handler().postDelayed({
notifyDataSetChanged()
}, 1000)
return true
}
return false
}