androidkotlinandroid-recyclerviewandroid-diffutils

Recyclerview DiffUtil Item Update


I have endless scroll in my recyclerview, so, it will update when there is new data. and i am using DiffUtil to update data in the recyclerview. DiffUtil does updates the data but whenever there is update data, recyclerview scroll to top and what it looks like is "using the notifydatasetchanged()". here is my DiffUtil and my adapter to update data.

class ProductDiffUtil(
    val oldProductList: List<ProductModel>, val newProductList: List<ProductModel>
) : DiffUtil.Callback() {

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldProductList[oldItemPosition].id == newProductList[newItemPosition].id
    }

    override fun getOldListSize(): Int = oldProductList.size

    override fun getNewListSize(): Int = newProductList.size

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldProductList[oldItemPosition] == newProductList[newItemPosition]
    }

    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
        return super.getChangePayload(oldItemPosition, newItemPosition)
    }
}

Here is my adapter to update data

fun addProductList(productList: List<ProductModel>?) {
        val diffResult = DiffUtil.calculateDiff(ProductDiffUtil(this.productList, productList!!))
        this.productList.addAll(productList)
        diffResult.dispatchUpdatesTo(this)
    }

please help me with this. it is working fine when i am using notifyItemRangeChanged()... so what should i use to update data in recyclerview for best practice.

https://drive.google.com/open?id=1SapXW2wusmTpyGCRA9fa0aSLCYNL1fzN


Solution

  • You're comparing the previous contents against only the new items, rather than against the list with all of them added.

    Imagine if this.productList is currently 1,2,3, and the new productList is 4,5,6. When you run

    DiffUtil.calculateDiff(ProductDiffUtil(this.productList, productList!!)
    

    It will compare 1 to 4, 2 to 5, etc. and conclude that everything has changed and no new items have been added. (note: this is an oversimplification of the DiffUtil algorithm, but serves to illustrate the point)

    Instead, if you want to use DiffUtil:

    val oldList = ArrayList(productList)
    this.productList.addAll(productList)
    val diffResult = DiffUtil.calculateDiff(ProductDiffUtil(oldList, productList!!)
    diffResult.dispatchUpdatesTo(this)
    

    or, since you know exactly how many items are added and where, just use notifyItemRangeInserted and avoid the copy:

    val oldSize = this.productList.size
    this.productList.addAll(productList)
    notifyItemRangeInserted(oldSize, productList.size)