1

I know how to implement DiffUtil if the adapter receive single data type objects.

But in my case I have an adapter which get two data types from a fragment.

So how can I use DiffUtil with multiple data types?

Here is my adapter code:

class VisitorsAdapter(val listener: VisitorsViewHolder.OnVisitorClicked) :
RecyclerView.Adapter<BaseViewHolder<*>>() {


private var visitorsData = mutableListOf<Any>()
private var isOwner = true

fun setData(visitorsData: List<Any>) {
    Log.e("TAG", "setData called")
    this.visitorsData.clear()
    var currentVisitors = mutableListOf<CurrentVisitorResponseItem>()
    var leavedVisitors = mutableListOf<LeavedVisitorsResponseItem>()
    for (visitor in visitorsData) {
        when (visitor) {
            is CurrentVisitorResponseItem -> currentVisitors.add(visitor)
            is LeavedVisitorsResponseItem -> leavedVisitors.add(visitor)
        }
    }
    currentVisitors = currentVisitors.sortedBy { it.roomNumber?.toInt() }.toMutableList()
    leavedVisitors = leavedVisitors.sortedBy { it.room }.toMutableList()
    this.visitorsData.addAll(currentVisitors)
    this.visitorsData.addAll(leavedVisitors)
    notifyDataSetChanged()
}

fun isOwner(chooser: Boolean) {
    this.isOwner = chooser
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
    return VisitorsViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.visitor_item, parent, false)
    )
}

override fun getItemCount() = visitorsData.size

override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
    val dataPositioned = visitorsData[position]
    when (holder) {
        is VisitorsViewHolder -> {
            holder.bind(dataPositioned, position, listener, isOwner)
        }
    }
}

}

Note: I have 2 types of data:

1- CurrentVisitorResponseItem

2- LeavedVisitorsResponseItem

Hasan Al-Qaisi
  • 167
  • 3
  • 11

1 Answers1

4

I found the solution!

First of all, if we try to make the type of ItemCallback (Any) we will face a problem

says 'Suspicious equality check: equals() is not implemented in Object DiffUtilEquals'

The solution for this is to make an interface that override equals function

and implement that interface on the data classes that we want to pass. Like this:

    interface Equatable {
    override fun equals(other: Any?): Boolean
}

data class CurrentVisitorResponseItem() : Equatable

data class LeavedVisitorsResponseItem() : Equatable

Then, the adapter class will be like this:

class VisitorsAdapter(val listener: VisitorsViewHolder.OnVisitorClicked) :
    RecyclerView.Adapter<BaseViewHolder<*>>() {

    private var isOwner = true

    private val differCallBack = object : DiffUtil.ItemCallback<Equatable>() {
        override fun areItemsTheSame(oldItem: Equatable, newItem: Equatable): Boolean {
            Log.e("TAG", "I'm in the areItemsTheSame")
            return when {
                oldItem is CurrentVisitorResponseItem && newItem is CurrentVisitorResponseItem -> {
                    oldItem.id == newItem.id
                }
                oldItem is LeavedVisitorsResponseItem && newItem is LeavedVisitorsResponseItem -> {
                    oldItem.id == newItem.id
                }
                else -> false
            }
        }

        override fun areContentsTheSame(oldItem: Equatable, newItem: Equatable): Boolean {
            return when {
                oldItem is CurrentVisitorResponseItem && newItem is CurrentVisitorResponseItem -> {
                    oldItem == newItem
                }
                oldItem is LeavedVisitorsResponseItem && newItem is LeavedVisitorsResponseItem -> {
                    oldItem == newItem
                }
                else -> false
            }
        }
    }

    val differ = AsyncListDiffer(this, differCallBack)


    fun isOwner(chooser: Boolean) {
        this.isOwner = chooser
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
        return VisitorsViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.visitor_item, parent, false)
        )
    }

    override fun getItemCount() = differ.currentList.size


    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
        val dataPositioned = differ.currentList[position]
        when (holder) {
            is VisitorsViewHolder -> {
                holder.bind(dataPositioned, position, listener, isOwner)
            }
        }
    }
}
Hasan Al-Qaisi
  • 167
  • 3
  • 11