将 RecyclerView 与 DiffUtil 一起用于多种数据类型

Using RecyclerView with DiffUtil for multiple data types

如果适配器接收单一数据类型对象,我知道如何实现 DiffUtil。

但在我的例子中,我有一个从片段中获取两种数据类型的适配器。

那么如何将 DiffUtil 与多种数据类型一起使用?

这是我的适配器代码:

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

}

注:我有2种数据:

1- CurrentVisitorResponseItem

2- LeavedVisitorsResponseItem

我找到了解决方案!

首先,如果我们尝试使 ItemCallback 的类型为 (Any),我们将面临一个问题

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

解决方案是制作一个覆盖等于函数的接口

并在我们要传递的数据 classes 上实现该接口。像这样:

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

data class CurrentVisitorResponseItem() : Equatable

data class LeavedVisitorsResponseItem() : Equatable

那么,适配器class会是这样的:

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