diff --git a/CHANGELOG.md b/CHANGELOG.md index 16de1fa6..4e898540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ([#193](https://github.com/badoo/MVICore/pull/193)): Updated Kotlin to 1.8.10 +([#194](https://github.com/badoo/MVICore/pull/194)): +Introduced the ability to override `AndroidMainThreadFeatureScheduler` via `MviCoreAndroidPlugins` (similar to `RxAndroidPlugins` within RxAndroid). + ### 1.4.0 #### Additions diff --git a/mvicore-android/build.gradle.kts b/mvicore-android/build.gradle.kts index 0345e410..d4c34c9d 100644 --- a/mvicore-android/build.gradle.kts +++ b/mvicore-android/build.gradle.kts @@ -30,6 +30,7 @@ android { } testOptions { + unitTests.isReturnDefaultValues = true unitTests.all { it.useJUnitPlatform() } diff --git a/mvicore-android/src/main/java/com/badoo/mvicore/android/AndroidMainThreadFeatureScheduler.kt b/mvicore-android/src/main/java/com/badoo/mvicore/android/AndroidMainThreadFeatureScheduler.kt index 9c750aa3..5704253f 100644 --- a/mvicore-android/src/main/java/com/badoo/mvicore/android/AndroidMainThreadFeatureScheduler.kt +++ b/mvicore-android/src/main/java/com/badoo/mvicore/android/AndroidMainThreadFeatureScheduler.kt @@ -11,11 +11,29 @@ import io.reactivex.android.schedulers.AndroidSchedulers * * It also uses the 'isOnFeatureThread' field to avoid observing on the main thread if it is already * the current thread. + * + * To help facilitate testing, you can override the scheduler using + * [MviCoreAndroidPlugins.setMainThreadFeatureScheduler] */ -object AndroidMainThreadFeatureScheduler: FeatureScheduler { +object AndroidMainThreadFeatureScheduler : FeatureScheduler { + private val featureSchedulerDelegate: FeatureScheduler + get() = MviCoreAndroidPlugins.mainThreadFeatureScheduler + override val scheduler: Scheduler - get() = AndroidSchedulers.mainThread() + get() = featureSchedulerDelegate.scheduler override val isOnFeatureThread: Boolean - get() = Looper.myLooper() == Looper.getMainLooper() + get() = featureSchedulerDelegate.isOnFeatureThread + + /** + * The default implementation of the [AndroidMainThreadFeatureScheduler] which delegates to the + * RxAndroid main thread scheduler + */ + object Default : FeatureScheduler { + override val scheduler: Scheduler + get() = AndroidSchedulers.mainThread() + + override val isOnFeatureThread: Boolean + get() = Looper.myLooper() == Looper.getMainLooper() + } } diff --git a/mvicore-android/src/main/java/com/badoo/mvicore/android/MviCoreAndroidPlugins.kt b/mvicore-android/src/main/java/com/badoo/mvicore/android/MviCoreAndroidPlugins.kt new file mode 100644 index 00000000..3d31b054 --- /dev/null +++ b/mvicore-android/src/main/java/com/badoo/mvicore/android/MviCoreAndroidPlugins.kt @@ -0,0 +1,25 @@ +package com.badoo.mvicore.android + +import com.badoo.mvicore.feature.FeatureScheduler + +/** + * Allows customisation of the MVICore Android integration. + */ +object MviCoreAndroidPlugins { + @Volatile + var mainThreadFeatureScheduler: FeatureScheduler = AndroidMainThreadFeatureScheduler.Default + + /** + * Overrides the [AndroidMainThreadFeatureScheduler]. + */ + fun setMainThreadFeatureScheduler(schedulerProvider: () -> FeatureScheduler) { + mainThreadFeatureScheduler = schedulerProvider() + } + + /** + * Resets the plugins back to the original state. + */ + fun reset() { + mainThreadFeatureScheduler = AndroidMainThreadFeatureScheduler.Default + } +} diff --git a/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/AndroidMainThreadFeatureSchedulerTest.kt b/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/AndroidMainThreadFeatureSchedulerTest.kt new file mode 100644 index 00000000..41fed446 --- /dev/null +++ b/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/AndroidMainThreadFeatureSchedulerTest.kt @@ -0,0 +1,37 @@ +package com.badoo.mvicore.android.lifecycle + +import com.badoo.mvicore.android.AndroidMainThreadFeatureScheduler +import com.badoo.mvicore.android.MviCoreAndroidPlugins +import com.badoo.mvicore.feature.FeatureSchedulers +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions.assertSame +import org.junit.jupiter.api.Test + +class AndroidMainThreadFeatureSchedulerTest { + @AfterEach + fun after() { + MviCoreAndroidPlugins.reset() + } + + @Test + fun `GIVEN android main scheduler not overridden WHEN scheduler accessed THEN scheduler is android main thread scheduler`() { + assertSame(AndroidSchedulers.mainThread(), AndroidMainThreadFeatureScheduler.scheduler) + } + + @Test + fun `GIVEN android main scheduler overridden with trampoline feature scheduler WHEN scheduler accessed THEN scheduler is trampoline scheduler`() { + MviCoreAndroidPlugins.setMainThreadFeatureScheduler { FeatureSchedulers.TrampolineFeatureScheduler } + + assertSame(Schedulers.trampoline(), AndroidMainThreadFeatureScheduler.scheduler) + } + + @Test + fun `GIVEN android main scheduler overridden with trampoline feature scheduler AND reset WHEN scheduler accessed THEN scheduler is android main thread scheduler`() { + MviCoreAndroidPlugins.setMainThreadFeatureScheduler { FeatureSchedulers.TrampolineFeatureScheduler } + MviCoreAndroidPlugins.reset() + + assertSame(AndroidSchedulers.mainThread(), AndroidMainThreadFeatureScheduler.scheduler) + } +}