The library is the best Adapter I have used so far, strictly data-driven, with some extensions for ease of use.

The Delegate of encapsulation

This step of encapsulation, combined with a ViewBinding, saves the creation of a Viewholder.

Using reflection

abstract class ViewBindingDelegate<T, VB : ViewBinding> :
    ItemViewDelegate<T, ViewBindingViewHolder<VB>>() {

    override fun onCreateViewHolder(
        context: Context,
        parent: ViewGroup
    ): ViewBindingViewHolder<VB> {
        return ViewBindingViewHolder(inflateBindingWithGeneric(parent))
    }
}
Copy the code

Creating a ViewHolder requires passing in a Binding for the layout, which is generated using reflection.

The related reflection codes are as follows:

@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> Any.inflateBindingWithGeneric(layoutInflater: LayoutInflater): VB =
        withGenericBindingClass(this) { clazz ->
            clazz.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB
        }

@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> Any.inflateBindingWithGeneric(layoutInflater: LayoutInflater, parent: ViewGroup? , attachToParent:Boolean): VB =
        withGenericBindingClass(this) { clazz ->
            clazz.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean: :class.java)
                    .invoke(null, layoutInflater, parent, attachToParent) as VB
        }

@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> Any.inflateBindingWithGeneric(parent: ViewGroup): VB =
        inflateBindingWithGeneric(LayoutInflater.from(parent.context), parent, false)

fun <VB : ViewBinding> Any.bindViewWithGeneric(view: View): VB =
        withGenericBindingClass(this) { clazz ->
            clazz.getMethod("bind", LayoutInflater::class.java).invoke(null, view) as VB
        }

private fun <VB : ViewBinding> withGenericBindingClass(any: Any, block: (Class<VB- > >)VB): VB {
    any.allParameterizedType.forEach { parameterizedType ->
        parameterizedType.actualTypeArguments.forEach {
            try {
                return block.invoke(it as Class<VB>)
            } catch (e: Exception) {
            }
        }
    }
    throw IllegalArgumentException("There is no generic of ViewBinding.")}private val Any.allParameterizedType: List<ParameterizedType>
    get() {
        val genericParameterizedType = mutableListOf<ParameterizedType>()
        var genericSuperclass = javaClass.genericSuperclass
        var superclass = javaClass.superclass
        while(superclass ! =null) {
            if (genericSuperclass is ParameterizedType) {
                genericParameterizedType.add(genericSuperclass)
            }
            genericSuperclass = superclass.genericSuperclass
            superclass = superclass.superclass
        }
        return genericParameterizedType
    }
Copy the code

Don’t use reflection

Instead of using emission, you need to abstract a method that returns an instance of binding.

abstract class ViewBindingDelegate2<T, VB : ViewBinding> :
    ItemViewDelegate<T, ViewBindingViewHolder<VB>>() {

    override fun onCreateViewHolder(
        context: Context,
        parent: ViewGroup
    ): ViewBindingViewHolder<VB> {
        return ViewBindingViewHolder(binding(parent))
    }

    abstract fun binding(parent: ViewGroup): VB
}

class ViewBindingViewHolder<VB : ViewBinding>(val binding: VB) :
    RecyclerView.ViewHolder(binding.root)
Copy the code

Perform local updates with DiffUtil.callback

Consider using extension functions, encapsulated for use.

abstract class AnyCallback(val oldItems: List<Any>, val newItems: List<Any>) : DiffUtil.Callback() {
    override fun getOldListSize(a): Int {
        return oldItems.size
    }

    override fun getNewListSize(a): Int {
        return newItems.size
    }

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val oldItem = oldItems[oldItemPosition]
        val newItem = newItems[newItemPosition]
        return areItemsTheSame(oldItem, newItem)

    }

    abstract fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean


    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val oldItem = oldItems[oldItemPosition]
        val newItem = newItems[newItemPosition]
        return areContentsTheSame(oldItem, newItem)
    }

    abstract fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean
}

// Drive the differential update of the drawing
fun MultiTypeAdapter.submitList(callback: AnyCallback) {
    val result = DiffUtil.calculateDiff(callback)
    items = callback.newItems
    result.dispatchUpdatesTo(this)}// The old method is updated
fun MultiTypeAdapter.updateItems(items: List<Any>) {
    this.items = items
    notifyDataSetChanged()
}
Copy the code

The resources

  1. MultiType: github.com/drakeet/Mul…

  2. DylanCaiCoding: ViewBindingKTX: github.com/DylanCaiCod…