在适配器 kotlin 中更新视图时如何正确使用 Diff utils

How to proper way of using Diff utils when updating view in adapter kotlin

嘿,我是 Adpater 中 DiffUtil 的新手。我阅读了一些来自堆栈溢出的文章、google 文档和一些文章。我试图理解 callback of DiffUtil areItemsTheSameareContentsTheSame 但是,我不清楚那是什么意思。我正在添加一些代码,请看一下。如果我做错了,请指导我。

组键

data class GroupKey(
    val type: EnumType,
    val sender: Sender? = null,
    val close: String? = null
)

枚举类型

enum class EnumType {
    A,
    B
}

发件人

data class Sender(
    val company: RoleType? = null,
    val id: String? = null
)

角色类型

data class RoleType(
    val name : String?= null
    val id: String? = null
)

data class Group(
    val key: GroupKey,
    val value: MutableList<Item?>
)

我正在将我的列表传递给适配器,它是一个 Group mutableList

var messageGroupList: MutableList<Group>? = null
..
val adapter = MainAdapter()
binding.recylerview.adapter = adapter
adapter.submitList(groupList)

在适配器

中使用DiffUtil

MainAdapter.kt

class MainAdapter :ListAdapter<Group, RecyclerView.ViewHolder>(COMPARATOR) {

    companion object {
        private val COMPARATOR = object : DiffUtil.ItemCallback<Group>() {
            override fun areItemsTheSame(oldItem: Group, newItem: Group): Boolean {
                return oldItem == newItem
            }

            override fun areContentsTheSame(oldItem: Group, newItem: Group): Boolean {
                return ((oldItem.value == newItem.value) && (oldItem.key == newItem.key))
            }
        }
    }
.....
}

1. 这里需要比较key other 属性 like type, sender etc . 也在这个 DiffUtil.ItemCallback.

里面

2. 何时使用 ===== 以及 等于()

3.如果我们比较intbooleanString 我们使用 == 或者其他的 ?

在此适配器内,我正在调用另一个 Recyclerview,并在该适配器内传递 Item 列表。

项目

data class Item(
    val text: String? = null,
    var isRead: Boolean? = null,
    val sender: Sender? = null,
    val id: Int? = null
)

NestedRecyclerView.kt

class NestedRecyclerView : ListAdapter<Item, IncomingMessagesViewHolder>(COMPARATOR) {

    companion object {
        private val COMPARATOR = object : DiffUtil.ItemCallback<Item>() {
            override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
                return ((oldItem.isRead == oldItem.isRead) &&
                        (oldItem.sender == newItem.sender) &&
                        (oldItem.text == oldItem.text))
            }
        }
    }
}

同样的问题我是否需要在这里也比较发件人的其他属性。

4.areItemsTheSame 中,我需要比较 id 还是 oldItem == newItem 这个?

5. 如何正确更新我的适配器项目。在正常的 reyclerview 中,我们使用 notifiyDataSetChanged。但是在 diffutil 中,我是否需要再次调用 submitList 函数,它会处理所有事情?

adapter.submitList(groupList)

问题 1 和 4:

areItemsTheSame 表示两个实例表示相同的数据项,即使某些内容可能不同。假设您有一个联系人列表,并且 Jane 的中间名首字母已更改,但该行仍应代表同一个人 Jane。您的模型 class 可能有不同的实例,具有一些不同的值,但它们应该代表同一行。

因此,在这种情况下,通常您只会比较旧项目和新项目之间的一件事,这对每个项目来说都是一样的。通常,如果您从数据库或 API 获取数据,将会有一些唯一的 ID 代表一个数据点,这就是您需要在 areItemsTheSame 中进行比较的全部内容。例如,oldItem.id == newItem.id.

areContentsTheSame 表示如果这两个实例分别显示在您的列表中,它们将看起来完全相同。因此,如果您使用 data class,使用 oldItem == newItem 就足够了,因为数据 class 有一个 equals 函数,可以比较每个 属性.

在您的 Item 回调代码中,您的 areItemsTheSame 看起来是正确的,但您的 areContentsTheSame 过于复杂。由于Item是一个数据class,直接比较两个item即可

override fun areContentsTheSame(oldItem: Item, newItem: Item) = oldItem == newItem

在您的组回调代码中,也许您可​​以比较新旧项目的 GroupKeys,如果这是确定项目相同的有效方法的话。由于您仅使用直接 == 比较,当项目部分更改时,您可能会遇到一些视觉缺陷,例如视图消失和重新出现,而不是简单地更改其中的一些文本。

问题 2 你应该很少在 Kotlin 中使用 ===。它不仅检查两个项目是否等价,而且检查这两个项目是否引用内存中的完全相同的实例。它根本不适合 DiffUtil.ItemCallback。

问题 3 == 是比较任意两个对象的正确方法。在 Kotlin 中,即使是基元也应该以这种方式进行比较,因为它们的行为类似于对象。

问题 5 对于 ListAdapter,您应该始终使用 submitList 而不是 notifyDataSetChangednotifyDataSetChanged 会导致所有视图的无意义刷新并破坏使用 ListAdapter 和 DiffUtil 的目的。