diff --git a/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.kt b/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.kt index 6f2651ed2..b5640b07b 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.kt @@ -7,7 +7,7 @@ import androidx.core.view.get import androidx.multidex.MultiDexApplication import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 -import me.yifeiyuan.flap.Flap +import me.yifeiyuan.flap.FlapInitializer import me.yifeiyuan.flap.dsl.adapterHook import me.yifeiyuan.flap.hook.LoggingHook import me.yifeiyuan.flapdev.components.* @@ -47,28 +47,29 @@ class FlapApplication : MultiDexApplication() { private fun initFlap() { val dslAdapterHook = adapterHook { - onCreateViewHolderStart { adapter, delegate, viewType -> + onCreateViewHolderStart { adapter, viewType -> } - onCreateViewHolderEnd { adapter, delegate, viewType, component -> + onCreateViewHolderEnd { adapter, viewType, component -> } - onBindViewHolderStart { adapter, delegate, component, data, position, payloads -> + onBindViewHolderStart { adapter, component, data, position, payloads -> } - onBindViewHolderEnd { adapter, delegate, component, data, position, payloads -> - Log.d("dslAdapterHook", "onBindViewHolderEnd() called with: adapter = $adapter, delegate = $delegate, component = $component, data = $data, position = $position, payloads = $payloads") + onBindViewHolderEnd { adapter, component, data, position, payloads -> + Log.d("dslAdapterHook", "onBindViewHolderEnd() called with: adapter = $adapter, component = $component, data = $data, position = $position, payloads = $payloads") } - onViewAttachedToWindow { adapter, delegate, component -> + + onViewAttachedToWindow { adapter, component -> } - onViewDetachedFromWindow { adapter, delegate, component -> + onViewDetachedFromWindow { adapter, component -> } } - Flap.apply { + FlapInitializer.apply { //Flap 这里注册的都是是全局的,只是为了测试方便 //实际开发使用的话 哪个 Adapter 需要才注册更加合适。 @@ -101,6 +102,9 @@ class FlapApplication : MultiDexApplication() { //可选 withContext(this@FlapApplication) + //可选 +// withFallbackAdapterDelegate(YourFallbackAdapterDelegate()) + //打开日志 setDebug(true) } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/Banner.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/Banner.kt index 05be941b2..18fb4c78c 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/Banner.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/Banner.kt @@ -28,13 +28,13 @@ fun createBannerAdapterDelegate() = adapterDelegate(R.layout.compon val viewPager2 = findViewById(R.id.banner) - val bannerAdapter = FlapAdapter().apply { + val bannerAdapter = FlapAdapter { registerAdapterDelegate(bannerImageDelegate()) } viewPager2.adapter = bannerAdapter - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> model.images?.let { bannerAdapter.setDataAndNotify(it) } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/CustomViewTypeComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/CustomViewTypeComponent.kt index bd71f56bc..2648364e6 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/CustomViewTypeComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/CustomViewTypeComponent.kt @@ -15,7 +15,7 @@ class CustomViewTypeModel(var content: String = "自定义 itemViewType 的 Comp const val CUSTOM_ITEM_VIEW_TYPE = 466 fun createCustomViewTypeComponentDelegate() = adapterDelegate(R.layout.flap_item_custom_type, itemViewType = CUSTOM_ITEM_VIEW_TYPE) { - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> bindTextView(R.id.tv_content) { text = model.content } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/DiffComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/DiffComponent.kt index 38c54643c..a80d272b2 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/DiffComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/DiffComponent.kt @@ -39,12 +39,13 @@ class TestDiffModel(var content: String, var id: Int, var desc: String) : IDiffe } fun createDiffDelegate() = adapterDelegate(R.layout.component_diff) { - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> //当 payloads 更新时,事件点击需要重新设置 bindButton(R.id.modifyContent) { setOnClickListener { model.content = "修改后 Content:" + (SystemClock.uptimeMillis() % 10000).toInt().toString() + adapter.notifyItemChanged(position, model.content)//不会闪 // adapter.notifyItemChanged(position)//会闪 } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleImageComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleImageComponent.kt index 4049c4212..e674e3184 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleImageComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleImageComponent.kt @@ -16,7 +16,7 @@ class SimpleImageModel { } fun createSimpleImageDelegate() = adapterDelegate(R.layout.component_simple_image) { - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> bindImageView(R.id.logo) { if (model.url?.isNotEmpty() == true) { Glide.with(context).load(model.url).into(this) diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleTextComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleTextComponent.kt index f794521e3..654f5e128 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleTextComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/SimpleTextComponent.kt @@ -5,10 +5,8 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter import me.yifeiyuan.flap.ViewTypeGenerator import me.yifeiyuan.flap.delegate.AdapterDelegate -import me.yifeiyuan.flapdev.Logger import me.yifeiyuan.flapdev.R /** @@ -17,7 +15,7 @@ import me.yifeiyuan.flapdev.R * 作为文档 Demo */ -data class SimpleTextModel(val content: String){ +data class SimpleTextModel(val content: String) { override fun toString(): String { return "content=$content,SimpleTextModel" } @@ -29,18 +27,13 @@ class SimpleTextComponent(itemView: View) : Component(itemView) private val tvContent: TextView = findViewById(R.id.tv_content) - override fun onBind(model: SimpleTextModel, position: Int, payloads: List, adapter: FlapAdapter, delegate: AdapterDelegate<*, *>) { - Logger.d(TAG, "onBind() called with: model = $model, position = $position, payloads = $payloads, adapter = $adapter") + override fun onBind(model: SimpleTextModel, position: Int, payloads: List) { tvContent.text = model.content } override fun onBind(model: SimpleTextModel) { - Logger.d(TAG, "onBind() called with: model = $model") } - companion object { - private const val TAG = "SimpleTextComponent" - } } //自定义 AdapterDelegate 实现 diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/TestAdapterApiComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/TestAdapterApiComponent.kt index d141e1a8a..b0bb350a1 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/TestAdapterApiComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/TestAdapterApiComponent.kt @@ -21,7 +21,7 @@ fun createTestAdapterApiComponentDelegate() = adapterDelegate(R.id.message) - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> bindButton(R.id.testFireEvent) { // fireEvent 发送事件 @@ -31,19 +31,19 @@ fun createTestAdapterApiComponentDelegate() = adapterDelegate("stringValue") - val intValue = adapter.getParam("intValue") - val booleanValue = adapter.getParam("booleanValue") + val stringValue = getParam("stringValue") + val intValue = getParam("intValue") + val booleanValue = getParam("booleanValue") val results :String = StringBuilder(). append("stringValue=$stringValue ;;") @@ -58,9 +58,14 @@ fun createTestAdapterApiComponentDelegate() = adapterDelegate { + log("LogService Message") + messageTextView.text = testResult() + } + +// val logService = adapter.getAdapterService(TestService::class.java) +// logService?.log("LogService Message") +// messageTextView.text = logService?.testResult() } } } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/TestClickComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/TestClickComponent.kt index b24f91802..39788f1f0 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/TestClickComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/TestClickComponent.kt @@ -12,7 +12,7 @@ import me.yifeiyuan.flapdev.R class TestClickModel(var content: String) fun createTestClickDelegate() = adapterDelegate(R.layout.component_test_click) { - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> bindTextView(R.id.clicks){ text = model.content } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/TestConfig.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/TestConfig.kt index b59334274..c5308bf2c 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/TestConfig.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/TestConfig.kt @@ -51,7 +51,7 @@ class TestConfigModel : IDiffer { fun createFullConfigAdapterDelegate() = adapterDelegate(R.layout.component_full_feature) { - onBind { model, position, payloads, adapter -> + onBind { model, position, payloads -> bindTextView(R.id.title) { text = model.title diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/ViewBindingComponent.kt b/app/src/main/java/me/yifeiyuan/flapdev/components/ViewBindingComponent.kt index ae85e1713..dcf0e11e6 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/ViewBindingComponent.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/ViewBindingComponent.kt @@ -16,14 +16,13 @@ class ViewBindingModel private const val TAG = "ViewBindingComponent" -fun createViewBindingDelegate() = adapterDelegateViewBinding({ layoutInflater, parent -> FlapItemVbBinding.inflate(layoutInflater, parent, false) } -) { +fun createViewBindingDelegate() = adapterDelegateViewBinding({ layoutInflater, parent -> FlapItemVbBinding.inflate(layoutInflater, parent, false) }) { onBind { model -> binding.tvContent.text = "adapterDelegateViewBinding DSL 支持 ViewBinding" } - onClick { model, position, adapter -> + onClick { model, position -> toast("viewBindingDelegate onClick() called with: component = $this, model = $model, position = $position") } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/testcases/BaseTestcaseFragment.kt b/app/src/main/java/me/yifeiyuan/flapdev/testcases/BaseTestcaseFragment.kt index 1e55e1a95..133ea5f36 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/testcases/BaseTestcaseFragment.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/testcases/BaseTestcaseFragment.kt @@ -86,7 +86,7 @@ open class BaseTestcaseFragment : Fragment(), Scrollable, IMenuView { emptyView = view.findViewById(R.id.emptyView) recyclerView = view.findViewById(R.id.recyclerView) adapter = createAdapter() - .withLifecycleOwner(viewLifecycleOwner) + adapter.withLifecycleOwner(viewLifecycleOwner) .withEmptyView(emptyView) .observeEvent("showToast") { toast(it.arg ?: "Default Message") diff --git a/app/src/main/java/me/yifeiyuan/flapdev/testcases/ItemDecorationTestcase.kt b/app/src/main/java/me/yifeiyuan/flapdev/testcases/ItemDecorationTestcase.kt index a4552443b..d1fe45462 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/testcases/ItemDecorationTestcase.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/testcases/ItemDecorationTestcase.kt @@ -33,12 +33,12 @@ class ItemDecorationTestcase : BaseTestcaseFragment() { recyclerView.setBackgroundColor(Color.parseColor("#16000000")) - adapter.doOnCreateViewHolderEnd { adapter, delegate, viewType, component -> + adapter.doOnCreateViewHolderEnd { adapter, viewType, component -> val preLP = component.itemView.layoutParams preLP.height = Random.nextInt(requireActivity().toPixel(50), requireActivity().toPixel(150)) } - adapter.doOnBindViewHolderEnd { adapter, delegate, component, data, position, payloads -> + adapter.doOnBindViewHolderEnd { adapter, component, data, position, payloads -> if (recyclerView.layoutManager is StaggeredGridLayoutManager) { val index = (component.itemView.layoutParams as StaggeredGridLayoutManager.LayoutParams).spanIndex Log.d("StaggeredGridL", "onInit() called with: position = $position, spanIndex = $index") diff --git a/app/src/main/java/me/yifeiyuan/flapdev/testcases/MultiTypeTestcase.kt b/app/src/main/java/me/yifeiyuan/flapdev/testcases/MultiTypeTestcase.kt index 615bf1692..b6888da46 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/testcases/MultiTypeTestcase.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/testcases/MultiTypeTestcase.kt @@ -61,7 +61,7 @@ class MultiTypeTestcase : BaseTestcaseFragment() { } .onlyOnce(false) .suppressLayout(true) - .withEmptyViewHelper(adapter.emptyViewHelper) + .withEmptyViewHelper(adapter.getEmptyViewHelper()) .show() SwipeDragHelper(adapter) diff --git a/app/src/main/java/me/yifeiyuan/flapdev/testcases/ViewPager2Testcase.kt b/app/src/main/java/me/yifeiyuan/flapdev/testcases/ViewPager2Testcase.kt index 73a453af0..f275e933f 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/testcases/ViewPager2Testcase.kt +++ b/app/src/main/java/me/yifeiyuan/flapdev/testcases/ViewPager2Testcase.kt @@ -47,7 +47,7 @@ class ViewPager2Testcase : Fragment(), Scrollable { * java.lang.IllegalStateException: Pages must fill the whole ViewPager2 (use match_parent) * at androidx.viewpager2.widget.ViewPager2$4.onChildViewAttachedToWindow(ViewPager2.java:270) */ - doOnCreateViewHolderEnd { adapter, delegate, viewType, component -> + doOnCreateViewHolderEnd { adapter, viewType, component -> component.itemView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) } diff --git a/flap-animation/src/main/java/me/yifeiyuan/flap/animation/BaseAdapterAnimation.kt b/flap-animation/src/main/java/me/yifeiyuan/flap/animation/BaseAdapterAnimation.kt index 4c4030138..4a7a1235d 100644 --- a/flap-animation/src/main/java/me/yifeiyuan/flap/animation/BaseAdapterAnimation.kt +++ b/flap-animation/src/main/java/me/yifeiyuan/flap/animation/BaseAdapterAnimation.kt @@ -4,9 +4,9 @@ import android.animation.Animator import android.view.View import android.view.animation.Interpolator import android.view.animation.LinearInterpolator +import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component import me.yifeiyuan.flap.FlapAdapter -import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.hook.AdapterHook /** @@ -23,8 +23,8 @@ abstract class BaseAdapterAnimation : AdapterHook { var interpolator: Interpolator = LinearInterpolator() private var lastPosition = -1 - override fun onBindViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { - super.onBindViewHolderEnd(adapter, delegate, component, data, position, payloads) + override fun onBindViewHolderEnd(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + super.onBindViewHolderEnd(adapter, component, data, position, payloads) val adapterPosition = component.adapterPosition if (!isFirstOnly || adapterPosition > lastPosition) { val animator = createAnimator(component.itemView, component, data, position) diff --git a/flap-paging/.gitignore b/flap-paging/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/flap-paging/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/flap-paging/build.gradle b/flap-paging/build.gradle new file mode 100644 index 000000000..b03a910e8 --- /dev/null +++ b/flap-paging/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'com.android.library' + id 'kotlin-android' +} + +android { + compileSdkVersion 29 + + defaultConfig { + minSdkVersion 17 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + api project(':flap') + + def paging_version = "3.1.1" + + implementation "androidx.paging:paging-runtime:$paging_version" +} \ No newline at end of file diff --git a/flap-paging/consumer-rules.pro b/flap-paging/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/flap-paging/proguard-rules.pro b/flap-paging/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/flap-paging/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/flap-paging/src/androidTest/java/me/yifeiyuan/flap/paging/ExampleInstrumentedTest.kt b/flap-paging/src/androidTest/java/me/yifeiyuan/flap/paging/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..071d99843 --- /dev/null +++ b/flap-paging/src/androidTest/java/me/yifeiyuan/flap/paging/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package me.yifeiyuan.flap.paging + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("me.yifeiyuan.flap.paging.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/flap-paging/src/main/AndroidManifest.xml b/flap-paging/src/main/AndroidManifest.xml new file mode 100644 index 000000000..5893e24a2 --- /dev/null +++ b/flap-paging/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/flap-paging/src/main/java/me/yifeiyuan/flap/paging/FlapPagingDataAdapter.kt b/flap-paging/src/main/java/me/yifeiyuan/flap/paging/FlapPagingDataAdapter.kt new file mode 100644 index 000000000..7aaa312a3 --- /dev/null +++ b/flap-paging/src/main/java/me/yifeiyuan/flap/paging/FlapPagingDataAdapter.kt @@ -0,0 +1,74 @@ +package me.yifeiyuan.flap.paging + +import android.view.ViewGroup +import androidx.paging.PagingDataAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import me.yifeiyuan.flap.Component +import me.yifeiyuan.flap.Flap +import me.yifeiyuan.flap.FlapApi +import me.yifeiyuan.flap.delegate.IAdapterDelegateManager +import me.yifeiyuan.flap.ext.SwipeDragHelper +import me.yifeiyuan.flap.hook.IAdapterHookManager +import me.yifeiyuan.flap.service.IAdapterServiceManager +import me.yifeiyuan.flap.widget.FlapStickyHeaders + +/** + * + * 支持 Paging + * Created by 程序亦非猿 on 2022/11/7. + * + * @since 3.3.0 + */ +class FlapPagingDataAdapter(private val flap: Flap = Flap(), diffCallback: DiffUtil.ItemCallback, private val flapInitBlock: (Flap.() -> Unit)? = null) : PagingDataAdapter>(diffCallback), IAdapterHookManager by flap, IAdapterDelegateManager by flap, IAdapterServiceManager by flap, SwipeDragHelper.Callback, FlapStickyHeaders, FlapApi by flap { + + init { + apply { + flapInitBlock?.invoke(flap) + } + } + + override fun getItemViewType(position: Int): Int { + return flap.getItemViewType(position, getItemData(position) as Any) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Component { + return flap.onCreateViewHolder(this, parent, viewType) as Component + } + + override fun onBindViewHolder(component: Component, position: Int) { + this.onBindViewHolder(component, position, mutableListOf()) + } + + override fun onBindViewHolder( + component: Component, + position: Int, + payloads: MutableList + ) { + flap.onBindViewHolder(this, getItemData(position) as Any, component, position, payloads) + } + + override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { + super.onAttachedToRecyclerView(recyclerView) + flap.onAttachedToRecyclerView(this, recyclerView) + } + + override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { + super.onDetachedFromRecyclerView(recyclerView) + flap.onDetachedFromRecyclerView(this, recyclerView) + } + + var stickyHeaderHandler: ((position: Int, itemData: T?) -> Boolean)? = null + + fun setupStickyHeaderHandler(block: (position: Int, itemData: T?) -> Boolean) { + stickyHeaderHandler = block + } + + override fun isStickyHeader(position: Int): Boolean { + return stickyHeaderHandler?.invoke(position, getItemData(position)) ?: false + } + + fun getItemData(position: Int): T? { + return peek(position) + } +} \ No newline at end of file diff --git a/flap-paging/src/test/java/me/yifeiyuan/flap/paging/ExampleUnitTest.kt b/flap-paging/src/test/java/me/yifeiyuan/flap/paging/ExampleUnitTest.kt new file mode 100644 index 000000000..b1a7891bb --- /dev/null +++ b/flap-paging/src/test/java/me/yifeiyuan/flap/paging/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package me.yifeiyuan.flap.paging + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/Component.kt b/flap/src/main/java/me/yifeiyuan/flap/Component.kt index 6767024b4..50ff181b1 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/Component.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/Component.kt @@ -13,17 +13,18 @@ import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent import androidx.recyclerview.widget.RecyclerView -import me.yifeiyuan.flap.delegate.AdapterDelegate +import me.yifeiyuan.flap.event.Event +import me.yifeiyuan.flap.service.AdapterService /** * Component is used by Flap as the base ViewHolder , which provides some useful and convenient abilities as well. * * Component 基于 ViewHolder, 封装了更多日常开发所需的功能。 * - * @see FlapAdapter.getParam 从 Adapter 获取额外的参数 - * @see FlapAdapter.fireEvent 发送事件给 Adapter - * @see FlapAdapter.getActivityContext 获取 Activity 类型的 Context,因为如果你使用 Application 创建 Component,context 不是 Activity - * @see FlapAdapter.inflateWithApplicationContext + * @see Flap.getParam 从 Adapter 获取额外的参数 + * @see Flap.fireEvent 发送事件给 Adapter + * @see Flap.getActivityContext 获取 Activity 类型的 Context,因为如果你使用 Application 创建 Component,context 不是 Activity + * @see Flap.inflateWithApplicationContext * * Created by 程序亦非猿 on 2021/9/22. * @@ -39,8 +40,8 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif * 如果设置了 FlapAdapter.inflateWithApplicationContext==true ,则会变成 Application Context, * 此时如果要获取 Activity Context 则需要通过 FlapAdapter#getActivityContext() 获取 * - * @see FlapAdapter.inflateWithApplicationContext - * @see FlapAdapter.getActivityContext + * @see Flap.inflateWithApplicationContext + * @see Flap.getActivityContext */ val context: Context = itemView.context @@ -49,6 +50,24 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif */ protected var isVisible = false + internal var _bindingAdapter: RecyclerView.Adapter<*>? = null + + val adapter: RecyclerView.Adapter<*> + get() = if (_bindingAdapter == null) { + throw java.lang.IllegalArgumentException("onBind 还未调用,还不可以使用") + } else { + _bindingAdapter as RecyclerView.Adapter<*> + } + + internal var _flap: Flap? = null + + val flap: Flap + get() = if (_flap == null) { + throw java.lang.IllegalArgumentException("onBind 还未调用,还不可以使用") + } else { + _flap as Flap + } + internal var _bindingData: Any? = null /** @@ -56,16 +75,18 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif */ val data: T get() = if (_bindingData == null) { - throw IllegalArgumentException("onBind 还未调用,不可以使用 bindingData") + throw IllegalArgumentException("onBind 还未调用,还不可以使用") } else { @Suppress("UNCHECKED_CAST") _bindingData as T } @Suppress("UNCHECKED_CAST") - fun bindData(model: Any, position: Int, payloads: List, adapter: FlapAdapter, delegate: AdapterDelegate<*, *>) { + internal fun bindData(model: Any, position: Int, payloads: List, adapter: RecyclerView.Adapter<*>, flap: Flap) { _bindingData = model - onBind(model as T, position, payloads, adapter, delegate) + _flap = flap + _bindingAdapter = adapter + onBind(model as T, position, payloads) } /** @@ -79,10 +100,7 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif protected open fun onBind( model: T, position: Int, - payloads: List, - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *> - ) { + payloads: List) { onBind(model) } @@ -99,43 +117,43 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif } /** - * @see FlapAdapter.onViewAttachedToWindow + * @see RecyclerView.Adapter.onViewAttachedToWindow */ @CallSuper - open fun onViewAttachedToWindow(flapAdapter: FlapAdapter) { - onVisibilityChanged(true, flapAdapter) + open fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>) { + onVisibilityChanged(true, adapter) } /** - * @see FlapAdapter.onViewDetachedFromWindow + * @see RecyclerView.Adapter.onViewDetachedFromWindow */ @CallSuper - open fun onViewDetachedFromWindow(flapAdapter: FlapAdapter) { - onVisibilityChanged(false, flapAdapter) + open fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>) { + onVisibilityChanged(false, adapter) } /** * @param visible if component is visible - * @param flapAdapter + * @param adapter * * @see onViewAttachedToWindow * @see onViewDetachedFromWindow */ @CallSuper - open fun onVisibilityChanged(visible: Boolean, flapAdapter: FlapAdapter) { + open fun onVisibilityChanged(visible: Boolean, adapter: RecyclerView.Adapter<*>) { isVisible = visible } /** - * @see FlapAdapter.onViewRecycled + * @see RecyclerView.Adapter.onViewRecycled */ - open fun onViewRecycled(flapAdapter: FlapAdapter) {} + open fun onViewRecycled(adapter: RecyclerView.Adapter<*>) {} /** * @return true if the View should be recycled, false otherwise. - * @see FlapAdapter.onFailedToRecycleView + * @see RecyclerView.Adapter.onFailedToRecycleView */ - open fun onFailedToRecycleView(flapAdapter: FlapAdapter): Boolean { + open fun onFailedToRecycleView(adapter: RecyclerView.Adapter<*>): Boolean { return false } @@ -155,6 +173,9 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) open fun onDestroy(owner: LifecycleOwner) { owner.lifecycle.removeObserver(this) + _bindingAdapter = null + _flap = null + _bindingData = null } fun getString(@StringRes resId: Int): String { @@ -222,4 +243,20 @@ open class Component(itemView: View) : RecyclerView.ViewHolder(itemView), Lif } itemView.layoutParams = param } + + inline fun callService(noinline block: T.() -> Unit) { + flap.getAdapterService(T::class.java)?.let { + it.apply { block() } + } + } + + fun

getParam(key: String): P? { + return flap.getParam(key) as? P + } + + fun fireEvent(event: Event) { + flap.fireEvent(event) + } + + } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/Flap.kt b/flap/src/main/java/me/yifeiyuan/flap/Flap.kt index e4061f13f..53b7a8de5 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/Flap.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/Flap.kt @@ -1,51 +1,490 @@ package me.yifeiyuan.flap import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.LifecycleOwner +import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.delegate.AdapterDelegateManager import me.yifeiyuan.flap.delegate.FallbackAdapterDelegate import me.yifeiyuan.flap.delegate.IAdapterDelegateManager +import me.yifeiyuan.flap.event.Event +import me.yifeiyuan.flap.event.EventObserver +import me.yifeiyuan.flap.event.EventObserverWrapper +import me.yifeiyuan.flap.ext.* import me.yifeiyuan.flap.hook.AdapterHookManager import me.yifeiyuan.flap.hook.IAdapterHookManager +import me.yifeiyuan.flap.hook.PreloadHook +import me.yifeiyuan.flap.pool.ComponentPool import me.yifeiyuan.flap.service.AdapterServiceManager import me.yifeiyuan.flap.service.IAdapterServiceManager /** - * Flap 存放全局的配置,会应用于所有的 FlapAdapter 实例 + * 负责代理部分 Adapter API 实现 * - * - AdapterDelegate - * - AdapterHook - * - AdapterService + * 本着组合由于继承的理念,Flap SDK 核心功能在这里实现,方便适配多种系统 Adapter。 * - * Created by 程序亦非猿 on 2021/9/22. + * Created by 程序亦非猿 on 2022/9/27. * - * Flap Github: https://github.com/AlanCheen/Flap - * @author 程序亦非猿 [Follow me]( https://github.com/AlanCheen) - * @since 2020/9/22 - * @since 3.0.0 + * @since 3.1.5 */ -object Flap : IAdapterHookManager by AdapterHookManager(), IAdapterDelegateManager by AdapterDelegateManager(), IAdapterServiceManager by AdapterServiceManager() { +class Flap : IAdapterHookManager by AdapterHookManager(), IAdapterDelegateManager by AdapterDelegateManager(), IAdapterServiceManager by AdapterServiceManager(), FlapApi { + + companion object { + private const val TAG = "Flap" + + /** + * 当 Adapter.data 中存在一个 Model 没有对应的 AdapterDelegate.delegate()==true 时抛出 + */ + internal class AdapterDelegateNotFoundException(errorMessage: String) : Exception(errorMessage) + } /** - * 是否使用 application context 来创建 Component + * Components 监听的生命周期对象,一般是 Activity + * 默认取的是 RecyclerView.Context + * + * 如果使用 Fragment 那么需要自行设置 + */ + private var lifecycleOwner: LifecycleOwner? = null + + private val viewTypeDelegateCache: MutableMap?> = mutableMapOf() + private val delegateViewTypeCache: MutableMap, Int> = mutableMapOf() + + var fallbackDelegate: FallbackAdapterDelegate? = null + + /** + * 是否使用 ApplicationContext 来创建 LayoutInflater 来创建 View + * + * 当开启后 Component.context 将变成 Application Context */ var inflateWithApplicationContext = false - internal var globalFallbackAdapterDelegate: AdapterDelegate<*, *> = FallbackAdapterDelegate() + private val emptyViewHelperImpl = EmptyViewHelper().also { + registerAdapterHook(it) + } + + init { + adapterHooks.addAll(FlapInitializer.adapterHooks) + adapterDelegates.addAll(FlapInitializer.adapterDelegates) + adapterServices.putAll(FlapInitializer.adapterServices) + + fallbackDelegate = FlapInitializer.globalFallbackAdapterDelegate + + inflateWithApplicationContext = FlapInitializer.inflateWithApplicationContext + } + + fun onCreateViewHolder(adapter: RecyclerView.Adapter<*>, parent: ViewGroup, viewType: Int): Component<*> { + val delegate = getDelegateByViewType(viewType) + dispatchOnCreateViewHolderStart(adapter, viewType) + + val context = if (inflateWithApplicationContext) parent.context.applicationContext else parent.context + val layoutInflater = LayoutInflater.from(context) + + val component = delegate.onCreateViewHolder(layoutInflater, parent, viewType) + dispatchOnCreateViewHolderEnd(adapter, viewType, component) + return component + } + + private fun dispatchOnCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) { + try { + adapterHooks.forEach { + it.onCreateViewHolderStart(adapter, viewType) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun dispatchOnCreateViewHolderEnd(adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) { + try { + adapterHooks.forEach { + it.onCreateViewHolderEnd(adapter, viewType, component) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun getDelegateByViewType(viewType: Int): AdapterDelegate<*, *> { + return viewTypeDelegateCache[viewType] ?: fallbackDelegate + ?: throw AdapterDelegateNotFoundException("找不到 viewType = $viewType 对应的 Delegate,请先注册,或设置默认的 Delegate") + } + + fun onBindViewHolder( + adapter: RecyclerView.Adapter<*>, + itemData: Any, + component: Component<*>, + position: Int, + payloads: MutableList) { + try { + val delegate = getDelegateByViewType(component.itemViewType) + dispatchOnBindViewHolderStart(adapter, component, itemData, position, payloads) + delegate.onBindViewHolder( + component, + itemData, + position, + payloads, + adapter, + this + ) + dispatchOnBindViewHolderEnd(adapter, component, itemData, position, payloads) + tryAttachLifecycleOwner(component) + } catch (e: Exception) { + e.printStackTrace() + FlapDebug.e(TAG, "onBindViewHolder: Error = ", e) + } + } + + /** + * Attaches the component to lifecycle if need. + * + * @param component The component we are going to bind. + */ + private fun tryAttachLifecycleOwner(component: Component<*>) { + if (lifecycleOwner == null) { + throw NullPointerException("lifecycleOwner==null,无法监听生命周期,请先调用 FlapAdapter#setLifecycleOwner()") + } + lifecycleOwner!!.lifecycle.addObserver(component) + } + + private fun dispatchOnBindViewHolderStart( + adapter: RecyclerView.Adapter<*>, + component: Component<*>, + itemData: Any, + position: Int, + payloads: MutableList) { + try { + adapterHooks.forEach { + it.onBindViewHolderStart(adapter, component, itemData, position, payloads) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun dispatchOnBindViewHolderEnd( + adapter: RecyclerView.Adapter<*>, + component: Component<*>, + data: Any, + position: Int, + payloads: MutableList) { + try { + adapterHooks.forEach { + it.onBindViewHolderEnd(adapter, component, data, position, payloads) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + fun getItemViewType(position: Int, itemData: Any): Int { + + var itemViewType: Int + + val delegate: AdapterDelegate<*, *>? = adapterDelegates.firstOrNull { + it.delegate(itemData) + } ?: fallbackDelegate + + if (delegateViewTypeCache.containsKey(delegate)) { + return delegateViewTypeCache[delegate]!! + } + + itemViewType = delegate?.getItemViewType(itemData) + ?: throw AdapterDelegateNotFoundException("找不到对应的 AdapterDelegate,请先注册或设置默认 AdapterDelegate ,position=$position , itemData=$itemData") + + if (itemViewType == 0) { + itemViewType = generateItemViewType() + } + FlapDebug.d(TAG, "getItemViewType() called with: position = $position , itemViewType = $itemViewType") + viewTypeDelegateCache[itemViewType] = delegate + delegateViewTypeCache[delegate] = itemViewType + return itemViewType + } + + private fun generateItemViewType(): Int { + val viewType = ViewTypeGenerator.generateViewType() + if (viewTypeDelegateCache.containsKey(viewType)) { + return generateItemViewType() + } + return viewType + } + + fun getItemId(position: Int, itemData: Any): Long { + val delegate = getDelegateByViewType(getItemViewType(position, itemData)) + return delegate.getItemId(itemData, position) + } + + internal fun onViewRecycled(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + val delegate = getDelegateByViewType(component.itemViewType) + delegate.onViewRecycled(adapter, component) + } + + internal fun onFailedToRecycleView(adapter: RecyclerView.Adapter<*>, component: Component<*>): Boolean { + val delegate = getDelegateByViewType(component.itemViewType) + return delegate.onFailedToRecycleView(adapter, component) + } + + internal fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + val delegate = getDelegateByViewType(component.itemViewType) + delegate.onViewAttachedToWindow(adapter, component) + dispatchOnViewAttachedToWindow(adapter, component) + } - fun withContext(context: Context) = apply { - context.applicationContext + private fun dispatchOnViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + try { + adapterHooks.forEach { + it.onViewAttachedToWindow(adapter, component) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + internal fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + val delegate = getDelegateByViewType(component.itemViewType) + delegate.onViewDetachedFromWindow(adapter, component) + dispatchOnViewDetachedFromWindow(adapter, component) + } + + private fun dispatchOnViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + try { + adapterHooks.forEach { + it.onViewDetachedFromWindow(adapter, component) + } + } catch (e: Exception) { + e.printStackTrace() + } } /** - * 设置全局的 FallbackAdapterDelegate + * 是否使用 ComponentPool */ - fun withFallbackAdapterDelegate(fallbackAdapterDelegate: AdapterDelegate<*, *>) = apply { - globalFallbackAdapterDelegate = fallbackAdapterDelegate + private var useComponentPool = true + + fun onAttachedToRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { + handleOnAttachedToRecyclerView(recyclerView) + dispatchOnAttachedToRecyclerView(adapter, recyclerView) + } + + private fun handleOnAttachedToRecyclerView(recyclerView: RecyclerView) { + bindingRecyclerView = recyclerView + bindingContext = recyclerView.context + + //当没设置 lifecycleOwner 尝试获取 context 作为 LifecycleOwner + if (lifecycleOwner == null && recyclerView.context is LifecycleOwner) { + FlapDebug.d(TAG, "onAttachedToRecyclerView,FlapAdapter 自动设置了 recyclerView.context 为 LifecycleOwner") + lifecycleOwner = recyclerView.context as LifecycleOwner + } + + if (useComponentPool) { + if (!this::componentPool.isInitialized) { + componentPool = ComponentPool() + } + + if (recyclerView.recycledViewPool != componentPool) { + recyclerView.setRecycledViewPool(componentPool) + } + bindingContext.applicationContext.registerComponentCallbacks(componentPool) + } + } + + private fun dispatchOnAttachedToRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { + try { + adapterHooks.forEach { + it.onAttachedToRecyclerView(adapter, recyclerView) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + lateinit var componentPool: ComponentPool + + lateinit var bindingRecyclerView: RecyclerView + lateinit var bindingContext: Context + + fun onDetachedFromRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { + if (this::componentPool.isInitialized) { + bindingContext.applicationContext.unregisterComponentCallbacks(componentPool) + } + dispatchOnDetachedFromRecyclerView(adapter, recyclerView) } - fun setDebug(debug: Boolean) = apply { - FlapDebug.isDebug = debug + private fun dispatchOnDetachedFromRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { + try { + adapterHooks.forEach { + it.onDetachedFromRecyclerView(adapter, recyclerView) + } + } catch (e: Exception) { + e.printStackTrace() + } } + /** + * RecyclerView 滑动到顶部触发预加载 + */ + private var scrollUpPreloadHook: PreloadHook? = null + + /** + * RecyclerView 滑动到底部触发预加载 + */ + private var scrollDownPreloadHook: PreloadHook? = null + + override fun doOnPreload(offset: Int, minItemCount: Int, direction: Int, onPreload: () -> Unit) = apply { + when (direction) { + PreloadHook.SCROLL_UP -> { + scrollUpPreloadHook?.let { + unregisterAdapterHook(it) + } + scrollUpPreloadHook = PreloadHook(offset, minItemCount, direction, onPreload = onPreload).also { + registerAdapterHook(it) + } + } + PreloadHook.SCROLL_DOWN -> { + scrollDownPreloadHook?.let { + unregisterAdapterHook(it) + } + scrollDownPreloadHook = PreloadHook(offset, minItemCount, direction, onPreload = onPreload).also { + registerAdapterHook(it) + } + } + } + } + + /** + * 设置是否启用预加载 + * 需要先调用 doOnPreload 开启才有效。 + */ + override fun setPreloadEnable(enable: Boolean, direction: Int) = apply { + when (direction) { + PreloadHook.SCROLL_UP -> { + scrollUpPreloadHook?.preloadEnable = enable + } + PreloadHook.SCROLL_DOWN -> { + scrollDownPreloadHook?.preloadEnable = enable + } + } + } + + override fun setPreloadComplete(direction: Int) { + when (direction) { + PreloadHook.SCROLL_UP -> { + scrollUpPreloadHook?.setPreloadComplete() + } + PreloadHook.SCROLL_DOWN -> { + scrollDownPreloadHook?.setPreloadComplete() + } + } + } + + private var itemClicksHelper = ItemClicksHelper().also { + registerAdapterHook(it) + } + + /** + * 设置点击事件监听 + * @see doOnItemLongClick + */ + override fun doOnItemClick(onItemClick: OnItemClickListener?) = apply { + itemClicksHelper.onItemClickListener = onItemClick + } + + /** + * 设置长按事件监听 + * @see doOnItemClick + */ + override fun doOnItemLongClick(onItemLongClick: OnItemLongClickListener?) = apply { + itemClicksHelper.onItemLongClickListener = onItemLongClick + } + + override fun withEmptyView(emptyView: View?) = apply { + emptyViewHelperImpl.emptyView = emptyView + } + + override fun getEmptyViewHelper(): EmptyViewHelper { + return emptyViewHelperImpl + } + + private var paramProvider: ExtraParamsProvider? = null + + /** + * 提供 Component 从 Adapter 获取参数的方法 + * + * @return key 对应的参数,如果类型不匹配,则会为 null + */ + @Suppress("UNCHECKED_CAST") + override fun

getParam(key: String): P? { + return paramProvider?.getParam(key) as? P? + } + + override fun setParamProvider(block: (key: String) -> Any?) = apply { + paramProvider = ExtraParamsProviderWrapper(block) + } + + /** + * 设置 Component 绑定的 LifecycleOwner + * 会尝试去获取 recyclerView.context 作为 LifecycleOwner + */ + override fun withLifecycleOwner(lifecycleOwner: LifecycleOwner) = apply { + this.lifecycleOwner = lifecycleOwner + } + + /** + * 设置是否使用 ComponentPool 作为缓存池 + */ + override fun withComponentPoolEnable(enable: Boolean) = apply { + useComponentPool = enable + } + + /** + * 所有事件的监听 + */ + var allEventsObserver: EventObserver? = null + + /** + * 根据 Event.eventName 存放的 + */ + private val eventObservers: MutableMap = mutableMapOf() + + /** + * 通过 Adapter 发送事件 + * + * @see observeEvent + * @see observerEvents + */ + override fun fireEvent(event: Event) { + val observer = eventObservers[event.eventName] + observer?.onEvent(event) + + allEventsObserver?.onEvent(event) + } + + /** + * 观察指定 eventName 的事件 + * @see fireEvent + */ + override fun observeEvent(eventName: String, block: (Event) -> Unit) = apply { + eventObservers[eventName] = EventObserverWrapper(block) + } + + /** + * 观察所有的事件 + */ + override fun observerEvents(block: (Event<*>) -> Unit) = apply { + allEventsObserver = object : EventObserver { + override fun onEvent(event: Event<*>) { + block.invoke(event) + } + } + } + + /** + * @see inflateWithApplicationContext + * @return activity context + */ + override fun getActivityContext(): Context { + return bindingContext + } } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.kt b/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.kt index 1edc975dd..fafdf300e 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.kt @@ -2,28 +2,16 @@ package me.yifeiyuan.flap -import android.content.Context -import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.delegate.IAdapterDelegateManager -import me.yifeiyuan.flap.event.Event -import me.yifeiyuan.flap.event.EventObserver -import me.yifeiyuan.flap.event.EventObserverWrapper -import me.yifeiyuan.flap.ext.* +import me.yifeiyuan.flap.ext.SwipeDragHelper import me.yifeiyuan.flap.hook.IAdapterHookManager -import me.yifeiyuan.flap.hook.PreloadHook -import me.yifeiyuan.flap.pool.ComponentPool -import java.util.* import me.yifeiyuan.flap.service.IAdapterServiceManager import me.yifeiyuan.flap.widget.FlapStickyHeaders +import java.util.* /** - * FlapAdapter is a flexible and powerful Adapter that makes you enjoy developing with RecyclerView. - * - * * Created by 程序亦非猿 on 2021/9/22. * * Flap Github: https://github.com/AlanCheen/Flap @@ -31,60 +19,20 @@ import me.yifeiyuan.flap.widget.FlapStickyHeaders * @since 2020/9/22 * @since 3.0.0 */ -open class FlapAdapter(private val delegation: FlapDelegation = FlapDelegation()) : RecyclerView.Adapter>(), IAdapterHookManager by delegation, IAdapterDelegateManager by delegation, IAdapterServiceManager by delegation, SwipeDragHelper.Callback, FlapStickyHeaders { +open class FlapAdapter(private val flap: Flap = Flap(), private val flapInitBlock: (Flap.() -> Unit)? = null) : RecyclerView.Adapter>(), IAdapterHookManager by flap, IAdapterDelegateManager by flap, IAdapterServiceManager by flap, SwipeDragHelper.Callback, FlapStickyHeaders, FlapApi by flap { companion object { private const val TAG = "FlapAdapter" } - private var data: MutableList = mutableListOf() - - /** - * 是否使用 ComponentPool - */ - private var useComponentPool = true - - /** - * RecyclerView 滑动到顶部触发预加载 - */ - private var scrollUpPreloadHook: PreloadHook? = null - - /** - * RecyclerView 滑动到底部触发预加载 - */ - private var scrollDownPreloadHook: PreloadHook? = null - - /** - * 所有事件的监听 - */ - var allEventsObserver: EventObserver? = null - - /** - * 根据 Event.eventName 存放的 - */ - private val eventObservers: MutableMap = mutableMapOf() - - /** - * 是否使用 ApplicationContext 来创建 LayoutInflater 来创建 View - * - * 当开启后 Component.context 将变成 Application Context - */ - var inflateWithApplicationContext = false - - private var paramProvider: ExtraParamsProvider? = null - - private var itemClicksHelper = ItemClicksHelper() - val emptyViewHelper = EmptyViewHelper() - - lateinit var componentPool: ComponentPool - - lateinit var bindingRecyclerView: RecyclerView - lateinit var bindingContext: Context - init { - inflateWithApplicationContext = Flap.inflateWithApplicationContext + apply { + flapInitBlock?.invoke(flap) + } } + private var data: MutableList = mutableListOf() + // 暂时不需要 // private fun getData(): List { // return Collections.unmodifiableList(data) @@ -139,9 +87,7 @@ open class FlapAdapter(private val delegation: FlapDelegation = FlapDelegation() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Component<*> { - val context = if (inflateWithApplicationContext) parent.context.applicationContext else parent.context - val layoutInflater = LayoutInflater.from(context) - return delegation.onCreateViewHolder(this, parent, viewType, layoutInflater) + return flap.onCreateViewHolder(this, parent, viewType) } override fun onBindViewHolder(component: Component<*>, position: Int) { @@ -153,8 +99,7 @@ open class FlapAdapter(private val delegation: FlapDelegation = FlapDelegation() position: Int, payloads: MutableList ) { - val data = getItemData(position) - delegation.onBindViewHolder(this, data, component, position, payloads) + flap.onBindViewHolder(this, getItemData(position), component, position, payloads) } open fun getItemData(position: Int): Any { @@ -162,216 +107,40 @@ open class FlapAdapter(private val delegation: FlapDelegation = FlapDelegation() } override fun getItemViewType(position: Int): Int { - val itemData = getItemData(position) - return delegation.getItemViewType(position, itemData) + return flap.getItemViewType(position, getItemData(position)) } override fun getItemId(position: Int): Long { - val itemData = getItemData(position) - return delegation.getItemId(position, itemData) + return flap.getItemId(position, getItemData(position)) } override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { super.onAttachedToRecyclerView(recyclerView) - handleOnAttachedToRecyclerView(recyclerView) - delegation.onAttachedToRecyclerView(this, recyclerView) - } - - private fun handleOnAttachedToRecyclerView(recyclerView: RecyclerView) { - bindingRecyclerView = recyclerView - bindingContext = recyclerView.context - - if (useComponentPool) { - if (!this::componentPool.isInitialized) { - componentPool = ComponentPool() - } - - if (recyclerView.recycledViewPool != componentPool) { - recyclerView.setRecycledViewPool(componentPool) - } - bindingContext.applicationContext.registerComponentCallbacks(componentPool) - } - - itemClicksHelper.attachRecyclerView(recyclerView) - emptyViewHelper.attachRecyclerView(recyclerView, true) + flap.onAttachedToRecyclerView(this, recyclerView) } override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { super.onDetachedFromRecyclerView(recyclerView) - itemClicksHelper.detachRecyclerView(recyclerView) - emptyViewHelper.detachRecyclerView() - if (this::componentPool.isInitialized) { - bindingContext.applicationContext.unregisterComponentCallbacks(componentPool) - } - delegation.onDetachedFromRecyclerView(this, recyclerView) + flap.onDetachedFromRecyclerView(this, recyclerView) } /** * 会优先于 FlapComponentPool.putRecycledView 被调用 */ override fun onViewRecycled(component: Component<*>) { - delegation.onViewRecycled(this, component) + flap.onViewRecycled(this, component) } override fun onFailedToRecycleView(component: Component<*>): Boolean { - return delegation.onFailedToRecycleView(this, component) + return flap.onFailedToRecycleView(this, component) } override fun onViewAttachedToWindow(component: Component<*>) { - delegation.onViewAttachedToWindow(this, component) + flap.onViewAttachedToWindow(this, component) } override fun onViewDetachedFromWindow(component: Component<*>) { - delegation.onViewDetachedFromWindow(this, component) - } - - /** - * 设置 Component 绑定的 LifecycleOwner - * 会尝试去获取 recyclerView.context 作为 LifecycleOwner - */ - fun withLifecycleOwner(lifecycleOwner: LifecycleOwner) = apply { - delegation.lifecycleOwner = lifecycleOwner - } - - /** - * 设置 Component 是否监听生命周期,默认开启 - */ - fun withLifecycleEnable(enable: Boolean) = apply { - delegation.lifecycleEnable = enable - } - - /** - * 设置是否使用 ComponentPool 作为缓存池 - */ - fun withComponentPoolEnable(enable: Boolean) = apply { - useComponentPool = enable - } - - /** - * 通过 Adapter 发送事件 - * - * @see observeEvent - * @see observerEvents - */ - fun fireEvent(event: Event) { - val observer = eventObservers[event.eventName] - observer?.onEvent(event) - - allEventsObserver?.onEvent(event) - } - - /** - * 观察指定 eventName 的事件 - * @see fireEvent - */ - fun observeEvent(eventName: String, block: (Event) -> Unit) = apply { - eventObservers[eventName] = EventObserverWrapper(block) - } - - /** - * 观察所有的事件 - */ - fun observerEvents(block: (Event<*>) -> Unit) = apply { - allEventsObserver = object : EventObserver { - override fun onEvent(event: Event<*>) { - block.invoke(event) - } - } - } - - /** - * 预加载 - * - * @see PreloadHook - */ - fun doOnPreload(offset: Int = 0, minItemCount: Int = 2, direction: Int = PreloadHook.SCROLL_DOWN, onPreload: () -> Unit) = apply { - when (direction) { - PreloadHook.SCROLL_UP -> { - scrollUpPreloadHook?.let { - unregisterAdapterHook(it) - } - scrollUpPreloadHook = PreloadHook(offset, minItemCount, direction, onPreload = onPreload).also { - registerAdapterHook(it) - } - } - PreloadHook.SCROLL_DOWN -> { - scrollDownPreloadHook?.let { - unregisterAdapterHook(it) - } - scrollDownPreloadHook = PreloadHook(offset, minItemCount, direction, onPreload = onPreload).also { - registerAdapterHook(it) - } - } - } - } - - /** - * 设置是否启用预加载 - * 需要先调用 doOnPreload 开启才有效。 - */ - fun setPreloadEnable(enable: Boolean, direction: Int = PreloadHook.SCROLL_DOWN) = apply { - when (direction) { - PreloadHook.SCROLL_UP -> { - scrollUpPreloadHook?.preloadEnable = enable - } - PreloadHook.SCROLL_DOWN -> { - scrollDownPreloadHook?.preloadEnable = enable - } - } - } - - fun setPreloadComplete(direction: Int = PreloadHook.SCROLL_DOWN) { - when (direction) { - PreloadHook.SCROLL_UP -> { - scrollUpPreloadHook?.setPreloadComplete() - } - PreloadHook.SCROLL_DOWN -> { - scrollDownPreloadHook?.setPreloadComplete() - } - } - } - - /** - * 提供 Component 从 Adapter 获取参数的方法 - * - * @return key 对应的参数,如果类型不匹配,则会为 null - */ - @Suppress("UNCHECKED_CAST") - open fun

getParam(key: String): P? { - return paramProvider?.getParam(key) as? P? - } - - fun setParamProvider(block: (key: String) -> Any?) = apply { - paramProvider = ExtraParamsProviderWrapper(block) - } - - /** - * - * @see FlapAdapter.inflateWithApplicationContext - * @return activity context - */ - fun getActivityContext(): Context { - return bindingContext - } - - /** - * 设置点击事件监听 - * @see doOnItemLongClick - */ - fun doOnItemClick(onItemClick: OnItemClickListener?) = apply { - itemClicksHelper.onItemClickListener = onItemClick - } - - /** - * 设置长按事件监听 - * @see doOnItemClick - */ - fun doOnItemLongClick(onItemLongClick: OnItemLongClickListener?) = apply { - itemClicksHelper.onItemLongClickListener = onItemLongClick - } - - fun withEmptyView(emptyView: View?) = apply { - emptyViewHelper.emptyView = emptyView + flap.onViewDetachedFromWindow(this, component) } fun insertDataAt(index: Int, element: Any, notify: Boolean = true) { diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapApi.kt b/flap/src/main/java/me/yifeiyuan/flap/FlapApi.kt new file mode 100644 index 000000000..07b1c9a49 --- /dev/null +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapApi.kt @@ -0,0 +1,95 @@ +package me.yifeiyuan.flap + +import android.content.Context +import android.view.View +import androidx.lifecycle.LifecycleOwner +import me.yifeiyuan.flap.event.Event +import me.yifeiyuan.flap.ext.EmptyViewHelper +import me.yifeiyuan.flap.ext.OnItemClickListener +import me.yifeiyuan.flap.ext.OnItemLongClickListener +import me.yifeiyuan.flap.hook.PreloadHook + +/** + * 抽象 Flap 类的 API。 + * + * Created by 程序亦非猿 on 2022/11/3. + * @since 3.3.0 + */ +interface FlapApi { + + /** + * 通过 Adapter 发送事件 + * + * @see observeEvent + * @see observerEvents + */ + fun fireEvent(event: Event) + + /** + * 观察指定 eventName 的事件 + * @see fireEvent + */ + fun observeEvent(eventName: String, block: (Event) -> Unit): FlapApi + + /** + * 观察所有的事件 + */ + fun observerEvents(block: (Event<*>) -> Unit): FlapApi + + /** + * 设置 Component 绑定的 LifecycleOwner + * 会尝试去获取 recyclerView.context 作为 LifecycleOwner + */ + fun withLifecycleOwner(lifecycleOwner: LifecycleOwner): FlapApi + + /** + * 设置是否使用 ComponentPool 作为缓存池 + */ + fun withComponentPoolEnable(enable: Boolean): FlapApi + + /** + * 预加载 + * + * @see PreloadHook + */ + fun doOnPreload(offset: Int = 0, minItemCount: Int = 2, direction: Int = PreloadHook.SCROLL_DOWN, onPreload: () -> Unit): FlapApi + + /** + * 设置是否启用预加载 + * 需要先调用 doOnPreload 开启才有效。 + */ + fun setPreloadEnable(enable: Boolean, direction: Int = PreloadHook.SCROLL_DOWN): FlapApi + + fun setPreloadComplete(direction: Int = PreloadHook.SCROLL_DOWN) + + /** + * 设置点击事件监听 + * @see doOnItemLongClick + */ + fun doOnItemClick(onItemClick: OnItemClickListener?): FlapApi + + /** + * 设置长按事件监听 + * @see doOnItemClick + */ + fun doOnItemLongClick(onItemLongClick: OnItemLongClickListener?): FlapApi + + fun withEmptyView(emptyView: View?): FlapApi + + fun getEmptyViewHelper(): EmptyViewHelper + + fun setParamProvider(block: (key: String) -> Any?): FlapApi + + /** + * 提供 Component 从 Adapter 获取参数的方法 + * + * @return key 对应的参数,如果类型不匹配,则会为 null + */ + fun

getParam(key: String): P? + + /** + * @see FlapAdapter.inflateWithApplicationContext + * @return activity context + */ + fun getActivityContext(): Context +} \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapDelegation.kt b/flap/src/main/java/me/yifeiyuan/flap/FlapDelegation.kt deleted file mode 100644 index 5be1ab443..000000000 --- a/flap/src/main/java/me/yifeiyuan/flap/FlapDelegation.kt +++ /dev/null @@ -1,283 +0,0 @@ -package me.yifeiyuan.flap - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.RestrictTo -import androidx.lifecycle.LifecycleOwner -import androidx.recyclerview.widget.RecyclerView -import me.yifeiyuan.flap.delegate.AdapterDelegate -import me.yifeiyuan.flap.delegate.AdapterDelegateManager -import me.yifeiyuan.flap.delegate.IAdapterDelegateManager -import me.yifeiyuan.flap.hook.AdapterHookManager -import me.yifeiyuan.flap.hook.IAdapterHookManager -import me.yifeiyuan.flap.service.AdapterServiceManager -import me.yifeiyuan.flap.service.IAdapterServiceManager - -/** - * 负责代理部分 Adapter API 实现 - * - * Created by 程序亦非猿 on 2022/9/27. - * - * @since 3.1.5 - */ -@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -class FlapDelegation : IAdapterHookManager by AdapterHookManager(), IAdapterDelegateManager by AdapterDelegateManager(), IAdapterServiceManager by AdapterServiceManager() { - - companion object { - private const val TAG = "FlapDelegation" - - /** - * 当 Adapter.data 中存在一个 Model 没有对应的 AdapterDelegate.delegate()==true 时抛出 - */ - internal class AdapterDelegateNotFoundException(errorMessage: String) : Exception(errorMessage) - } - - /** - * Components 监听的生命周期对象,一般是 Activity - * 默认取的是 RecyclerView.Context - */ - internal var lifecycleOwner: LifecycleOwner? = null - - /** - * Components 是否监听生命周期事件 - */ - internal var lifecycleEnable = true - - private val viewTypeDelegateCache: MutableMap?> = mutableMapOf() - private val delegateViewTypeCache: MutableMap, Int> = mutableMapOf() - - var fallbackDelegate: AdapterDelegate<*, *>? = null - - init { - adapterHooks.addAll(Flap.adapterHooks) - adapterDelegates.addAll(Flap.adapterDelegates) - adapterServices.putAll(Flap.adapterServices) - - fallbackDelegate = Flap.globalFallbackAdapterDelegate - } - - internal fun onCreateViewHolder(adapter: FlapAdapter, parent: ViewGroup, viewType: Int, layoutInflater: LayoutInflater): Component<*> { - val delegate = getDelegateByViewType(viewType) - dispatchOnCreateViewHolderStart(adapter, delegate, viewType) - val component = delegate.onCreateViewHolder(layoutInflater, parent, viewType) - dispatchOnCreateViewHolderEnd(adapter, delegate, viewType, component) - return component - } - - private fun dispatchOnCreateViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) { - try { - adapterHooks.forEach { - it.onCreateViewHolderStart(adapter, delegate, viewType) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - private fun dispatchOnCreateViewHolderEnd( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, - viewType: Int, - component: Component<*> - ) { - try { - adapterHooks.forEach { - it.onCreateViewHolderEnd(adapter, delegate, viewType, component) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - private fun getDelegateByViewType(viewType: Int): AdapterDelegate<*, *> { - return viewTypeDelegateCache[viewType] ?: fallbackDelegate - ?: throw AdapterDelegateNotFoundException("找不到 viewType = $viewType 对应的 Delegate,请先注册,或设置默认的 Delegate") - } - - internal fun onBindViewHolder( - adapter: FlapAdapter, - itemData: Any, - component: Component<*>, - position: Int, - payloads: MutableList - ) { - try { - val delegate = getDelegateByViewType(component.itemViewType) - dispatchOnBindViewHolderStart(adapter, delegate, component, itemData, position, payloads) - delegate.onBindViewHolder( - component, - itemData, - position, - payloads, - adapter - ) - dispatchOnBindViewHolderEnd(adapter, delegate, component, itemData, position, payloads) - tryAttachLifecycleOwner(component) - } catch (e: Exception) { - e.printStackTrace() - FlapDebug.e(TAG, "onBindViewHolder: Error = ", e) - } - } - - /** - * Attaches the component to lifecycle if need. - * - * @param component The component we are going to bind. - */ - private fun tryAttachLifecycleOwner(component: Component<*>) { - if (lifecycleEnable) { - if (lifecycleOwner == null) { - throw NullPointerException("lifecycleOwner == null,无法监听生命周期,请先调用 FlapAdapter#setLifecycleOwner()") - } - lifecycleOwner!!.lifecycle.addObserver(component) - } - } - - private fun dispatchOnBindViewHolderStart( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, - component: Component<*>, - itemData: Any, - position: Int, - payloads: MutableList - ) { - try { - adapterHooks.forEach { - it.onBindViewHolderStart(adapter, delegate, component, itemData, position, payloads) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - private fun dispatchOnBindViewHolderEnd( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, - component: Component<*>, - data: Any, - position: Int, - payloads: MutableList - ) { - try { - adapterHooks.forEach { - it.onBindViewHolderEnd(adapter, delegate, component, data, position, payloads) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - internal fun getItemViewType(position: Int, itemData: Any): Int { - - var itemViewType: Int - - val delegate: AdapterDelegate<*, *>? = adapterDelegates.firstOrNull { - it.delegate(itemData) - } ?: fallbackDelegate - - if (delegateViewTypeCache.containsKey(delegate)) { - return delegateViewTypeCache[delegate]!! - } - - itemViewType = delegate?.getItemViewType(itemData) - ?: throw AdapterDelegateNotFoundException("找不到对应的 AdapterDelegate,请先注册或设置默认 AdapterDelegate ,position=$position , itemData=$itemData") - - if (itemViewType == 0) { - itemViewType = generateItemViewType() - } - FlapDebug.d(TAG, "getItemViewType() called with: position = $position , itemViewType = $itemViewType") - viewTypeDelegateCache[itemViewType] = delegate - delegateViewTypeCache[delegate] = itemViewType - return itemViewType - } - - private fun generateItemViewType(): Int { - val viewType = ViewTypeGenerator.generateViewType() - if (viewTypeDelegateCache.containsKey(viewType)) { - return generateItemViewType() - } - return viewType - } - - internal fun getItemId(position: Int, itemData: Any): Long { - val delegate = getDelegateByViewType(getItemViewType(position, itemData)) - return delegate.getItemId(itemData, position) - } - - internal fun onViewRecycled(adapter: FlapAdapter, component: Component<*>) { - val delegate = getDelegateByViewType(component.itemViewType) - delegate.onViewRecycled(adapter, component) - } - - internal fun onFailedToRecycleView(adapter: FlapAdapter, component: Component<*>): Boolean { - val delegate = getDelegateByViewType(component.itemViewType) - return delegate.onFailedToRecycleView(adapter, component) - } - - internal fun onViewAttachedToWindow(adapter: FlapAdapter, component: Component<*>) { - val delegate = getDelegateByViewType(component.itemViewType) - delegate.onViewAttachedToWindow(adapter, component) - - dispatchOnViewAttachedToWindow(adapter, delegate, component) - } - - private fun dispatchOnViewAttachedToWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { - try { - adapterHooks.forEach { - it.onViewAttachedToWindow(adapter, delegate, component) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - internal fun onViewDetachedFromWindow(adapter: FlapAdapter, component: Component<*>) { - val delegate = getDelegateByViewType(component.itemViewType) - delegate.onViewDetachedFromWindow(adapter, component) - - dispatchOnViewDetachedFromWindow(adapter, delegate, component) - } - - private fun dispatchOnViewDetachedFromWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { - try { - adapterHooks.forEach { - it.onViewDetachedFromWindow(adapter, delegate, component) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - internal fun onAttachedToRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) { - //当没设置 lifecycleOwner 尝试获取 context 作为 LifecycleOwner - if (lifecycleOwner == null && recyclerView.context is LifecycleOwner) { - FlapDebug.d(TAG, "onAttachedToRecyclerView,FlapAdapter 自动设置了 recyclerView.context 为 LifecycleOwner") - lifecycleOwner = recyclerView.context as LifecycleOwner - } - dispatchOnAttachedToRecyclerView(adapter, recyclerView) - } - - private fun dispatchOnAttachedToRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) { - try { - adapterHooks.forEach { - it.onAttachedToRecyclerView(adapter, recyclerView) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - internal fun onDetachedFromRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) { - dispatchOnDetachedFromRecyclerView(adapter, recyclerView) - } - - private fun dispatchOnDetachedFromRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) { - try { - adapterHooks.forEach { - it.onDetachedFromRecyclerView(adapter, recyclerView) - } - } catch (e: Exception) { - e.printStackTrace() - } - } -} \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapInitializer.kt b/flap/src/main/java/me/yifeiyuan/flap/FlapInitializer.kt new file mode 100644 index 000000000..e14ebf340 --- /dev/null +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapInitializer.kt @@ -0,0 +1,51 @@ +package me.yifeiyuan.flap + +import android.content.Context +import me.yifeiyuan.flap.delegate.* +import me.yifeiyuan.flap.delegate.AdapterDelegateManager +import me.yifeiyuan.flap.delegate.DefaultFallbackAdapterDelegate +import me.yifeiyuan.flap.delegate.IAdapterDelegateManager +import me.yifeiyuan.flap.hook.AdapterHookManager +import me.yifeiyuan.flap.hook.IAdapterHookManager +import me.yifeiyuan.flap.service.AdapterServiceManager +import me.yifeiyuan.flap.service.IAdapterServiceManager + +/** + * FlapInitializer 是 Flap 的初始化器,存放全局的配置,会应用于所有的 FlapAdapter 实例。 + * + * - AdapterDelegate + * - AdapterHook + * - AdapterService + * + * Created by 程序亦非猿 on 2021/9/22. + * + * Flap Github: https://github.com/AlanCheen/Flap + * @author 程序亦非猿 [Follow me]( https://github.com/AlanCheen) + * @since 2020/9/22 + * @since 3.0.0 + */ +object FlapInitializer : IAdapterHookManager by AdapterHookManager(), IAdapterDelegateManager by AdapterDelegateManager(), IAdapterServiceManager by AdapterServiceManager() { + + /** + * 是否使用 application context 来创建 Component + */ + var inflateWithApplicationContext = false + + internal var globalFallbackAdapterDelegate: FallbackAdapterDelegate = DefaultFallbackAdapterDelegate() + + fun withContext(context: Context) = apply { + context.applicationContext + } + + /** + * 设置全局的 FallbackAdapterDelegate + */ + fun withFallbackAdapterDelegate(fallbackAdapterDelegate: FallbackAdapterDelegate) = apply { + globalFallbackAdapterDelegate = fallbackAdapterDelegate + } + + fun setDebug(debug: Boolean) = apply { + FlapDebug.isDebug = debug + } + +} \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/delegate/AdapterDelegate.kt b/flap/src/main/java/me/yifeiyuan/flap/delegate/AdapterDelegate.kt index cad8f1856..697414ea1 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/delegate/AdapterDelegate.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/delegate/AdapterDelegate.kt @@ -4,7 +4,7 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter +import me.yifeiyuan.flap.Flap import java.lang.reflect.ParameterizedType /** @@ -79,36 +79,37 @@ interface AdapterDelegate> { data: Any, position: Int, payloads: List, - adapter: FlapAdapter + adapter: RecyclerView.Adapter<*>, + flap: Flap ) { - component.bindData(data, position, payloads, adapter, this) + component.bindData(data, position, payloads, adapter, flap) } /** - * @see FlapAdapter.onViewAttachedToWindow + * @see RecyclerView.Adapter.onViewAttachedToWindow */ - fun onViewAttachedToWindow(adapter: FlapAdapter, component: Component<*>) { + fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { component.onViewAttachedToWindow(adapter) } /** - * @see FlapAdapter.onViewDetachedFromWindow + * @see RecyclerView.Adapter.onViewDetachedFromWindow */ - fun onViewDetachedFromWindow(adapter: FlapAdapter, component: Component<*>) { + fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { component.onViewDetachedFromWindow(adapter) } /** - * @see FlapAdapter.onFailedToRecycleView + * @see RecyclerView.Adapter.onFailedToRecycleView */ - fun onFailedToRecycleView(adapter: FlapAdapter, component: Component<*>): Boolean { + fun onFailedToRecycleView(adapter: RecyclerView.Adapter<*>, component: Component<*>): Boolean { return component.onFailedToRecycleView(adapter) } /** - * @see FlapAdapter.onViewRecycled + * @see RecyclerView.Adapter.onViewRecycled */ - fun onViewRecycled(adapter: FlapAdapter, component: Component<*>) { + fun onViewRecycled(adapter: RecyclerView.Adapter<*>, component: Component<*>) { component.onViewRecycled(adapter) } } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/delegate/FallbackAdapterDelegate.kt b/flap/src/main/java/me/yifeiyuan/flap/delegate/FallbackAdapterDelegate.kt index 948efb7f7..46cb35482 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/delegate/FallbackAdapterDelegate.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/delegate/FallbackAdapterDelegate.kt @@ -17,9 +17,9 @@ import me.yifeiyuan.flap.FlapDebug * * 开发者也可以自己定义自己的 FallbackAdapterDelegate。 * - * @see me.yifeiyuan.flap.Flap.globalFallbackAdapterDelegate - * @see me.yifeiyuan.flap.FlapAdapter.defaultAdapterDelegate - * @see FallbackComponent + * @see me.yifeiyuan.flap.FlapInitializer.globalFallbackAdapterDelegate + * @see me.yifeiyuan.flap.Flap.fallbackDelegate + * @see DefaultFallbackComponent * * Created by 程序亦非猿 on 2021/9/22. * @@ -28,19 +28,19 @@ import me.yifeiyuan.flap.FlapDebug * @since 2020/9/22 * @since 3.0.0 */ -internal class FallbackAdapterDelegate : AdapterDelegate { - - override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup, viewType: Int): FallbackComponent { - return FallbackComponent(TextView(parent.context)) - } - +abstract class FallbackAdapterDelegate : AdapterDelegate>{ override fun delegate(model: Any): Boolean { return true } +} +internal class DefaultFallbackAdapterDelegate : FallbackAdapterDelegate() { + override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup, viewType: Int): DefaultFallbackComponent { + return DefaultFallbackComponent(TextView(parent.context)) + } } -internal class FallbackComponent(v: View) : Component(v) { +internal class DefaultFallbackComponent(v: View) : Component(v) { override fun onBind(model: Any) { if (FlapDebug.isDebug) { (itemView as TextView).run { diff --git a/flap/src/main/java/me/yifeiyuan/flap/delegate/IAdapterDelegateManager.kt b/flap/src/main/java/me/yifeiyuan/flap/delegate/IAdapterDelegateManager.kt index 56762e90e..ff99a0b79 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/delegate/IAdapterDelegateManager.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/delegate/IAdapterDelegateManager.kt @@ -8,7 +8,7 @@ package me.yifeiyuan.flap.delegate * Created by 程序亦非猿 on 2022/9/5. * @since 3.1.0 */ -internal interface IAdapterDelegateManager { +interface IAdapterDelegateManager { val adapterDelegates: MutableList> diff --git a/flap/src/main/java/me/yifeiyuan/flap/delegate/LayoutAdapterDelegate.kt b/flap/src/main/java/me/yifeiyuan/flap/delegate/LayoutAdapterDelegate.kt deleted file mode 100644 index b1ec1666e..000000000 --- a/flap/src/main/java/me/yifeiyuan/flap/delegate/LayoutAdapterDelegate.kt +++ /dev/null @@ -1,55 +0,0 @@ -package me.yifeiyuan.flap.delegate - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.annotation.LayoutRes -import androidx.recyclerview.widget.RecyclerView -import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter - -/** - * - * LayoutAdapterDelegate 是为了降低创建 Component 和 自定义 AdapterDelegate 带来的使用成本而创建的。 - * - * 使用 LayoutAdapterDelegate 只适用于: - * - layoutId 可以当做 itemViewType 直接用 - * - 只关心 onBind 处理逻辑 - * - * LayoutAdapterDelegate 的使用体验介于 自定义 AdapterDelegate 和 DSL 中间,看情况选择。 - * - * @see me.yifeiyuan.flap.dsl.adapterDelegate - * - * Created by 程序亦非猿 on 2021/10/27. - * @since 3.1.1 - */ -class LayoutAdapterDelegate( - private var modelClass: Class?, - @LayoutRes - private var layoutId: Int, - private var itemId: Long = RecyclerView.NO_ID, - private var isDelegateFor: ((model: Any) -> Boolean) = { m -> m.javaClass == modelClass }, - private var onBind: Component.(model: T, position: Int, payloads: List, adapter: FlapAdapter) -> Unit, -) : AdapterDelegate> { - - override fun delegate(model: Any): Boolean { - return isDelegateFor.invoke(model) - } - - override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup, viewType: Int): Component { - val view = inflater.inflate(viewType, parent, false) - return Component(view) - } - - override fun onBindViewHolder(component: Component<*>, data: Any, position: Int, payloads: List, adapter: FlapAdapter) { - onBind.invoke(component as Component, data as T, position, payloads, adapter) - } - - override fun getItemViewType(model: Any): Int { - return layoutId - } - - override fun getItemId(model: Any, position: Int): Long { - return itemId - } -} \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterDelegateDsl.kt b/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterDelegateDsl.kt index 9861559ec..377bd5456 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterDelegateDsl.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterDelegateDsl.kt @@ -7,7 +7,7 @@ import androidx.annotation.LayoutRes import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter +import me.yifeiyuan.flap.Flap import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.ext.BooleanBlock import me.yifeiyuan.flap.ext.UnitBlock @@ -58,8 +58,8 @@ class DslAdapterDelegate( return component } - override fun onBindViewHolder(component: Component<*>, data: Any, position: Int, payloads: List, adapter: FlapAdapter) { - super.onBindViewHolder(component, data, position, payloads, adapter) + override fun onBindViewHolder(component: Component<*>, data: Any, position: Int, payloads: List, adapter: RecyclerView.Adapter<*>, flap: Flap) { + super.onBindViewHolder(component, data, position, payloads, adapter, flap) } override fun getItemViewType(model: Any): Int { @@ -81,7 +81,7 @@ open class DslComponent(view: View) : Component(view) { /** * 更多参数的 onBind */ - private var onBind2: ((model: T, position: Int, payloads: List, adapter: FlapAdapter) -> Unit)? = null + private var onBind2: ((model: T, position: Int, payloads: List) -> Unit)? = null /** * 简单参数的 onBind @@ -102,17 +102,17 @@ open class DslComponent(view: View) : Component(view) { /** * 单击事件 */ - private var onClickListener: ((model: T, position: Int, adapter: FlapAdapter) -> Unit)? = null + private var onClickListener: ((model: T, position: Int) -> Unit)? = null /** * 长按事件 */ - private var onLongClickListener: ((model: T, position: Int, adapter: FlapAdapter) -> Boolean)? = null + private var onLongClickListener: ((model: T, position: Int) -> Boolean)? = null - override fun onBind(model: T, position: Int, payloads: List, adapter: FlapAdapter, delegate: AdapterDelegate<*, *>) { + override fun onBind(model: T, position: Int, payloads: List) { if (onBind2 != null) { - onBind2?.invoke(model, position, payloads, adapter) + onBind2?.invoke(model, position, payloads) } else if (onBind != null) { onBind?.invoke(model) } @@ -120,7 +120,7 @@ open class DslComponent(view: View) : Component(view) { if (onClickListener != null) { itemView.setOnClickListener { if (isClickable()) { - onClickListener?.invoke(model, position, adapter) + onClickListener?.invoke(model, position) } } } else { @@ -130,7 +130,7 @@ open class DslComponent(view: View) : Component(view) { if (onLongClickListener != null) { itemView.setOnLongClickListener { if (isLongClickable()) { - onLongClickListener!!.invoke(model, position, adapter) + onLongClickListener!!.invoke(model, position) } else { false } @@ -140,18 +140,18 @@ open class DslComponent(view: View) : Component(view) { } } - override fun onViewAttachedToWindow(flapAdapter: FlapAdapter) { - super.onViewAttachedToWindow(flapAdapter) + override fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>) { + super.onViewAttachedToWindow(adapter) onViewAttachedToWindow?.invoke() } - override fun onViewDetachedFromWindow(flapAdapter: FlapAdapter) { - super.onViewDetachedFromWindow(flapAdapter) + override fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>) { + super.onViewDetachedFromWindow(adapter) onViewDetachedFromWindow?.invoke() } - override fun onViewRecycled(flapAdapter: FlapAdapter) { - super.onViewRecycled(flapAdapter) + override fun onViewRecycled(adapter: RecyclerView.Adapter<*>) { + super.onViewRecycled(adapter) onViewRecycled?.invoke() } @@ -175,8 +175,8 @@ open class DslComponent(view: View) : Component(view) { onDestroy?.invoke() } - override fun onFailedToRecycleView(flapAdapter: FlapAdapter): Boolean { - return onFailedToRecycleView?.invoke() ?: super.onFailedToRecycleView(flapAdapter) + override fun onFailedToRecycleView(adapter: RecyclerView.Adapter<*>): Boolean { + return onFailedToRecycleView?.invoke() ?: super.onFailedToRecycleView(adapter) } var swipeFlags: Int? = null @@ -213,15 +213,15 @@ open class DslComponent(view: View) : Component(view) { this.onBind = onBind } - fun onBind(onBind: ((model: T, position: Int, payloads: List, adapter: FlapAdapter) -> Unit)) { + fun onBind(onBind: ((model: T, position: Int, payloads: List) -> Unit)) { onBind2 = onBind } - fun onClick(onclick: ((model: T, position: Int, adapter: FlapAdapter) -> Unit)) { + fun onClick(onclick: ((model: T, position: Int) -> Unit)) { onClickListener = onclick } - fun onLongClick(onLongClick: ((model: T, position: Int, adapter: FlapAdapter) -> Boolean)) { + fun onLongClick(onLongClick: ((model: T, position: Int) -> Boolean)) { onLongClickListener = onLongClick } diff --git a/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterHookDsl.kt b/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterHookDsl.kt index b34bedc04..5fd842672 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterHookDsl.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/dsl/AdapterHookDsl.kt @@ -2,9 +2,8 @@ package me.yifeiyuan.flap.dsl +import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter -import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.hook.AdapterHook /** @@ -25,60 +24,60 @@ fun adapterHook(block: DslAdapterHook.() -> Unit): AdapterHook { */ class DslAdapterHook : AdapterHook { - private var onCreateViewHolderStart: ((adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) -> Unit)? = null - private var onCreateViewHolderEnd: ((adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int, component: Component<*>) -> Unit)? = null + private var onCreateViewHolderStart: ((adapter: RecyclerView.Adapter<*>, viewType: Int) -> Unit)? = null + private var onCreateViewHolderEnd: ((adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) -> Unit)? = null - private var onViewAttachedToWindow: ((adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) -> Unit)? = null - private var onViewDetachedFromWindow: ((adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) -> Unit)? = null + private var onViewAttachedToWindow: ((adapter: RecyclerView.Adapter<*>, component: Component<*>) -> Unit)? = null + private var onViewDetachedFromWindow: ((adapter: RecyclerView.Adapter<*>, component: Component<*>) -> Unit)? = null - private var onBindViewHolderStart: ((adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit)? = null - private var onBindViewHolderEnd: ((adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit)? = null + private var onBindViewHolderStart: ((adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit)? = null + private var onBindViewHolderEnd: ((adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit)? = null - fun onCreateViewHolderStart(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) -> Unit) { + fun onCreateViewHolderStart(block: (adapter: RecyclerView.Adapter<*>, viewType: Int) -> Unit) { onCreateViewHolderStart = block } - fun onCreateViewHolderEnd(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int, component: Component<*>) -> Unit) { + fun onCreateViewHolderEnd(block: (adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) -> Unit) { onCreateViewHolderEnd = block } - fun onViewAttachedToWindow(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) -> Unit) { + fun onViewAttachedToWindow(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>) -> Unit) { onViewAttachedToWindow = block } - fun onViewDetachedFromWindow(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) -> Unit) { + fun onViewDetachedFromWindow(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>) -> Unit) { onViewDetachedFromWindow = block } - fun onBindViewHolderStart(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { + fun onBindViewHolderStart(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { onBindViewHolderStart = block } - fun onBindViewHolderEnd(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { + fun onBindViewHolderEnd(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { onBindViewHolderEnd = block } - override fun onCreateViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) { - onCreateViewHolderStart?.invoke(adapter, delegate, viewType) + override fun onCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) { + onCreateViewHolderStart?.invoke(adapter, viewType) } - override fun onCreateViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int, component: Component<*>) { - onCreateViewHolderEnd?.invoke(adapter, delegate, viewType, component) + override fun onCreateViewHolderEnd(adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) { + onCreateViewHolderEnd?.invoke(adapter, viewType, component) } - override fun onBindViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { - onBindViewHolderStart?.invoke(adapter, delegate, component, data, position, payloads) + override fun onBindViewHolderStart(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + onBindViewHolderStart?.invoke(adapter, component, data, position, payloads) } - override fun onBindViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { - onBindViewHolderEnd?.invoke(adapter, delegate, component, data, position, payloads) + override fun onBindViewHolderEnd(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + onBindViewHolderEnd?.invoke(adapter, component, data, position, payloads) } - override fun onViewAttachedToWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { - onViewAttachedToWindow?.invoke(adapter, delegate, component) + override fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + onViewAttachedToWindow?.invoke(adapter, component) } - override fun onViewDetachedFromWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { - onViewDetachedFromWindow?.invoke(adapter, delegate, component) + override fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + onViewDetachedFromWindow?.invoke(adapter, component) } } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/event/Event.kt b/flap/src/main/java/me/yifeiyuan/flap/event/Event.kt index ed533aef7..574106eca 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/event/Event.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/event/Event.kt @@ -3,8 +3,8 @@ package me.yifeiyuan.flap.event /** * 在 FlapAdapter 与 Component 之间发送的事件 * - * @see me.yifeiyuan.flap.FlapAdapter.fireEvent - * @see me.yifeiyuan.flap.FlapAdapter.observeEvent + * @see me.yifeiyuan.flap.Flap.fireEvent + * @see me.yifeiyuan.flap.Flap.observeEvent * @see EventObserver * * Created by 程序亦非猿 on 2021/9/30. diff --git a/flap/src/main/java/me/yifeiyuan/flap/ext/ComponentBinder.kt b/flap/src/main/java/me/yifeiyuan/flap/ext/ComponentBinder.kt index 0b8f5801e..e2248c43c 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/ext/ComponentBinder.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/ext/ComponentBinder.kt @@ -20,6 +20,8 @@ import me.yifeiyuan.flap.Component * @see bindImageButton * @see bindProgressBar * @see bindRatingBar + * @see bindRadioButton + * @see bindRadioGroup * * Created by 程序亦非猿 on 2021/9/29. * @since 3.0.0 diff --git a/flap/src/main/java/me/yifeiyuan/flap/ext/EmptyViewHelper.kt b/flap/src/main/java/me/yifeiyuan/flap/ext/EmptyViewHelper.kt index 76d1907aa..766d88a4c 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/ext/EmptyViewHelper.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/ext/EmptyViewHelper.kt @@ -2,8 +2,12 @@ package me.yifeiyuan.flap.ext import android.view.View import androidx.recyclerview.widget.RecyclerView +import me.yifeiyuan.flap.FlapApi +import me.yifeiyuan.flap.hook.AdapterHook +import me.yifeiyuan.flap.hook.IAdapterHookManager /** + * todo 改造,不默认放入Flap,在使用时绑定 * * 当 FlapRecyclerView 内容为空时,帮助展示 EmptyView * @@ -12,7 +16,7 @@ import androidx.recyclerview.widget.RecyclerView * Created by 程序亦非猿 on 2022/6/16. * @since 3.0.0 */ -class EmptyViewHelper : OnAdapterDataChangedObserver() { +class EmptyViewHelper : OnAdapterDataChangedObserver() ,AdapterHook{ /** * 设置空状态下需要展示的 View @@ -27,21 +31,20 @@ class EmptyViewHelper : OnAdapterDataChangedObserver() { */ var contentView: RecyclerView? = null - fun attachRecyclerView(targetRecyclerView: RecyclerView, checkRightNow: Boolean = false) { + private fun attachRecyclerView(targetRecyclerView: RecyclerView, checkRightNow: Boolean = false) { contentView = targetRecyclerView contentView?.adapter?.let { attachAdapter(it,checkRightNow) } } - fun detachRecyclerView() { + private fun detachRecyclerView() { contentView?.adapter?.let { detachAdapter(it) } } /** - * * @param adapter RecyclerView.adapter * @param checkRightNow 是否立即检查是否展示 empty view */ @@ -69,6 +72,19 @@ class EmptyViewHelper : OnAdapterDataChangedObserver() { maybeShowEmptyView() } + override fun onAttachedToRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { + attachRecyclerView(recyclerView,true) + } + + override fun onDetachedFromRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { + try { + adapter.unregisterAdapterDataObserver(this) + } catch (e: Exception) { + //ignore + } + detachRecyclerView() + } + private fun maybeShowEmptyView() { if (contentView != null && emptyView != null) if (contentView!!.adapter != null && contentView!!.adapter?.itemCount == 0) { diff --git a/flap/src/main/java/me/yifeiyuan/flap/ext/Extendtions.kt b/flap/src/main/java/me/yifeiyuan/flap/ext/Extendtions.kt index 53132903a..7bde13dd3 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/ext/Extendtions.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/ext/Extendtions.kt @@ -2,9 +2,9 @@ package me.yifeiyuan.flap.ext +import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component import me.yifeiyuan.flap.FlapAdapter -import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.hook.AdapterHook /** @@ -18,10 +18,10 @@ import me.yifeiyuan.flap.hook.AdapterHook * 在 onCreateViewHolder 之前回调 * @see doOnCreateViewHolderEnd */ -fun FlapAdapter.doOnCreateViewHolderStart(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) -> Unit) { +fun FlapAdapter.doOnCreateViewHolderStart(block: (adapter: RecyclerView.Adapter<*>, viewType: Int) -> Unit) { registerAdapterHook(object : AdapterHook { - override fun onCreateViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) { - block.invoke(adapter, delegate, viewType) + override fun onCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) { + block.invoke(adapter, viewType) } }) } @@ -30,10 +30,10 @@ fun FlapAdapter.doOnCreateViewHolderStart(block: (adapter: FlapAdapter, delegate * 在 onCreateViewHolder 之后回调 * @see doOnCreateViewHolderStart */ -fun FlapAdapter.doOnCreateViewHolderEnd(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int, component: Component<*>) -> Unit) { +fun FlapAdapter.doOnCreateViewHolderEnd(block: (adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) -> Unit) { registerAdapterHook(object : AdapterHook { - override fun onCreateViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int, component: Component<*>) { - block.invoke(adapter, delegate, viewType, component) + override fun onCreateViewHolderEnd(adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) { + block.invoke(adapter, viewType, component) } }) } @@ -42,10 +42,10 @@ fun FlapAdapter.doOnCreateViewHolderEnd(block: (adapter: FlapAdapter, delegate: * 在 onBindViewHolder 之前回调 * @see doOnBindViewHolderEnd */ -fun FlapAdapter.doOnBindViewHolderStart(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { +fun FlapAdapter.doOnBindViewHolderStart(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { registerAdapterHook(object : AdapterHook { - override fun onBindViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { - block.invoke(adapter, delegate, component, data, position, payloads) + override fun onBindViewHolderStart(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + block.invoke(adapter, component, data, position, payloads) } }) } @@ -54,10 +54,10 @@ fun FlapAdapter.doOnBindViewHolderStart(block: (adapter: FlapAdapter, delegate: * 在 onBindViewHolder 之后回调 * @see doOnBindViewHolderStart */ -fun FlapAdapter.doOnBindViewHolderEnd(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { +fun FlapAdapter.doOnBindViewHolderEnd(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) -> Unit) { registerAdapterHook(object : AdapterHook { - override fun onBindViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { - block.invoke(adapter, delegate, component, data, position, payloads) + override fun onBindViewHolderEnd(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + block.invoke(adapter, component, data, position, payloads) } }) } @@ -65,10 +65,10 @@ fun FlapAdapter.doOnBindViewHolderEnd(block: (adapter: FlapAdapter, delegate: Ad /** * @see doOnViewAttachedFromWindow */ -fun FlapAdapter.doOnViewDetachedFromWindow(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) -> Unit) { +fun FlapAdapter.doOnViewDetachedFromWindow(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>) -> Unit) { registerAdapterHook(object : AdapterHook { - override fun onViewDetachedFromWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { - block.invoke(adapter, delegate, component) + override fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + block.invoke(adapter, component) } }) } @@ -76,10 +76,10 @@ fun FlapAdapter.doOnViewDetachedFromWindow(block: (adapter: FlapAdapter, delegat /** * @see doOnViewDetachedFromWindow */ -fun FlapAdapter.doOnViewAttachedFromWindow(block: (adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) -> Unit) { +fun FlapAdapter.doOnViewAttachedFromWindow(block: (adapter: RecyclerView.Adapter<*>, component: Component<*>) -> Unit) { registerAdapterHook(object : AdapterHook { - override fun onViewAttachedToWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { - block.invoke(adapter, delegate, component) + override fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { + block.invoke(adapter, component) } }) } diff --git a/flap/src/main/java/me/yifeiyuan/flap/ext/ItemClicksHelper.kt b/flap/src/main/java/me/yifeiyuan/flap/ext/ItemClicksHelper.kt index 1891bcb53..fe9be4b38 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/ext/ItemClicksHelper.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/ext/ItemClicksHelper.kt @@ -3,6 +3,7 @@ package me.yifeiyuan.flap.ext import android.view.View import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.ComponentConfig +import me.yifeiyuan.flap.hook.AdapterHook typealias OnItemClickListener = ((recyclerView: RecyclerView, childView: View, position: Int) -> Unit) @@ -24,7 +25,7 @@ typealias OnItemLongClickListener = ((recyclerView: RecyclerView, childView: Vie * * @since 3.0.0 */ -internal class ItemClicksHelper : RecyclerView.OnChildAttachStateChangeListener { +internal class ItemClicksHelper : RecyclerView.OnChildAttachStateChangeListener, AdapterHook { lateinit var recyclerView: RecyclerView @@ -62,13 +63,12 @@ internal class ItemClicksHelper : RecyclerView.OnChildAttachStateChangeListener //do nothing } - fun attachRecyclerView(recyclerView: RecyclerView) { + override fun onAttachedToRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { this.recyclerView = recyclerView this.recyclerView.addOnChildAttachStateChangeListener(this) } - fun detachRecyclerView(recyclerView: RecyclerView) { + override fun onDetachedFromRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { recyclerView.removeOnChildAttachStateChangeListener(this) } - } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/ext/OnAdapterDataChangedObserver.kt b/flap/src/main/java/me/yifeiyuan/flap/ext/OnAdapterDataChangedObserver.kt index ef17ed77c..8f6268b73 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/ext/OnAdapterDataChangedObserver.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/ext/OnAdapterDataChangedObserver.kt @@ -3,7 +3,7 @@ package me.yifeiyuan.flap.ext import androidx.recyclerview.widget.RecyclerView /** - * 只关心数据有变化,不关心变化的细节 + * 只关心数据有变化,不关心变化的细节。 * * Created by 程序亦非猿 on 2022/8/12. * @@ -41,6 +41,5 @@ abstract class OnAdapterDataChangedObserver : RecyclerView.AdapterDataObserver() onAdapterDataChanged() } - override fun onStateRestorationPolicyChanged() { - } + override fun onStateRestorationPolicyChanged() {} } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/hook/AdapterHook.kt b/flap/src/main/java/me/yifeiyuan/flap/hook/AdapterHook.kt index 73fd78079..5ee870c21 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/hook/AdapterHook.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/hook/AdapterHook.kt @@ -1,13 +1,12 @@ package me.yifeiyuan.flap.hook import androidx.recyclerview.widget.RecyclerView -import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.Component import me.yifeiyuan.flap.FlapAdapter /** * - * AdapterHook 是基于 Adapter 做的 hooks ,可以通过 hooks 监听一些流程,例如组件的创建流程。 + * AdapterHook 是基于 Adapter 做的 hooks ,可以通过这些 hooks 监听一些流程,例如组件的创建流程。 * 并方便以 AOP & 解耦的方式实现某些功能。 * * 内置的一些 AdapterHook 实现: @@ -28,101 +27,76 @@ interface AdapterHook { * 在创建组件前调用 * * @param adapter 正在创建组件的 adapter - * @param delegate 创建组件的代理 * @param viewType viewType */ - fun onCreateViewHolderStart( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, - viewType: Int - ) { - } + fun onCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) {} /** * 在组件创建完毕后调用 * * @param adapter 正在创建组件的 adapter - * @param delegate 创建组件的代理 * @param viewType viewType * @param component 被创建出来的组件 */ fun onCreateViewHolderEnd( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, viewType: Int, - component: Component<*> - ) { + component: Component<*>) { } /** * 在绑定组件之前调用 * * @param adapter - * @param delegate 绑定组件的代理 * @param component * @param position * @param data * @param payloads */ fun onBindViewHolderStart( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, - payloads: MutableList - ) { + payloads: MutableList) { } /** * 在组件绑定完毕后回调 * * @param adapter - * @param delegate 绑定组件的代理 * @param component * @param position * @param data * @param payloads */ fun onBindViewHolderEnd( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, - payloads: MutableList - ) { + payloads: MutableList) { } /** * @see FlapAdapter.onViewAttachedToWindow */ - fun onViewAttachedToWindow( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, - component: Component<*>, - ) { - } + fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) {} /** * @see FlapAdapter.onViewDetachedFromWindow */ - fun onViewDetachedFromWindow( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, - component: Component<*>, - ) { - } + fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) {} /** * @see FlapAdapter.onAttachedToRecyclerView * @since 3.1.5 */ - fun onAttachedToRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) {} + fun onAttachedToRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) {} /** * @see FlapAdapter.onDetachedFromRecyclerView * @since 3.1.5 */ - fun onDetachedFromRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) {} + fun onDetachedFromRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) {} } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/hook/ApmHook.kt b/flap/src/main/java/me/yifeiyuan/flap/hook/ApmHook.kt index 389bb1d4c..e2c9cf769 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/hook/ApmHook.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/hook/ApmHook.kt @@ -1,9 +1,8 @@ package me.yifeiyuan.flap.hook import android.os.SystemClock -import me.yifeiyuan.flap.delegate.AdapterDelegate +import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter import me.yifeiyuan.flap.FlapDebug /** @@ -36,13 +35,12 @@ open class ApmHook(private val createTimeCostThreshold: Long = 20, private val b private var createStartTime: Long = 0 private var bindStartTime: Long = 0 - override fun onCreateViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) { + override fun onCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) { createStartTime = SystemClock.uptimeMillis() } override fun onCreateViewHolderEnd( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*> ) { @@ -50,10 +48,10 @@ open class ApmHook(private val createTimeCostThreshold: Long = 20, private val b val cost = endTime - createStartTime FlapDebug.d( TAG, - "${delegate.javaClass.simpleName} 【创建】组件完成,耗时 $cost (毫秒),组件为:$component" + "【创建】组件完成,耗时 $cost (毫秒),组件为:$component" ) if (cost > createTimeCostThreshold) { - onCreateAlarm(adapter, delegate, viewType, component, cost) + onCreateAlarm(adapter, viewType, component, cost) } } @@ -61,16 +59,14 @@ open class ApmHook(private val createTimeCostThreshold: Long = 20, private val b * 当创建耗时太长时警告 */ open fun onCreateAlarm( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>?, + adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>, cost: Long) { FlapDebug.e(TAG, "组件创建耗时过长,请优化!") } override fun onBindViewHolderStart( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, @@ -80,8 +76,7 @@ open class ApmHook(private val createTimeCostThreshold: Long = 20, private val b } override fun onBindViewHolderEnd( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, @@ -91,10 +86,10 @@ open class ApmHook(private val createTimeCostThreshold: Long = 20, private val b val cost = endTime - bindStartTime FlapDebug.d( TAG, - "${delegate.javaClass.simpleName} 【绑定】组件完成,耗时 $cost (毫秒),组件为:$component" + "【绑定】组件完成,耗时 $cost (毫秒),组件为:$component" ) if (cost > bindStartTime) { - onBindAlarm(adapter, delegate, component, data, position, payloads, cost) + onBindAlarm(adapter, component, data, position, payloads, cost) } } @@ -102,8 +97,7 @@ open class ApmHook(private val createTimeCostThreshold: Long = 20, private val b * 当绑定耗时太长时警告 */ open fun onBindAlarm( - adapter: FlapAdapter, - delegate: AdapterDelegate<*, *>, + adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, diff --git a/flap/src/main/java/me/yifeiyuan/flap/hook/IAdapterHookManager.kt b/flap/src/main/java/me/yifeiyuan/flap/hook/IAdapterHookManager.kt index 7a59d2e39..9fd794923 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/hook/IAdapterHookManager.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/hook/IAdapterHookManager.kt @@ -7,16 +7,20 @@ package me.yifeiyuan.flap.hook * Created by 程序亦非猿 on 2022/9/5. * @since 3.1.0 */ -internal interface IAdapterHookManager { +interface IAdapterHookManager { val adapterHooks: MutableList fun registerAdapterHook(adapterHook: AdapterHook) { - adapterHooks.add(adapterHook) + if (!adapterHooks.contains(adapterHook)) { + adapterHooks.add(adapterHook) + } } fun registerAdapterHook(index: Int, adapterHook: AdapterHook) { - adapterHooks.add(index, adapterHook) + if (!adapterHooks.contains(adapterHook)) { + adapterHooks.add(index, adapterHook) + } } fun registerAdapterHooks(vararg adapterHooks: AdapterHook) { diff --git a/flap/src/main/java/me/yifeiyuan/flap/hook/LoggingHook.kt b/flap/src/main/java/me/yifeiyuan/flap/hook/LoggingHook.kt index 020b0df0a..c73eafff4 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/hook/LoggingHook.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/hook/LoggingHook.kt @@ -2,9 +2,7 @@ package me.yifeiyuan.flap.hook import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter import me.yifeiyuan.flap.FlapDebug -import me.yifeiyuan.flap.delegate.AdapterDelegate /** * @@ -26,34 +24,33 @@ class LoggingHook(private val enableLog: Boolean = true, private val printTrace: class TraceException : RuntimeException("|只用于 LoggingHook 打印日志,不是真实异常|") } - override fun onCreateViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) { + override fun onCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) { if (enableLog) { - FlapDebug.d(TAG, "onCreateViewHolderStart() called with: adapter = $adapter, delegate = $delegate, viewType = $viewType") + FlapDebug.d(TAG, "onCreateViewHolderStart() called with: adapter = $adapter, viewType = $viewType") if (printTrace) { FlapDebug.e(TAG, "onCreateViewHolderStart: ", TraceException()) } } } - override fun onCreateViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int, component: Component<*>) { + override fun onCreateViewHolderEnd(adapter: RecyclerView.Adapter<*>, viewType: Int, component: Component<*>) { if (enableLog) { - FlapDebug.d(TAG, "onCreateViewHolderEnd() called with: adapter = $adapter, delegate = $delegate, viewType = $viewType, component = $component") + FlapDebug.d(TAG, "onCreateViewHolderEnd() called with: adapter = $adapter, viewType = $viewType, component = $component") } } - override fun onBindViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + override fun onBindViewHolderStart(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { if (enableLog) { - FlapDebug.d(TAG, "onBindViewHolderStart() called with: adapter = $adapter, delegate = $delegate, component = $component, data = $data, position = $position, payloads = $payloads") - + FlapDebug.d(TAG, "onBindViewHolderStart() called with: adapter = $adapter, component = $component, data = $data, position = $position, payloads = $payloads") if (printTrace) { FlapDebug.e(TAG, "onBindViewHolderStart: ", TraceException()) } } } - override fun onBindViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + override fun onBindViewHolderEnd(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { if (enableLog) { - FlapDebug.d(TAG, "onBindViewHolderEnd() called with: adapter = $adapter, delegate = $delegate, component = $component, data = $data, position = $position, payloads = $payloads") + FlapDebug.d(TAG, "onBindViewHolderEnd() called with: adapter = $adapter, component = $component, data = $data, position = $position, payloads = $payloads") if (payloads.isNotEmpty()) { //强调一下 payloads 的情况 FlapDebug.d(TAG, "onBindViewHolderEnd: >>>> payloads 不为空 <<<<") @@ -61,33 +58,39 @@ class LoggingHook(private val enableLog: Boolean = true, private val printTrace: } } - override fun onViewAttachedToWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { + override fun onViewAttachedToWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { if (enableLog) { - FlapDebug.d(TAG, "onViewAttachedToWindow() called with: adapter = $adapter, delegate = $delegate, component = $component") + FlapDebug.d(TAG, "onViewAttachedToWindow() called with: adapter = $adapter, component = $component") if (printTrace) { FlapDebug.e(TAG, "onViewAttachedToWindow: ", TraceException()) } } } - override fun onViewDetachedFromWindow(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>) { + override fun onViewDetachedFromWindow(adapter: RecyclerView.Adapter<*>, component: Component<*>) { if (enableLog) { - FlapDebug.d(TAG, "onViewDetachedFromWindow() called with: adapter = $adapter, delegate = $delegate, component = $component") + FlapDebug.d(TAG, "onViewDetachedFromWindow() called with: adapter = $adapter, component = $component") if (printTrace) { FlapDebug.e(TAG, "onViewDetachedFromWindow: ", TraceException()) } } } - override fun onAttachedToRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) { + override fun onAttachedToRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { if (enableLog) { FlapDebug.d(TAG, "onAttachedToRecyclerView() called with: adapter = $adapter, recyclerView = $recyclerView") + if (printTrace) { + FlapDebug.e(TAG, "onAttachedToRecyclerView: ", TraceException()) + } } } - override fun onDetachedFromRecyclerView(adapter: FlapAdapter, recyclerView: RecyclerView) { + override fun onDetachedFromRecyclerView(adapter: RecyclerView.Adapter<*>, recyclerView: RecyclerView) { if (enableLog) { FlapDebug.d(TAG, "onDetachedFromRecyclerView() called with: adapter = $adapter, recyclerView = $recyclerView") + if (printTrace) { + FlapDebug.e(TAG, "onDetachedFromRecyclerView: ", TraceException()) + } } } } \ No newline at end of file diff --git a/flap/src/main/java/me/yifeiyuan/flap/hook/PreloadHook.kt b/flap/src/main/java/me/yifeiyuan/flap/hook/PreloadHook.kt index b54e09c78..7cb7eb878 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/hook/PreloadHook.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/hook/PreloadHook.kt @@ -1,9 +1,8 @@ package me.yifeiyuan.flap.hook +import androidx.recyclerview.widget.RecyclerView import me.yifeiyuan.flap.Component -import me.yifeiyuan.flap.FlapAdapter import me.yifeiyuan.flap.FlapDebug -import me.yifeiyuan.flap.delegate.AdapterDelegate import me.yifeiyuan.flap.ext.OnAdapterDataChangedObserver import java.util.concurrent.atomic.AtomicBoolean @@ -69,7 +68,7 @@ class PreloadHook(private val offset: Int = 0, private val minItemCount: Int = 2 } } - override fun onCreateViewHolderStart(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, viewType: Int) { + override fun onCreateViewHolderStart(adapter: RecyclerView.Adapter<*>, viewType: Int) { if (!registered) { registered = true adapter.registerAdapterDataObserver(observer) @@ -77,7 +76,8 @@ class PreloadHook(private val offset: Int = 0, private val minItemCount: Int = 2 } private var prePosition = -1 - override fun onBindViewHolderEnd(adapter: FlapAdapter, delegate: AdapterDelegate<*, *>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { + + override fun onBindViewHolderEnd(adapter: RecyclerView.Adapter<*>, component: Component<*>, data: Any, position: Int, payloads: MutableList) { val itemCount = adapter.itemCount if (preloadEnable && !loading.get()) { if (direction == SCROLL_DOWN && prePosition < position) { diff --git a/flap/src/main/java/me/yifeiyuan/flap/pool/ComponentPool.kt b/flap/src/main/java/me/yifeiyuan/flap/pool/ComponentPool.kt index 9d0d985a9..28aa264e2 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/pool/ComponentPool.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/pool/ComponentPool.kt @@ -9,7 +9,7 @@ import me.yifeiyuan.flap.FlapDebug /** * 自定义的 RecycledViewPool,实现了 ComponentCallbacks2 ,可以在内存不足的时候清理缓存 * - * @see me.yifeiyuan.flap.FlapAdapter.withComponentPoolEnable 设置开关 + * @see me.yifeiyuan.flap.Flap.withComponentPoolEnable 设置开关 * * Created by 程序亦非猿 on 2021/9/22. * diff --git a/flap/src/main/java/me/yifeiyuan/flap/service/AdapterServiceManager.kt b/flap/src/main/java/me/yifeiyuan/flap/service/AdapterServiceManager.kt index 841ff658e..a5de8ff97 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/service/AdapterServiceManager.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/service/AdapterServiceManager.kt @@ -4,8 +4,8 @@ package me.yifeiyuan.flap.service * * 提供注册和发现 AdapterService 的能力 * - * @see me.yifeiyuan.flap.FlapAdapter.registerAdapterService - * @see me.yifeiyuan.flap.FlapAdapter.getAdapterService + * @see me.yifeiyuan.flap.Flap.registerAdapterService + * @see me.yifeiyuan.flap.Flap.getAdapterService * * Created by 程序亦非猿 on 2022/8/16. * @since 3.0.3 diff --git a/flap/src/main/java/me/yifeiyuan/flap/service/IAdapterServiceManager.kt b/flap/src/main/java/me/yifeiyuan/flap/service/IAdapterServiceManager.kt index a3436dc40..6f7c8b262 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/service/IAdapterServiceManager.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/service/IAdapterServiceManager.kt @@ -9,7 +9,7 @@ package me.yifeiyuan.flap.service * * @since 3.0.3 */ -internal interface IAdapterServiceManager { +interface IAdapterServiceManager { val adapterServices: MutableMap, AdapterService> diff --git a/flap/src/main/java/me/yifeiyuan/flap/widget/FlapStickyHeaderLinearLayoutManager.kt b/flap/src/main/java/me/yifeiyuan/flap/widget/FlapStickyHeaderLinearLayoutManager.kt index e96d1221e..a455a3f0c 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/widget/FlapStickyHeaderLinearLayoutManager.kt +++ b/flap/src/main/java/me/yifeiyuan/flap/widget/FlapStickyHeaderLinearLayoutManager.kt @@ -10,7 +10,6 @@ import android.view.ViewTreeObserver import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.parcel.Parcelize -import me.yifeiyuan.flap.FlapAdapter /** * Created by 程序亦非猿 on 2022/10/17. diff --git a/settings.gradle b/settings.gradle index 6b7fc18e1..6a930cc24 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,9 @@ +include ':flap-paging' include ':flap-animation' include ':flap-dsl-databinding' include ':flap-dsl-viewbinding' -//include ':flap-gradle-plugin' include ':app' include ':flap' //include ':flap-annotations' //include ':flap-compiler' +//include ':flap-gradle-plugin'