0

ネットワーク APIからデータをフェッチするをRecyclerView使用するがあります。を使用して、返されたデータがデータベース (ROOM) に挿入される API に要求を行います。PagedListAdapterROOMBoundaryCallback

増分ボタンと減分ボタンがあるリスト項目があります... ここに画像の説明を入力

現在のリストはフィルタリング可能です。たとえば、製品のリストを複数のカテゴリでフィルタリングできます

問題

インクリメント ボタンを使用して製品アイテム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
  • 新しいデータが (検索またはフィルターを介して) フェッチされると、itemsAretheSameまたはContentsAreThemSameの場合、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 に答える