3

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
3
  • Found any solution? Commented Feb 25, 2022 at 11:03
  • 1
    @AsthaGarg the only work round i found is creating a copy of the old listings to use it to calculate the difference. val diffCallBack = BriefDiffCallBack(ArrayList(listings), newListings) Commented Feb 25, 2022 at 11:38
  • @AsthaGarg see the answer below Commented Feb 25, 2022 at 11:45

1 Answer 1

1

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)
}
Sign up to request clarification or add additional context in comments.

2 Comments

How is it helping you? I mean can you briefly explain your solution
Thanks, I'm using the same solution now, hoping to not see same crash on Playstore

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.