Step #4: Comparing Our Models

The constructor parameter that we are missing to the ListAdapter constructor is an instance of the awkwardly-named DiffUtil.ItemCallback interface. This interface tells ListAdapter how to compare two model objects. In particular, it tells ListAdapter whether two model objects should be visually identical, so RecyclerView does not have to re-draw or move around views that have not changed their appearance. So, we need an object that can do this for us to provide to ListAdapter.

We can take advantage of a couple of Kotlin features as part of this work:

With that in mind, at the bottom of the RosterAdapter Kotlin file, add this:

private object DiffCallback : DiffUtil.ItemCallback<ToDoModel>() {
  override fun areItemsTheSame(oldItem: ToDoModel, newItem: ToDoModel) =
    oldItem.id == newItem.id

  override fun areContentsTheSame(oldItem: ToDoModel, newItem: ToDoModel) =
    oldItem.isCompleted == newItem.isCompleted &&
        oldItem.description == newItem.description
}

This implements DiffUtil.ItemCallback for ToDoModel. areItemsTheSame() needs to return true if the two models are really the same thing — in our case, that would be determined using their unique IDs. areContentsTheSame() should return true if the two models’ visual representations are the same. Our CheckBox will use the description property for the text and the isCompleted property for the checked state, so areContentsTheSame() compares those two values. In particular, the notes property is ignored for this comparison, since it will not appear in the list rows.

Then, add DiffCallback as the missing constructor parameter to ListAdapter. This means the entire Kotlin source file at this point should look like:

package com.commonsware.todo

import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter

class RosterAdapter : ListAdapter<ToDoModel, RosterRowHolder>(DiffCallback) {
  override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int
  ): RosterRowHolder {
    TODO("Not yet implemented")
  }

  override fun onBindViewHolder(holder: RosterRowHolder, position: Int) {
    TODO("Not yet implemented")
  }
}

private object DiffCallback : DiffUtil.ItemCallback<ToDoModel>() {
  override fun areItemsTheSame(oldItem: ToDoModel, newItem: ToDoModel) =
    oldItem.id == newItem.id

  override fun areContentsTheSame(oldItem: ToDoModel, newItem: ToDoModel) =
    oldItem.isCompleted == newItem.isCompleted &&
        oldItem.description == newItem.description
}

Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.