简体   繁体   中英

DiffUtil clashes with ArrayIndexOutOfBoundsException when updating the recyclerview adapter list

I'm trying to update ViewPager2 adapter with a new list of items using DiffUtil but it keeps clashing now and then.

from the Fragment

private suspend fun updateMap(items: List<Item>) {
       
        briefAdapter.submitList(items)
        
    }

Adapter

 private var items = ArrayList<Item>()

    
    override fun getItemCount(): Int {
        return items.size
    }

    suspend fun submitList(newItems: List<Item>) {
        val diff = withContext(Dispatchers.Default) {
            val diffCallBack = BriefDiffCallBack(items, newItems)
            val diffResult = DiffUtil.calculateDiff(diffCallBack)
            diffResult
        }
        items.clear()
        items.addAll(newItems)
        diff.dispatchUpdatesTo(this)
    }

DiffCallBack implementation

class BriefDiffCallBack(
    private val oldList: List<Item>,
    private val newList: List<Item>
) : DiffUtil.Callback() {


    override fun getOldListSize(): Int {
        return oldList.size
    }

    override fun getNewListSize(): Int {
        return newList.size
    }

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return try {
            val old = oldList[oldItemPosition]
            val new = newList[newItemPosition]
            
            old.id == new.id 
            
        } catch (exc: Exception) {
            exc.printStackTrace();
            false
        }
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return try {
            val old = oldList[oldItemPosition]
            val new = newList[newItemPosition]

            return old == new
           
        } catch (exc: Exception) {
            exc.printStackTrace();
            false
        }
    }
}

Clash

androidx.recyclerview.widget.DiffUtil$DiffResult.findMatchingAddition
DiffUtil.java, line 744
java.lang.ArrayIndexOutOfBoundsException: length=45; index=45

stacktrace

androidx.recyclerview.widget.DiffUtil$DiffResult.findMatchingAddition DiffUtil.java:744
androidx.recyclerview.widget.DiffUtil$DiffResult.findMoveMatches DiffUtil.java:723
androidx.recyclerview.widget.DiffUtil$DiffResult.findMatchingItems DiffUtil.java:712
androidx.recyclerview.widget.DiffUtil$DiffResult.<init> DiffUtil.java:675
androidx.recyclerview.widget.DiffUtil.calculateDiff DiffUtil.java:178
androidx.recyclerview.widget.DiffUtil.calculateDiff DiffUtil.java:106
ListingBriefAdapter$submitList$diff$1.invokeSuspend BriefAdapter.kt:46
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith ContinuationImpl.kt:33
kotlinx.coroutines.DispatchedTask.run DispatchedTask.kt:106
kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely CoroutineScheduler.kt:571
kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask CoroutineScheduler.kt:750
kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker CoroutineScheduler.kt:678
kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run CoroutineScheduler.kt:665

Updating the adapter's arraylist while accessing the arraylist items at the same time was the root cause of ArrayIndexOutOfBoundsException being thrown by the DiffUtil library. To avoid this and still maintain a smooth update of the UI, i made a copy of the underlying adapter's list and used it to calculate the difference instead of using the adapter's list directly ( BriefDiffCallBack(ArrayList(items), newItems) ). This ensured that the user will continue interacting with the old arraylist untill the difference in the two lists has being calculated and update is available.

Adapter class

private var items = ArrayList<Item>()


override fun getItemCount(): Int {
    return items.size
}

suspend fun submitList(newItems: List<Item>) {
    val diff = withContext(Dispatchers.Default) {
        val diffCallBack = BriefDiffCallBack(ArrayList(items), newItems)
        val diffResult = DiffUtil.calculateDiff(diffCallBack)
        diffResult
    }
    items.clear()
    items.addAll(newItems)
    diff.dispatchUpdatesTo(this)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM