【问题标题】:Recyclerview ListAdapter DiffUtil not working as expectedRecyclerview ListAdapter DiffUtil 未按预期工作
【发布时间】:2019-01-16 12:57:50
【问题描述】:

我的 diffcallback areContentsTheSame(oldItem: ItemModel, newItem: ItemModel) 总是收到相同的内容。我使用状态来检查,但每次状态都是一样的。尽管状态实际上正在发生变化。我打算显示每个项目的进度。所以我定期通过状态发送当前进度。使用 diffcallback,它应该检查项目的状态是否不同,然后仅更新该项目。但它收到的 newItem 和 oldItem 似乎是相同的。

我有一个自定义模型ItemModel

data class ItemModel(val id: String, var title: String) {

    var clickListener: ClickListener? = null
    var status: Status? = null

    interface ClickListener{
        fun onItemClick(view: View, item: ItemModel)
        fun onClick(view: View, item: ItemModel)
    }

    companion object {
        val STATUS_CHANGED = 1

        val diffCallback = object : DiffUtil.ItemCallback<ItemModel>() {
            override fun areItemsTheSame(oldItem: ItemModel, newItem: ItemModel): Boolean {
//                Log.i("DiffUtil", "SameItem? old status: ${oldItem.status}, new Status: ${newItem.status}")
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: ItemModel, newItem: ItemModel): Boolean {
//                Log.i("DiffUtil", "Checking status: new: ${newItem.status}, old ${oldItem.status}")
                return oldItem.status == newItem.status
            }

            override fun getChangePayload(oldItem: ItemModel, newItem: ItemModel): Any? {
                Log.i("DiffUtil", "Payload change: ${newItem.status?.state}")
                if (oldItem.status != newItem.status) {
                    return STATUS_CHANGED
                }
                return null
            }

        }
    }
}

和Status数据类

data class Status(val max: Int, val progress: Int, val state: State = State.NONE)

这是我的 ViewModel 类;我使用Observable.intervalRange 生成不同的数字并更改单个列表项的状态。但似乎 diffcallback 无法正常工作。

class FunViewModel : ViewModel() {

    private val itemModels: MutableLiveData<List<ItemModel>> = MutableLiveData()

    fun items(): LiveData<List<ItemModel>> {
        return itemModels
    }

    private val compositeDisposable = CompositeDisposable()

    fun initialize(itemList: List<ItemModel>) {
        itemModels.value = itemList
    }

    private fun updateItem(item: ItemModel, status: Status) {
        val currentItems = mutableListOf<ItemModel>()
        if (itemModels.value == null) return
        currentItems.addAll(itemModels.value!!)

        Log.i("UpdateItem", "Current item: ${item.id}")

        if (currentItems.isNotEmpty()) {
            for ((index, el) in currentItems.withIndex()) {
//                Log.i("UpdateItem", "searching: ${el.id}")
                if (el.id == item.id) {
                    val currentItem = currentItems.removeAt(index)
                    Log.i("UpdateItem", "old status: ${currentItem.status}")
                    currentItem.status = status
                    currentItems.add(index, currentItem)
                    break
                }
            }
            itemModels.value = currentItems
            Log.i("UpdateItem", "new status: ${items().value?.get(0)?.status}")
        }
    }

    fun startProgress(item: ItemModel) {
        val disposable = getProgress(item.id).map { progress ->
            val status = Status(progress.second.toInt(), progress.third.toInt(), State.IN_PROGRESS)
            status
        }.subscribeOn(Schedulers.single())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ status ->
                updateItem(item, status)
//                Log.i("FunViewModel:", "Status: progress: ${status.progress}, State: ${status.state}")
            },
                { throwable: Throwable? -> Log.e("FunViewModel", "Unable to process progress!", throwable) },
                {
                    val status = Status(20, 20, State.COMPLETED)
                    updateItem(item, status)
                    Log.i("FunViewModel:", "Status: progress: ${status.progress}, State: ${status.state}")
                })
        compositeDisposable.add(disposable)
    }


    private fun getProgress(id: String): Observable<Triple<String, Long, Long>> {
        return Observable.intervalRange(0, 20, 300, 500, TimeUnit.MILLISECONDS)
            .map { num -> Triple<String, Long, Long>(id, 20, num) }
    }

    override fun onCleared() {
        super.onCleared()
        if (!compositeDisposable.isDisposed) compositeDisposable.dispose()
    }
}

【问题讨论】:

    标签: android android-recyclerview android-livedata android-viewmodel


    【解决方案1】:

    好吧,我发现问题在于我以一种不进行实际内容复制而是引用的方式复制原始内容。所以我通过将项目内容复制到一个新的 itemModel 实例来解决这个问题。完成此操作后,diff util 能够正确区分。

    取而代之的是,

    private fun updateItem(item: ItemModel, status: Status) {
           ......................................................
    
    
                for ((index, el) in currentItems.withIndex()) {
                    if (el.id == item.id) {
                        val currentItem = currentItems.removeAt(index)
    
                        currentItem.status = status
                        currentItems.add(index, currentItem)
                        break
                    }
                }
                itemModels.value = currentItems
              ......................................
        }
    

    我做到了,

    private fun updateItem(item: ItemModel, status: Status) {
    ...............
        if (el.id == item.id) {
             currentItems.removeAt(index)
             val currentItem = ItemModel(item.id, "${item.title}, ${status.progress}")
             currentItem.status = status
             currentItems.add(index, currentItem)
             break
         }
    ...........
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-12
      • 2021-06-04
      • 2022-01-24
      • 2015-05-11
      相关资源
      最近更新 更多