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

Time:10-22

Hey I am new in DiffUtil in adpater. I read some articles from stack overflow, google docs and some articles. I am trying to understand callback of DiffUtil areItemsTheSame and areContentsTheSame but, I am not clear what that means. I am adding some code, please have a look. If I am doing wrong please guide me.

GroupKey

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

EnumType

enum class EnumType {
    A,
    B
}

Sender

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

RoleType

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

Group

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

I am passing my list to adapter which is a Group mutableList

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

Using DiffUtil in adapter

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. Here do I need to compare key other property like type, sender etc. also inside this DiffUtil.ItemCallback.

2. when to use == or === and what about equals()

3. If we compare int, boolean or String we use == or something else ?

Inside this adapter I am calling another Recyclerview with passing list of Item inside that adapter.

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

Again Same question Do I need to compare sender's other property here as well.

4. In areItemsTheSame do I need to compare id or just oldItem == newItem this?

5. How to proper way to update my adapter items. In normal reyclerview we use notifiyDataSetChanged. But in diffutil do I need to call again submitList function and it will take care of everything?

adapter.submitList(groupList)

CodePudding user response:

Questions 1 and 4:

areItemsTheSame means that the two instances represent the same data item, even if some of the contents might be different. Suppose you had a list of contacts, and Jane's middle initial has been changed, but the row should still represent the same person Jane. There might be distinct instances of your model class, with some different values, but they are supposed to represent the same row.

So, usually you will compare only one thing between the old and new items that will be the same for each of them in this case. Usually, if you're getting data from a database or API, there will be some unique ID that represents a data point, and that's all you need to compare in areItemsTheSame. For example, oldItem.id == newItem.id.

areContentsTheSame means that if the two instances were each displayed in your list, they would look identical. So if you are using a data class, it is sufficient to use oldItem == newItem because a data class has an equals function that compares every property.

In your Item callback code, it looks like your areItemsTheSame is correct, but your areContentsTheSame is overly complex. Since Item is a data class, you only need to compare the two items directly.

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

In your Group callback code, maybe you can compare the GroupKeys of the old and new items if that is a valid way to determine the items are the same. Since you are using only a direct == comparison, when items change partially you might have some visual defects like views disappearing and reappearing instead of simply having some of their text change.

Question 2 You should rarely ever have to use === in Kotlin. It does not only check if two items are equivalent, but it checks if the two items refer to the exact same instance in memory. It is not appropriate for DiffUtil.ItemCallback at all.

Question 3 == is the correct way to compare any two objects. In Kotlin, even primitives should be compared this way because they behave like objects.

Question 5 With ListAdapter, you should always use submitList instead of notifyDataSetChanged. notifyDataSetChanged would cause a pointless refresh of all the views and defeat the purpose of using ListAdapter and DiffUtil.

  • Related