RecyclerView 适配器的 Kotlin 泛型

sad*_*dat 2 java generics android kotlin

我正在尝试编写一个通用的 recyclerview 适配器。我找到了几个例子。然而,仍然无法弄清楚如何实现通用适配器。我写的代码是,

open abstract class BaseAdapter<T : RecyclerView.ViewHolder>(private val onClickListener: View.OnClickListener, @LayoutRes private val layoutResource:Int) :
        RecyclerView.Adapter<T>() {
        var items: MutableList<Item> = mutableListOf()

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): T  {
            val layout = LayoutInflater.from(parent.context).inflate(layoutResource, parent, false)
            layout.setOnClickListener(onClickListener)
            return T(layout)
        }

        override fun getItemCount(): Int {
            return items.size
        }
    }
Run Code Online (Sandbox Code Playgroud)

我在 line 处收到错误return T(layout)。错误是Expression 'T' of type 'Int' cannot be invoked as a function. The function 'invoke()' is not found

Sta*_*chu 5

我将类似的东西用于 ListAdapter 的通用 this (利用ViewBinding

class BaseListAdapter<T>(
    private val inflate: (layoutInflater: LayoutInflater, parent: ViewGroup?, attachToParent: Boolean) -> ViewBinding,
    private val bind: (item: T, binding: ViewBinding) -> Unit,
    private val onClick: (item: T) -> Unit,
    compareItems: (old: T, new: T) -> Boolean,
    compareContents: (old: T, new: T) -> Boolean
) : ListAdapter<T, RecyclerView.ViewHolder>(DiffCallback(compareItems, compareContents)) {
    var items = emptyList<T>()
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        ItemViewHolder(inflate(LayoutInflater.from(parent.context), parent, false))

    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        bind(getItem(position), (holder as BaseListAdapter<T>.ItemViewHolder).binding)
    }

    internal fun setItems(items: List<T>) {
        this.items = items
        this.submitList(items)
    }

    inner class ItemViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder((binding).root) {
        init {
            binding.root.setOnClickListener { onClick(getItem(adapterPosition)) }
        }
    }

    private class DiffCallback<K>(
        private val compareItems: (old: K, new: K) -> Boolean,
        private val compareContents: (old: K, new: K) -> Boolean
    ) : DiffUtil.ItemCallback<K>() {
        override fun areItemsTheSame(old: K, new: K) = compareItems(old, new)
        override fun areContentsTheSame(old: K, new: K) = compareContents(old, new)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在片段/活动中,您可以像这样启动它(对于ViewBindingCustomerRvCustomerBinding作为 ViewBinding)

val adapter = BaseListAdapter<Customer>(
    { li, parent, attach -> RvCustomerBinding.inflate(li, parent, attach) },
    { item, vb -> (vb as RvCustomerBinding).tvName.text = item.name },
    { item -> displayToast(requireContext(), "Customer: ${item.name}") },
    { old, new -> old.id == new.id },
    { old, new -> old == new }
)
Run Code Online (Sandbox Code Playgroud)