Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiType 的扩展使用(ViewBinding, Diff.Callback) #77

Open
yunshuipiao opened this issue Jun 1, 2021 · 0 comments
Open

MultiType 的扩展使用(ViewBinding, Diff.Callback) #77

yunshuipiao opened this issue Jun 1, 2021 · 0 comments

Comments

@yunshuipiao
Copy link
Owner

yunshuipiao commented Jun 1, 2021

MultiType 的扩展使用(ViewBinding, Diff.Callback)

该库是我目前使用过最好用的 adapter 库,严格的遵循数据驱动,针对使用方便性做了一些扩展。

Delegate 的封装

这一步封装,结合 viewbinding 省去 viewholder 的创建过程。

使用反射

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

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

ViewHolder 的创建需要传入 layout 对应的binding,这里使用反射生成。

相关反射代码如下:

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

不使用反射

不使用发射,需要抽象一个方法,将 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)

结合 DiffUtil.Callback 做局部更新

这里考虑使用扩展函数,封装进行使用。

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

    override fun getNewListSize(): 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
}

// 带动画的差分更新
fun MultiTypeAdapter.submitList(callback: AnyCallback) {
    val result = DiffUtil.calculateDiff(callback)
    items = callback.newItems
    result.dispatchUpdatesTo(this)
}

// 旧方法更新
fun MultiTypeAdapter.updateItems(items: List<Any>) {
    this.items = items
    notifyDataSetChanged()
}

参考资料

  1. MultiType: https://github.com/drakeet/MultiType

  2. DylanCaiCoding:ViewBindingKTX: https://github.com/DylanCaiCoding/ViewBindingKTX

@yunshuipiao yunshuipiao changed the title [MultiType](https://github.com/drakeet/MultiType) 的扩展使用(ViewBinding, Diff.Callback) MultiType 的扩展使用(ViewBinding, Diff.Callback) Jun 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant