【问题标题】:Recyclerview DiffUtil Item UpdateRecyclerview DiffUtil 项目更新
【发布时间】:2026-01-22 01:15:01
【问题描述】:

我的 recyclerview 中有无限滚动,所以当有新数据时它会更新。我正在使用 DiffUtil 更新 recyclerview 中的数据。 DiffUtil 确实会更新数据,但只要有更新数据,recyclerview 就会滚动到顶部,看起来就像“使用 notifydatasetchanged()”。这是我的 DiffUtil 和用于更新数据的适配器。

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)
    }
}

这是我更新数据的适配器

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

请帮我解决这个问题。当我使用 notifyItemRangeChanged() 时它工作正常......所以我应该使用什么来更新 recyclerview 中的数据以获得最佳实践。

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

【问题讨论】:

  • 使用 notifyitemrangeinserted 方法。
  • 我最初使用的是 notifyItemRangeInserted() 但 diffUtil 使列表更快,所以我正在尝试使用它。
  • DiffUtil.ItemCallback&lt;T&gt;() 代替DiffUtil.Callback 怎么样。
  • 你是如何实现适配器的?你是使用分页库还是定制的?

标签: android kotlin android-recyclerview android-diffutils


【解决方案1】:

您只是将以前的内容与新项目进行比较,而不是与添加了所有项目的列表进行比较。

假设this.productList 当前是1,2,3,而新的productList4,5,6。当你运行时

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

它会将1425 等进行比较,并得出结论:一切都发生了变化,并且没有添加新项目。 (注意:这是对 DiffUtil 算法的过度简化,但用于说明这一点)

如果你想使用 DiffUtil:

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

或者,由于您确切知道添加了多少项目以及在何处添加,只需使用 notifyItemRangeInserted 并避免复制:

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

【讨论】:

  • fun addProductList(productList: List?) 此方法仅更新来自 api 的新列表数据。所以,如果我这样做,列表的大小将不会改变。例如,this.productlist 为 1,2,3,新产品列表为 4,5,6。它不会包含 1,2,3,4,5,6。我按照你说的试过了,但不符合我的需要。我怎样才能得到这个?你能告诉我这个例子或其他的吗?
  • 啊,我明白了 - 从问题中并不清楚。我已经更新了我的答案以考虑到这一点 - 看看是否能解决你的问题。考虑到这种行为,这更有意义。
  • 感谢您的回答。它帮助我解决了我的问题。抱歉,兄弟重播晚了。
【解决方案2】:

考虑创建一个通用的 diffUtil 类,而不是为每个适配器创建它。

fun <T>diffList(oldList: List<T>, newList: List<T>, sameItem: (a: T, b: T) -> Boolean): DiffUtil.DiffResult {
val callback: DiffUtil.Callback = object : 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 sameItem(oldList[oldItemPosition], newList[newItemPosition])
    }

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

return DiffUtil.calculateDiff(callback) }

您可以像这样在适配器中使用它:

 fun setItems(products: List<Product>) {
    val oldList = productList
    productList = products
    diffList(oldList, products, sameItem = { a, b -> a.id == b.id }).dispatchUpdatesTo(this)
}

【讨论】:

    【解决方案3】:

    检查布局管理器是否已经设置并获取当前滚动位置。像这样:

    var itemPostion= 0
    if(myRecyclerView.layoutmanager != null){
      itemPostion = (myRecyclerView.layoutmanager as LinearLayoutManager)
    .findFirstCompletelyVisibleItemPosition()
    }
    

    您可以在 GitHub 上查看此示例项目

    【讨论】:

    • 这不应该是必要的,他们不应该更换适配器。
    • @RyanMentley 它没有更换适配器。它恢复了他想要解决的上一个滚动位置,而不是在数据更新时滚动回顶部。
    • RecyclerView 在更新时默认不会滚动到顶部。这不应该是必要的。
    最近更新 更多