From 090e1ee30cfb87f71786133a6a636aaa36b6c77e Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 22 Jun 2021 14:17:19 +0800 Subject: [PATCH] Add MultiTypeDelegate for management Types --- .../com/drakeet/multitype/MultiTypeAdapter.kt | 100 ++--------------- .../drakeet/multitype/MultiTypeDelegate.kt | 101 ++++++++++++++++++ .../com/drakeet/multitype/OneToManyBuilder.kt | 2 +- 3 files changed, 109 insertions(+), 94 deletions(-) create mode 100644 library/src/main/kotlin/com/drakeet/multitype/MultiTypeDelegate.kt diff --git a/library/src/main/kotlin/com/drakeet/multitype/MultiTypeAdapter.kt b/library/src/main/kotlin/com/drakeet/multitype/MultiTypeAdapter.kt index d67ed35d..84519aee 100644 --- a/library/src/main/kotlin/com/drakeet/multitype/MultiTypeAdapter.kt +++ b/library/src/main/kotlin/com/drakeet/multitype/MultiTypeAdapter.kt @@ -16,7 +16,6 @@ package com.drakeet.multitype -import android.util.Log import android.view.ViewGroup import androidx.annotation.CheckResult import androidx.recyclerview.widget.RecyclerView @@ -39,25 +38,12 @@ open class MultiTypeAdapter @JvmOverloads constructor( */ open var items: List = emptyList(), open val initialCapacity: Int = 0, - open var types: Types = MutableTypes(initialCapacity), -) : RecyclerView.Adapter() { + override var types: Types = MutableTypes(initialCapacity), +) : RecyclerView.Adapter(), MultiTypeDelegate { - /** - * Registers a type class and its item view delegate. If you have registered the class, - * it will override the original delegate(s). Note that the method is non-thread-safe - * so that you should not use it in concurrent operation. - * - * Note that the method should not be called after - * [RecyclerView.setAdapter], or you have to call the setAdapter - * again. - * - * @param clazz the class of a item - * @param delegate the item view delegate - * @param T the item data type - * */ - fun register(clazz: Class, delegate: ItemViewDelegate) { - unregisterAllTypesIfNeeded(clazz) - register(Type(clazz, delegate, DefaultLinker())) + override fun register(type: Type) { + super.register(type) + type.delegate._adapter = this } inline fun register(delegate: ItemViewDelegate) { @@ -86,63 +72,17 @@ open class MultiTypeAdapter @JvmOverloads constructor( register(clazz, binder as ItemViewDelegate) } - internal fun register(type: Type) { - types.register(type) - type.delegate._adapter = this - } - - /** - * Registers a type class to multiple item view delegates. If you have registered the - * class, it will override the original delegate(s). Note that the method is non-thread-safe - * so that you should not use it in concurrent operation. - * - * Note that the method should not be called after - * [RecyclerView.setAdapter], or you have to call the setAdapter again. - * - * @param clazz the class of a item - * @param the item data type - * @return [OneToManyFlow] for setting the delegates - * @see [register] - */ - @CheckResult - fun register(clazz: Class): OneToManyFlow { - unregisterAllTypesIfNeeded(clazz) - return OneToManyBuilder(this, clazz) - } - @CheckResult fun register(clazz: KClass): OneToManyFlow { return register(clazz.java) } - /** - * Registers all of the contents in the specified [Types]. If you have registered a - * class, it will override the original delegate(s). Note that the method is non-thread-safe - * so that you should not use it in concurrent operation. - * - * Note that the method should not be called after - * [RecyclerView.setAdapter], or you have to call the setAdapter - * again. - * - * @param types a [Types] containing contents to be added to this adapter inner [Types] - * @see [register] - * @see [register] - */ - fun registerAll(types: Types) { - val size = types.size - for (i in 0 until size) { - val type = types.getType(i) - unregisterAllTypesIfNeeded(type.clazz) - register(type) - } - } - override fun getItemViewType(position: Int): Int { return indexInTypesOf(position, items[position]) } override fun onCreateViewHolder(parent: ViewGroup, indexViewType: Int): ViewHolder { - return types.getType(indexViewType).delegate.onCreateViewHolder(parent.context, parent) + return getOutDelegate(indexViewType).onCreateViewHolder(parent.context, parent) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -166,9 +106,8 @@ open class MultiTypeAdapter @JvmOverloads constructor( * @since v3.2.0 */ override fun getItemId(position: Int): Long { - val item = items[position] val itemViewType = getItemViewType(position) - return types.getType(itemViewType).delegate.getItemId(item) + return getOutDelegate(itemViewType).getItemId(position) } /** @@ -224,29 +163,4 @@ open class MultiTypeAdapter @JvmOverloads constructor( override fun onViewDetachedFromWindow(holder: ViewHolder) { getOutDelegateByViewHolder(holder).onViewDetachedFromWindow(holder) } - - private fun getOutDelegateByViewHolder(holder: ViewHolder): ItemViewDelegate { - @Suppress("UNCHECKED_CAST") - return types.getType(holder.itemViewType).delegate as ItemViewDelegate - } - - @Throws(DelegateNotFoundException::class) - internal fun indexInTypesOf(position: Int, item: Any): Int { - val index = types.firstIndexOf(item.javaClass) - if (index != -1) { - val linker = types.getType(index).linker - return index + linker.index(position, item) - } - throw DelegateNotFoundException(item.javaClass) - } - - private fun unregisterAllTypesIfNeeded(clazz: Class<*>) { - if (types.unregister(clazz)) { - Log.w(TAG, "The type ${clazz.simpleName} you originally registered is now overwritten.") - } - } - - companion object { - private const val TAG = "MultiTypeAdapter" - } } diff --git a/library/src/main/kotlin/com/drakeet/multitype/MultiTypeDelegate.kt b/library/src/main/kotlin/com/drakeet/multitype/MultiTypeDelegate.kt new file mode 100644 index 00000000..63f2e3d6 --- /dev/null +++ b/library/src/main/kotlin/com/drakeet/multitype/MultiTypeDelegate.kt @@ -0,0 +1,101 @@ +package com.drakeet.multitype + +import android.util.Log +import androidx.annotation.CheckResult +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder + +interface MultiTypeDelegate { + + val types: Types + + fun register(type: Type) { + types.register(type) + } + + /** + * Registers a type class and its item view delegate. If you have registered the class, + * it will override the original delegate(s). Note that the method is non-thread-safe + * so that you should not use it in concurrent operation. + * + * Note that the method should not be called after + * [RecyclerView.setAdapter], or you have to call the setAdapter + * again. + * + * @param clazz the class of a item + * @param delegate the item view delegate + * @param T the item data type + * */ + fun register(clazz: Class, delegate: ItemViewDelegate) { + unregisterAllTypesIfNeeded(clazz) + register(Type(clazz, delegate, DefaultLinker())) + } + + /** + * Registers a type class to multiple item view delegates. If you have registered the + * class, it will override the original delegate(s). Note that the method is non-thread-safe + * so that you should not use it in concurrent operation. + * + * Note that the method should not be called after + * [RecyclerView.setAdapter], or you have to call the setAdapter again. + * + * @param clazz the class of a item + * @param the item data type + * @return [OneToManyFlow] for setting the delegates + * @see [register] + */ + @CheckResult + fun register(clazz: Class): OneToManyFlow { + unregisterAllTypesIfNeeded(clazz) + return OneToManyBuilder(this, clazz) + } + + /** + * Registers all of the contents in the specified [Types]. If you have registered a + * class, it will override the original delegate(s). Note that the method is non-thread-safe + * so that you should not use it in concurrent operation. + * + * Note that the method should not be called after + * [RecyclerView.setAdapter], or you have to call the setAdapter + * again. + * + * @param types a [Types] containing contents to be added to this adapter inner [Types] + * @see [register] + * @see [register] + */ + fun registerAll(types: Types) { + val size = types.size + for (i in 0 until size) { + val type = types.getType(i) + unregisterAllTypesIfNeeded(type.clazz) + register(type) + } + } + + @Throws(DelegateNotFoundException::class) + fun indexInTypesOf(position: Int, item: Any): Int { + val index = types.firstIndexOf(item.javaClass) + if (index != -1) { + val linker = types.getType(index).linker + return index + linker.index(position, item) + } + throw DelegateNotFoundException(item.javaClass) + } + + fun getOutDelegate(itemViewType: Int): ItemViewDelegate { + return types.getType(itemViewType).delegate + } + + fun getOutDelegateByViewHolder(holder: ViewHolder): ItemViewDelegate { + @Suppress("UNCHECKED_CAST") + return getOutDelegate(holder.itemViewType) as ItemViewDelegate + } +} + +private fun MultiTypeDelegate.unregisterAllTypesIfNeeded(clazz: Class<*>) { + if (types.unregister(clazz)) { + Log.w(TAG, "The type ${clazz.simpleName} you originally registered is now overwritten.") + } +} + +private const val TAG = "MultiTypeAdapter" \ No newline at end of file diff --git a/library/src/main/kotlin/com/drakeet/multitype/OneToManyBuilder.kt b/library/src/main/kotlin/com/drakeet/multitype/OneToManyBuilder.kt index 3a848a24..aa15fc08 100644 --- a/library/src/main/kotlin/com/drakeet/multitype/OneToManyBuilder.kt +++ b/library/src/main/kotlin/com/drakeet/multitype/OneToManyBuilder.kt @@ -22,7 +22,7 @@ import androidx.annotation.CheckResult * @author Drakeet Xu */ internal class OneToManyBuilder( - private val adapter: MultiTypeAdapter, + private val adapter: MultiTypeDelegate, private val clazz: Class ) : OneToManyFlow, OneToManyEndpoint {