当前位置: 首页 > 知识库问答 >
问题:

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

范浩宕
2023-03-14

嘿,我是DiffUtil在adpater中的新手。我从堆栈溢出、谷歌文档和一些文章中阅读了一些文章。我正在尝试理解DiffUtil areItemsThe相同和areContentsThe相同的回调,但我不清楚这是什么意思。我正在添加一些代码,请看看。如果我做错了,请指导我。

群策

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

我正在将我的列表传递给适配器,这是一个组可变列表

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.在这里,我需要比较关键的其他属性,如类型,发件人等,也在这个DiffUtil.ItemCallback中。

2.何时使用==或===以及equals()呢

3.如果我们比较int、boolean或String,我们使用==或其他东西?

在这个适配器里面,我正在调用另一个回收器视图,并在该适配器内传递项目列表。

项目

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

NestedRecyclView.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个答案

常培
2023-03-14

问题 1 和 4:

< code>areItemsTheSame意味着这两个实例表示相同的数据项,即使某些内容可能不同。假设您有一个联系人列表,Jane的中间名已经被更改,但是该行仍然表示同一个人Jane。您的模型类可能有不同的实例,具有一些不同的值,但是它们应该表示同一行。

因此,通常情况下,在旧项目和新项目之间只比较一件事,在这种情况下,它们中的每一项都是相同的。通常,如果您从数据库或API获取数据,则会有一些表示数据点的唯一ID,这就是您需要在<code>中进行比较的全部内容。例如,oldItem。id==newItem.id

areContentsThe相同意味着如果这两个实例都显示在您的列表中,它们看起来将是相同的。因此,如果您使用的是数据类,则使用oldItem==newItem就足够了,因为数据类有一个比较每个属性的equals函数

在你的 Item 回调代码中,看起来你的 areItemsTheSame 是正确的,但你的 areContentsTheSame 过于复杂。由于 Item 是一个数据类,因此只需直接比较这两个项目。

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

在你的组回调代码中,也许你可以比较新旧条目的组键,如果这是确定条目相同的有效方法的话。因为您只使用直接的< code>==比较,所以当项目部分更改时,您可能会有一些视觉缺陷,如视图消失和重新出现,而不是简单地更改一些文本。

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

问题3==是比较任何两个对象的正确方法,在静态编程语言中,即使是原语也应该这样比较,因为它们的行为类似于对象。

问题5使用ListAdapter,您应该始终使用submitList而不是通知数据设置更改通知数据设置更改会导致所有视图的无意义刷新并破坏使用ListAdapter和DiffUtil的目的。

 类似资料:
  • 我正在使用SQLite数据库填充RecyclerView。我想让RecyclerView实时更新。但我失败了。我尝试过使用“notifyDataSetChanged()”但它不起作用。 你能不能也告诉我如何通过制作一个“新适配器”来刷新回收器视图。 哪个是更好的通知DataSetChanged();或任何其他? 这是我的回收水 **编辑: adapter.update数据(列表); 在“locat

  • 问题内容: 我有一个扩展ExpandableListActivity的活动。我使用SimpleCursorTreeAdapter填充ExpandableListView。我的布局包含列表视图和空视图。在应用启动时,ExpandableListActivity自动选择要显示的右视图。 我的步骤: 应用启动,没有数据。(屏幕上的空白视图) 将一些数据插入db。 调用adapter.notifyData

  • 我在android应用程序上使用自定义适配器查看列表。我不知道如何设置项目单击的侦听器。我的应用程序使用Kotlin。 这是我的适配器布局。 有人可以帮助我吗?

  • 您好,我目前正在使用Recyclerview ListAdapter,我想知道什么是等价的通知DataSetChanged或如何在添加值/记录后更新整个列表。? 我目前使用过此方法,但如果不刷新,则不会更新。 我想回到回收器视图。适配器和通知数据设置更改()。这样我的问题就解决了,你觉得怎么样?提前谢谢。

  • 我想确定回收站视图中最明显的项目,因此我使用以下方法: 它工作得很好,但是在我更改数据集,并在我的适配器中调用任何方法后,如果我尝试使用上述函数,则和返回的项目位置是错误的。 我注意到他们都在幕后使用getlayoutposition,我还注意到在文档上写着: 听起来好像正是我正在寻找的,但我不知道如何从中访问它。 有什么想法吗? 谢谢你。

  • > 从创建的片段中更新,将新数据设置为adapter,然后调用;但没有奏效。 像其他人一样创建一个新适配器,它对他们起作用,但对我没有任何改变: 在中创建一个更新数据的方法,如下所示: 问题是gridView的布局如下所示: 然后我只是删除了并将作为父布局。