0

我有一个RecyclerView使用PagedListAdapterROOM网络 API 获取数据的。它使用一个BoundaryCallback向API发出请求,返回的数据被插入到数据库(ROOM)中

我有一个具有递增和递减按钮的列表项... 在此处输入图像描述

当前列表是可过滤的,例如我可以按多个类别过滤产品列表

问题

如果我使用增量按钮将产品项目quantity增加到例如 12,然后我尝试通过添加更多类别来过滤列表,则当前列表不会刷新,这很好,因为 DiffUtil.ItemCallback 确认项目是相同的,但是一旦我尝试在按更多类别过滤后增加同一产品的数量,它就会再次从零开始......

请注意,数量不是房间中的一列,它是一个被忽略的变量。

所以我不太确定问题到底是什么:下面是执行递增和递减的代码。

override fun onIncrementQuantity(position: Int, item: ProductEntity) {
    item.quantity = item.quantity + 1
    selectedProducts[item.item.id!!] = item
    productAdapter?.notifyItemChanged(position, item)
}
override fun onDecrementQuantity(position: Int, item: ProductEntity) {
    item.quantity = if (item.quantity == 0) 0 else item.quantity - 1
    if (item.quantity == 0) {
        selectedProducts.remove(item.item.id)
    } else {
        selectedProducts[item.item.id!!] = item
    }
    productAdapter?.notifyItemChanged(position, item)
}
4

1 回答 1

0

因此,经过数小时的调试后,我发现了这一点。

  • 列表最初加载了数据
  • 对当前数据进行更新,例如增量item.quantity = 2
  • 一旦获取了新数据(通过搜索或过滤器),如果itemsAretheSameContentsAreThemSame则不会调用 onBindViewHolder,因此无需更新视图。此时一切都很好。

但是,似乎 currentList 已更新为新获取的数据,而不必更新视图......现在,当notifyItemChanged被调用时,触发了 onBindViewHolder:

onBindViewHolder的就是这样

override fun onBindViewHolder(holder: ViewHolder<T>, position: Int) {
    getItem(position)?.let { holder.bind(it) }
}

getItem(position)为您提供当前列表中已更新且数量恢复为默认值 0 的项目。

解决方案

覆盖下面的函数RecyclerView.Adapter

override fun onBindViewHolder(
    holder: ViewHolder<ProductEntity>, 
    pos: Int, 
    payloads: MutableList<Any>
) { 
    if(payloads.isEmpty()) return super.onBindViewHolder(holder, pos, payloads)
    val product = getItem(pos)?: return
    payloads.forEach {
       val oldProduct = it as ProductEntity
       if(product.item.id == oldProduct.item.id){
          product.quauntity = oldProduct.quantity
       }
    }
}

有效载荷应包括可用于更新新数据的部分旧数据。

根据文档

     * The payloads parameter is a merge list from {@link #notifyItemChanged(int, Object)} or
     * {@link #notifyItemRangeChanged(int, int, Object)}.  If the payloads list is not empty,
     * the ViewHolder is currently bound to old data and Adapter may run an efficient partial
     * update using the payload info.  If the payload is empty,  Adapter must run a full bind.
     * Adapter should not assume that the payload passed in notify methods will be received by
     * onBindViewHolder().  For example when the view is not attached to the screen, the
     * payload in notifyItemChange() will be simply dropped.
于 2020-07-14T20:40:49.827 回答