From 59618b694edbef51cd537dca82074228b308af39 Mon Sep 17 00:00:00 2001 From: Rick Busarow Date: Sun, 20 Sep 2020 21:04:03 -0500 Subject: [PATCH] 1.0.0 beta04 (#162) * update version to 1.0.0-beta04 (#137) * Kotest 4.1.0 (#138) * update Kotest to 4.1.0 * update Kotest to 4.1.0 * update Kotest to 4.1.0 * update Kotest to 4.1.0 * Revert "update Kotest to 4.1.0" This reverts commit 833c838f * fix version parsing in DocsTasks * add `release/*` matcher to ci.yml * dispatch-internal-test-android module (#139) * add hermit dependency (#140) * add hermit dependency * add Hermit to the dependency matchers in DocsTasks * Lifecycle coroutine scope leak fixes (#141) * - automatically cancel LifecycleCoroutineScope when lifecycle reaches DESTROYED (fixes #135) - automatically remove lifecycleScope extension property from cache when lifecycle reaches DESTROYED (fixes #136) * dispatch-internal-test-android module * update lifecycle handling * update lifecycle handling * update lifecycle handling * convert LifecycleScopeExtensionTest from Kotest to JUnit5 to fix some weird recursive behavior * convert LifecycleScopeExtensionTest from Kotest to JUnit5 to fix some weird recursive behavior * remove workspace.xml backup which shouldn't have been added to git * update docs from main branch * update change log (#142) * Change LifecycleCoroutineScope argument to a CoroutineContext, add LifecycleCoroutineScopeFactory (#145) * change LifecycleCoroutineScope argument to CoroutineContext * MainImmediateProvidedContext -> MainImmediateContext * MainImmediateProvidedContext -> MainImmediateContext * update docs * MainImmediateProvidedContext -> MainImmediateContext * Misc cleanup (#146) * LifecycleScopeFactory README example cleanup * remove duplicate dependency declarations in android-lifecycle gradle config * android-lifecycle sample annotation consolidation * lifecycleScope extension sample rename * MainImmediateCoroutineScope factory function formatting * update docs * - remove tabs (#147) - consolidate capitalization for modules and kdoc - add lifecycle-extensions - dtekt -> detekt * update Detekt to 1.10.0 (#148) * update Knit to 0.1.4 (#149) * coroutines 1.3.7 -> 1.3.8 (#150) * Detekt cleanup (#151) * Detekt cleanup * add detekt to CI, remove Lint * add dependency graph generator task * DefaultDispatcherProvider (#153) * add DefaultDispatcherProvider singleton holder (fixes #152) * update docs for DefaultDispatcherProvider * add resolution strategies for coroutines and dispatch (#155) * cleanup of LifecycleCoroutineScope samples (#156) * add ViewLifecycleCoroutineScope (#158) * add ViewLifecycleCoroutineScope * add ViewLifecycleCoroutineScope docs * Lifecycle coroutine scope context parameter (#160) * Add a CoroutineContext parameter to the Lifecycle launch and suspend functions * add tests * update docs --- .github/workflows/ci.yml | 16 +- .idea/codeStyles/Project.xml | 2 +- .idea/codeStyles/codeStyleConfig.xml | 2 +- CHANGELOG.md | 28 ++ README.md | 12 +- build.gradle.kts | 167 ++++--- buildSrc/src/main/kotlin/Dependencies.kt | 33 +- buildSrc/src/main/kotlin/DependencyGraph.kt | 171 ++++++++ buildSrc/src/main/kotlin/DocsTasks.kt | 26 +- buildSrc/src/main/kotlin/Modules.kt | 15 +- dispatch-android-espresso/README.md | 4 +- dispatch-android-espresso/build.gradle.kts | 1 + .../samples/build.gradle.kts | 1 + ...ngCoroutineScopeRuleWithLifecycleSample.kt | 4 +- .../espresso/IdlingDispatcherProvider.kt | 4 +- .../README.md | 12 +- .../dispatch-android-lifecycle-extensions.api | 5 + .../build.gradle.kts | 10 +- .../samples/build.gradle.kts | 8 + .../samples/src/test/java/samples/Fragment.kt | 1 + ...> LifecycleCoroutineScopeFactorySample.kt} | 16 +- ...le.kt => LifecycleScopeExtensionSample.kt} | 17 +- .../java/samples/WithLifecycleScopeSample.kt | 55 +++ .../lifecycle/LifecycleScopeFactory.kt | 66 ++- .../internal/LifecycleCoroutineScopeStore.kt | 73 ++-- .../android/lifecycle/internal/atomic.kt | 60 +++ .../{LifecycleScope.kt => lifecycleScope.kt} | 5 +- .../lifecycle/withViewLifecycleScope.kt | 32 ++ .../lifecycle/LifecycleScopeExtensionTest.kt | 413 ++++++++++++++++++ .../lifecycle/LifecycleScopeFactoryTest.kt | 28 +- .../ViewLifecycleScopeFlowCollectionTest.kt | 151 +++++++ .../WithViewLifecycleScopeExtensionTest.kt | 198 +++++++++ .../lifecycle/internal/AtomicGetOrPutTest.kt | 86 ++++ dispatch-android-lifecycle/README.md | 11 +- .../api/dispatch-android-lifecycle.api | 61 ++- dispatch-android-lifecycle/build.gradle.kts | 23 +- .../samples/build.gradle.kts | 13 + .../test/java/samples/FakeLifecycleOwner.kt | 73 ---- .../samples/src/test/java/samples/Fragment.kt | 1 + .../LifecycleCoroutineScopeFactorySample.kt | 50 +++ .../samples/LifecycleCoroutineScopeSample.kt | 80 +++- .../java/samples/LifecycleSuspendSample.kt | 2 +- .../java/samples/WithLifecycleScopeSample.kt | 61 +++ .../lifecycle/LifecycleCoroutineScope.kt | 91 +++- .../LifecycleCoroutineScopeFactory.kt | 40 ++ .../lifecycle/ViewLifecycleCoroutineScope.kt | 76 ++++ .../LifecycleCoroutineScopeBinding.kt | 68 +++ ...ScopeExt.kt => lifecycleCoroutineScope.kt} | 27 +- .../internal/viewLifecycleCoroutineScope.kt | 64 +++ .../{LifecycleSuspendExt.kt => suspend.kt} | 49 ++- .../lifecycle/LifecycleCoroutineScopeTest.kt | 110 ++++- .../android/lifecycle/OnNextCreateTest.kt | 42 +- .../android/lifecycle/OnNextResumeTest.kt | 42 +- .../android/lifecycle/OnNextStartTest.kt | 42 +- .../ViewLifecycleScopeFlowCollectionTest.kt | 146 +++++++ .../lifecycle/WithViewLifecycleTest.kt | 263 +++++++++++ dispatch-android-viewmodel/README.md | 4 +- dispatch-android-viewmodel/build.gradle.kts | 1 + .../samples/build.gradle.kts | 1 + .../viewmodel/CoroutineViewModelTest.kt | 2 +- .../viewmodel/ViewModelScopeFactoryTest.kt | 4 +- dispatch-core/README.md | 68 ++- dispatch-core/api/dispatch-core.api | 31 +- dispatch-core/build.gradle.kts | 4 + dispatch-core/samples/build.gradle.kts | 1 + .../DefaultDispatcherProviderSample.kt | 61 +++ .../src/main/java/dispatch/core/Async.kt | 2 + .../java/dispatch/core/CoroutineScopeExt.kt | 28 +- .../java/dispatch/core/CoroutineScopes.kt | 34 +- .../core/DefaultDispatcherProvider.kt | 77 ++++ .../java/dispatch/core/DispatcherProvider.kt | 43 +- .../java/dispatch/core/CoroutineScopesTest.kt | 21 +- ...iderTest2.kt => DispatcherProviderTest.kt} | 36 +- dispatch-detekt/README.md | 2 +- dispatch-detekt/build.gradle.kts | 1 + dispatch-detekt/samples/build.gradle.kts | 1 + .../rules/AndroidxLifecycleScopeUsageTest.kt | 3 - .../api/dispatch-internal-test-android.api | 33 ++ .../build.gradle.kts | 51 +++ .../src/main/AndroidManifest.xml | 16 + .../internal/test/android/FakeFragment.java | 60 +++ .../internal/test/android/FakeLifecycle.kt | 55 +++ .../test/android}/FakeLifecycleOwner.kt | 30 +- .../test/resources/junit-platform.properties | 15 + dispatch-internal-test/build.gradle.kts | 2 + .../test/{Assertions.kt => assertions.kt} | 11 + .../java/dispatch/internal/test/reflect.kt | 45 ++ dispatch-sample/build.gradle.kts | 1 + .../main/java/dispatch/sample/MainFragment.kt | 22 + dispatch-test-junit4/README.md | 12 +- dispatch-test-junit4/build.gradle.kts | 1 + dispatch-test-junit4/samples/build.gradle.kts | 1 + dispatch-test-junit5/README.md | 12 +- dispatch-test-junit5/build.gradle.kts | 1 + dispatch-test-junit5/samples/build.gradle.kts | 1 + dispatch-test/README.md | 6 +- dispatch-test/api/dispatch-test.api | 4 + dispatch-test/build.gradle.kts | 1 + dispatch-test/samples/build.gradle.kts | 1 + .../DefaultDispatcherProviderSample.kt | 72 +++ .../test/defaultDispatcherProvider.kt | 30 ++ docs/CHANGELOG.md | 28 ++ docs/index.md | 12 +- .../-init-.md | 4 +- .../-idling-dispatcher-provider-rule/index.md | 4 +- .../-idling-dispatcher-provider.md | 4 +- .../dispatch.android.espresso/index.md | 2 +- docs/kdoc/dispatch-android-espresso/index.md | 4 +- .../alltypes/index.md | 5 + .../-lifecycle-scope-factory/index.md | 27 +- .../-lifecycle-scope-factory/reset.md | 7 +- .../-lifecycle-scope-factory/set.md | 14 +- .../androidx.fragment.app.-fragment/index.md | 7 + .../with-view-lifecycle-scope.md | 31 ++ .../lifecycle-scope.md | 5 +- .../dispatch.android.lifecycle/index.md | 1 + .../index.md | 12 +- .../package-list | 1 + .../alltypes/index.md | 22 +- .../-init-.md | 33 ++ .../create.md | 11 + .../index.md | 45 ++ .../-lifecycle-coroutine-scope/-init-.md | 54 ++- .../-minimum-state-policy/-c-a-n-c-e-l.md | 2 +- .../-r-e-s-t-a-r-t_-e-v-e-r-y.md | 2 +- .../-minimum-state-policy/index.md | 2 +- .../-lifecycle-coroutine-scope/index.md | 72 ++- .../-lifecycle-coroutine-scope/invoke.md | 55 +++ .../launch-on-create.md | 8 +- .../launch-on-resume.md | 8 +- .../launch-on-start.md | 8 +- .../-lifecycle-coroutine-scope/lifecycle.md | 2 +- .../-main-immediate-context.md | 12 + .../-view-lifecycle-coroutine-scope/index.md | 15 + .../launch-on-create.md | 12 + .../launch-on-resume.md | 12 + .../launch-on-start.md | 12 + .../index.md | 6 +- .../on-next-create.md | 10 +- .../on-next-resume.md | 10 +- .../on-next-start.md | 10 +- .../androidx.lifecycle.-lifecycle/index.md | 6 +- .../on-next-create.md | 10 +- .../on-next-resume.md | 10 +- .../on-next-start.md | 10 +- .../dispatch.android.lifecycle/index.md | 11 +- .../index.md | 7 + .../with-view-lifecycle.md | 27 ++ docs/kdoc/dispatch-android-lifecycle/index.md | 11 +- .../dispatch-android-lifecycle/package-list | 13 +- docs/kdoc/dispatch-android-viewmodel/index.md | 4 +- docs/kdoc/dispatch-core/alltypes/index.md | 3 +- .../dispatch.core/-default-coroutine-scope.md | 6 +- .../-default-dispatcher-provider/-init-.md | 11 - .../-default-dispatcher-provider/default.md | 14 - .../-default-dispatcher-provider/get.md | 12 + .../-default-dispatcher-provider/index.md | 30 +- .../-default-dispatcher-provider/io.md | 14 - .../main-immediate.md | 14 - .../-default-dispatcher-provider/main.md | 14 - .../-default-dispatcher-provider/set.md | 22 + .../unconfined.md | 14 - .../dispatch.core/-dispatcher-provider.md | 12 - .../-dispatcher-provider/-key.md | 8 - .../-dispatcher-provider/-key/index.md | 13 + .../-dispatcher-provider/-key/invoke.md | 15 + .../-dispatcher-provider/default.md | 2 +- .../-dispatcher-provider/index.md | 18 +- .../-dispatcher-provider/invoke.md | 15 + .../dispatch.core/-dispatcher-provider/io.md | 2 +- .../dispatch.core/-dispatcher-provider/key.md | 2 +- .../-dispatcher-provider/main-immediate.md | 2 +- .../-dispatcher-provider/main.md | 2 +- .../-dispatcher-provider/unconfined.md | 2 +- .../dispatch.core/-i-o-coroutine-scope.md | 6 +- .../dispatch.core/-main-coroutine-scope.md | 6 +- .../-main-immediate-coroutine-scope.md | 6 +- .../-unconfined-coroutine-scope.md | 6 +- .../kdoc/dispatch-core/dispatch.core/index.md | 13 +- .../dispatcher-provider.md | 4 +- .../index.md | 2 +- .../async-default.md | 2 +- .../async-i-o.md | 2 +- .../async-main-immediate.md | 2 +- .../async-main.md | 2 +- .../async-unconfined.md | 2 +- .../default-dispatcher.md | 8 +- .../dispatcher-provider.md | 8 +- .../index.md | 12 +- .../io-dispatcher.md | 8 +- .../main-dispatcher.md | 8 +- .../main-immediate-dispatcher.md | 8 +- .../unconfined-dispatcher.md | 8 +- docs/kdoc/dispatch-core/index.md | 57 ++- docs/kdoc/dispatch-detekt/index.md | 2 +- docs/kdoc/dispatch-test-junit4/index.md | 12 +- docs/kdoc/dispatch-test-junit5/index.md | 12 +- docs/kdoc/dispatch-test/alltypes/index.md | 5 + .../index.md | 7 + .../reset.md | 32 ++ .../kdoc/dispatch-test/dispatch.test/index.md | 6 + docs/kdoc/dispatch-test/index.md | 6 +- docs/kdoc/dispatch-test/package-list | 2 +- docs/modules/dispatch-android-espresso.md | 4 +- .../dispatch-android-lifecycle-extensions.md | 12 +- docs/modules/dispatch-android-lifecycle.md | 11 +- docs/modules/dispatch-android-viewmodel.md | 4 +- docs/modules/dispatch-core.md | 68 ++- docs/modules/dispatch-detekt.md | 2 +- docs/modules/dispatch-test-junit4.md | 12 +- docs/modules/dispatch-test-junit5.md | 12 +- docs/modules/dispatch-test.md | 6 +- settings.gradle.kts | 1 + site/mkdocs.yml | 20 +- 214 files changed, 4490 insertions(+), 928 deletions(-) create mode 100644 buildSrc/src/main/kotlin/DependencyGraph.kt rename dispatch-android-lifecycle-extensions/samples/src/test/java/samples/{LifecycleScopeFactorySample.kt => LifecycleCoroutineScopeFactorySample.kt} (73%) rename dispatch-android-lifecycle-extensions/samples/src/test/java/samples/{LifecycleCoroutineScopeSample.kt => LifecycleScopeExtensionSample.kt} (81%) create mode 100644 dispatch-android-lifecycle-extensions/samples/src/test/java/samples/WithLifecycleScopeSample.kt create mode 100644 dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/atomic.kt rename dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/{LifecycleScope.kt => lifecycleScope.kt} (87%) create mode 100644 dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/withViewLifecycleScope.kt create mode 100644 dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeExtensionTest.kt create mode 100644 dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt create mode 100644 dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/WithViewLifecycleScopeExtensionTest.kt create mode 100644 dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/internal/AtomicGetOrPutTest.kt delete mode 100644 dispatch-android-lifecycle/samples/src/test/java/samples/FakeLifecycleOwner.kt create mode 100644 dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt create mode 100644 dispatch-android-lifecycle/samples/src/test/java/samples/WithLifecycleScopeSample.kt create mode 100644 dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScopeFactory.kt create mode 100644 dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt create mode 100644 dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeBinding.kt rename dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/{LifecycleScopeExt.kt => lifecycleCoroutineScope.kt} (86%) create mode 100644 dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/viewLifecycleCoroutineScope.kt rename dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/{LifecycleSuspendExt.kt => suspend.kt} (54%) create mode 100644 dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt create mode 100644 dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/WithViewLifecycleTest.kt create mode 100644 dispatch-core/samples/test/samples/DefaultDispatcherProviderSample.kt create mode 100644 dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt rename dispatch-core/src/test/java/dispatch/core/{DispatcherProviderTest2.kt => DispatcherProviderTest.kt} (65%) create mode 100644 dispatch-internal-test-android/api/dispatch-internal-test-android.api create mode 100644 dispatch-internal-test-android/build.gradle.kts create mode 100644 dispatch-internal-test-android/src/main/AndroidManifest.xml create mode 100644 dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeFragment.java create mode 100644 dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycle.kt rename {dispatch-android-lifecycle-extensions/samples/src/test/java/samples => dispatch-internal-test-android/src/main/java/dispatch/internal/test/android}/FakeLifecycleOwner.kt (64%) create mode 100644 dispatch-internal-test-android/src/test/resources/junit-platform.properties rename dispatch-internal-test/src/main/java/dispatch/internal/test/{Assertions.kt => assertions.kt} (77%) create mode 100644 dispatch-internal-test/src/main/java/dispatch/internal/test/reflect.kt create mode 100644 dispatch-test/samples/test/samples/DefaultDispatcherProviderSample.kt create mode 100644 dispatch-test/src/main/java/dispatch/test/defaultDispatcherProvider.kt create mode 100644 docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/index.md create mode 100644 docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/with-view-lifecycle-scope.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/-init-.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/create.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/invoke.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-main-immediate-context.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/index.md create mode 100644 docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/with-view-lifecycle.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/-init-.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/default.md create mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/get.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/io.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main-immediate.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main.md create mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/set.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/unconfined.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider.md delete mode 100644 docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key.md create mode 100644 docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/index.md create mode 100644 docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/invoke.md create mode 100644 docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/invoke.md create mode 100644 docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/index.md create mode 100644 docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/reset.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc51871f1..9e7091940 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ on: branches: - dev - main + - release/* jobs: @@ -25,16 +26,5 @@ jobs: java-version: 1.8 - name: all tests run: ./gradlew test - - lint: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: lint - run: ./gradlew lint + - name: detekt + run: ./gradlew detekt diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index e6295f500..3e7a42c25 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -181,4 +181,4 @@ - \ No newline at end of file + diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index 79ee123c2..0f7bc519d 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e7b3bd97..f8613e6fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,37 @@ ## Version 1.0.0-beta04 +### Features +* [DefaultDispatcherProvider] is now a mutable singleton which allows for a custom global default. + ### Bug fixes +#### dispatch-test-junit5 * [CoroutineTestExtension] will now properly call `Dispatchers.setMain(...)` when injecting a CoroutineScope into a function or when not injecting at all. ([#130](https://github.com/RBusarow/Dispatch/issues/130)) +#### dispatch-android-lifecycle +* [LifecycleCoroutineScope] will now be automatically cancelled when the associated [Lifecycle][Android Lifecycle] drops to the [Destroyed][Android Lifecycle] state. + ([#135](https://github.com/RBusarow/Dispatch/issues/135)) + +#### dispatch-android-lifecycle-extensions +* Cached [LifecycleCoroutineScopes][LifecycleCoroutineScope] will now be removed from the cache when + they are destroyed. ([#136](https://github.com/RBusarow/Dispatch/issues/136)) +* Fixed a race condition where multiple [LifecycleCoroutineScopes][LifecycleCoroutineScope] may be + created for concurrent cache misses. ([#136](https://github.com/RBusarow/Dispatch/issues/136)) + +### Deprecations +* The [DefaultDispatcherProvider] class constructor has been changed to an object factory function + (`operator fun invoke(): DispatcherProvider`) and deprecated. This function will be removed prior + to the 1.0 release. + +### Breaking changes +* [DefaultDispatcherProvider] has been changed from a `class` to an `object`, and its functionality + changed. It is now a singleton holder for a default `DispatcherProvider` instance. To create a + default `DispatcherProvider`, use the interface's companion object factory function + (`DispatcherProvider()`). + ## Version 1.0.0-beta03 ### Renames @@ -52,6 +77,7 @@ +[DefaultDispatcherProvider]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/index.html [TestProvidedCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-test//dispatch.test/-test-provided-coroutine-scope/index.html @@ -64,6 +90,7 @@ +[LifecycleCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.html [lifecycleScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle-extensions//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.html @@ -72,6 +99,7 @@ [viewModelScope]: https://rbusarow.github.io/Dispatch/dispatch-android-viewmodel//dispatch.android.viewmodel/-coroutine-view-model/view-model-scope.html +[Android Lifecycle]: https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html [androidx-lifecycleScope]: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-runtime-ktx/src/main/java/androidx/lifecycle/Lifecycle.kt;l=44 [Detekt]: https://github.com/detekt/detekt [dispatch-android-espresso]: https://rbusarow.github.io/Dispatch/android-espresso//index.html diff --git a/README.md b/README.md index 57774b9b8..3adac5f26 100644 --- a/README.md +++ b/README.md @@ -361,8 +361,8 @@ dependencies { */ // core coroutines - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") // everything provides :core via "api", so you only need this if you have no other "implementation" dispatch artifacts implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") @@ -386,7 +386,7 @@ dependencies { */ // core coroutines-test - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") // you only need this if you don't have the -junit4 or -junit5 artifacts testImplementation("com.rickbusarow.dispatch:dispatch-test:1.0.0-beta04") @@ -480,9 +480,9 @@ limitations under the License. [LifecycleCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.html -[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.html -[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.html -[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.html +[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.html +[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.html +[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.html [onNextCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.html [onNextStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.html [onNextResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.html diff --git a/build.gradle.kts b/build.gradle.kts index b9a22bae0..cf0c8dc06 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,10 +15,9 @@ @file:Suppress("MagicNumber") -import io.gitlab.arturbosch.detekt.Detekt +import io.gitlab.arturbosch.detekt.* import kotlinx.knit.* import kotlinx.validation.* -import org.gradle.kotlin.dsl.* import org.jetbrains.dokka.gradle.* import org.jetbrains.kotlin.gradle.tasks.* import java.net.* @@ -49,6 +48,8 @@ plugins { id("io.gitlab.arturbosch.detekt") version Libs.Detekt.version } +apply(plugin = "base") + allprojects { repositories { @@ -214,12 +215,6 @@ fun linkModuleDocs( } } -val clean by tasks.registering { - doLast { - delete("build") - } -} - subprojects { tasks.withType() .configureEach { @@ -263,6 +258,54 @@ val copyRootFiles by tasks.registering { } } +detekt { + parallel = true + config = files("$rootDir/detekt/detekt-config.yml") + + val unique = "${rootProject.relativePath(projectDir)}/${project.name}" + + reports { + xml { + enabled = false + destination = file("$rootDir/build/detekt-reports/$unique-detekt.xml") + } + html { + enabled = true + destination = file("$rootDir/build/detekt-reports/$unique-detekt.html") + } + txt { + enabled = false + destination = file("$rootDir/build/detekt-reports/$unique-detekt.txt") + } + } +} + +dependencies { + detekt(Libs.Detekt.cli) + detektPlugins(project(path = ":dispatch-detekt")) +} + +apply(plugin = Plugins.binaryCompatilibity) + +extensions.configure { + + /** + * Packages that are excluded from public API dumps even if they + * contain public API. + */ + ignoredPackages = mutableSetOf("sample", "samples") + + /** + * Sub-projects that are excluded from API validation + */ + ignoredProjects = mutableSetOf( + "dispatch-internal-test", + "dispatch-internal-test-android", + "dispatch-sample", + "samples" + ) +} + apply(plugin = Plugins.knit) extensions.configure { @@ -280,93 +323,37 @@ tasks.getByName("knitPrepare") { dependsOn(subprojects.mapNotNull { it.tasks.findByName("dokka") }) } -subprojects { - - apply { - plugin("io.gitlab.arturbosch.detekt") - } - - detekt { - parallel = true - config = files("$rootDir/detekt/detekt-config.yml") - - val unique = "${rootProject.relativePath(projectDir)}/${project.name}" +val generateDependencyGraph by tasks.registering { - idea { - path = "$rootDir/.idea" - codeStyleScheme = "$rootDir/.idea/Project.xml" - inspectionsProfile = "$rootDir/.idea/Project-Default.xml" - report = "${project.projectDir}/reports/build/detekt-reports" - mask = "*.kt" - } - - reports { - xml { - enabled = false - destination = file("$rootDir/build/detekt-reports/$unique-detekt.xml") - } - html { - enabled = true - destination = file("$rootDir/build/detekt-reports/$unique-detekt.html") - } - txt { - enabled = false - destination = file("$rootDir/build/detekt-reports/$unique-detekt.txt") - } - } - } -} + description = "generate a visual dependency graph" + group = "refactor" -allprojects { - dependencies { - detekt(Libs.Detekt.cli) - detektPlugins(project(path = ":dispatch-detekt")) + doLast { + createDependencyGraph() } } -val analysisDir = file(projectDir) -val baselineFile = file("$rootDir/detekt/project-baseline.xml") -val configFile = file("$rootDir/detekt/detekt-config.yml") -val formatConfigFile = file("$rootDir/config/detekt/format.yml") -val statisticsConfigFile = file("$rootDir/config/detekt/statistics.yml") - -val kotlinFiles = "**/*.kt" -val kotlinScriptFiles = "**/*.kts" -val resourceFiles = "**/resources/**" -val buildFiles = "**/build/**" -val testFiles = "**/src/test/**" - -val detektAll by tasks.registering(Detekt::class) { +subprojects { - description = "Runs the whole project at once." - parallel = true - buildUponDefaultConfig = true - setSource(files(rootDir)) - config.setFrom(files(configFile)) - include(kotlinFiles, kotlinScriptFiles) - exclude(resourceFiles, buildFiles, testFiles) - reports { - xml.enabled = false - html.enabled = false - txt.enabled = false + // force update all transitive dependencies (prevents some library leaking an old version) + configurations.all { + resolutionStrategy { + force( + // androidx is currently leaking coroutines 1.1.1 everywhere + Libs.Kotlinx.Coroutines.core, + Libs.Kotlinx.Coroutines.test, + Libs.Kotlinx.Coroutines.android, + // prevent dependency libraries from leaking their own old version of this library + Libs.RickBusarow.Dispatch.core, + Libs.RickBusarow.Dispatch.detekt, + Libs.RickBusarow.Dispatch.espresso, + Libs.RickBusarow.Dispatch.lifecycle, + Libs.RickBusarow.Dispatch.lifecycleExtensions, + Libs.RickBusarow.Dispatch.viewModel, + Libs.RickBusarow.Dispatch.Test.core, + Libs.RickBusarow.Dispatch.Test.jUnit4, + Libs.RickBusarow.Dispatch.Test.jUnit5 + ) + } } } - -tasks.findByName("detekt") - ?.finalizedBy(detektAll) - -apply(plugin = Plugins.binaryCompatilibity) - -extensions.configure { - - /** - * Packages that are excluded from public API dumps even if they - * contain public API. - */ - ignoredPackages = mutableSetOf("sample", "samples") - - /** - * Sub-projects that are excluded from API validation - */ - ignoredProjects = mutableSetOf("dispatch-internal-test", "dispatch-sample", "samples") -} diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index fef89e144..bbb1be0a2 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -36,7 +36,7 @@ object Plugins { object Versions { const val ktlint = "0.35.0" const val dokka = "0.10.1" - const val knit = "0.1.1" + const val knit = "0.1.4" const val compileSdk = 29 const val minSdk = "21" @@ -61,7 +61,7 @@ object BuildPlugins { const val binaryCompatibility = "org.jetbrains.kotlinx:binary-compatibility-validator:${Versions.binaryCompatibility}" - const val atomicFu = "org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.14.1" + const val atomicFu = "org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.14.3" const val androidGradlePlugin = "com.android.tools.build:gradle:${Versions.gradleWrapper}" const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}" @@ -137,7 +137,7 @@ object Libs { } object Detekt { - const val version = "1.9.1" + const val version = "1.10.0" const val api = "io.gitlab.arturbosch.detekt:detekt-api:$version" const val cli = "io.gitlab.arturbosch.detekt:detekt-cli:$version" const val formatting = "io.gitlab.arturbosch.detekt:detekt-formatting:$version" @@ -160,6 +160,14 @@ object Libs { const val jUnit5Vintage = "org.junit.vintage:junit-vintage-engine:$version" } + object Kotest { + private const val version = "4.1.1" + const val assertions = "io.kotest:kotest-assertions-core-jvm:$version" + const val consoleRunner = "io.kotest:kotest-runner-console-jvm:$version" + const val properties = "io.kotest:kotest-property-jvm:$version" + const val runner = "io.kotest:kotest-runner-junit5-jvm:$version" + } + object Kotlin { const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${Versions.kotlin}" const val reflect = "org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlin}" @@ -168,18 +176,10 @@ object Libs { const val test = "org.jetbrains.kotlin:kotlin-test:${Versions.kotlin}" const val testCommon = "org.jetbrains.kotlin:kotlin-test-common:${Versions.kotlin}" } - - object Kotest { - private const val version = "4.0.5" - const val assertions = "io.kotest:kotest-assertions-core-jvm:$version" - const val properties = "io.kotest:kotest-property-jvm:$version" - const val runner = "io.kotest:kotest-runner-junit5-jvm:$version" - } - object Kotlinx { object Coroutines { - private const val version = "1.3.7" + private const val version = "1.3.8" const val core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version" const val android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version" const val test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:$version" @@ -218,6 +218,15 @@ object Libs { } } + + object Hermit { + private const val version = "0.9.2" + const val core = "com.rickbusarow.hermit:hermit-core:$version" + const val junit4 = "com.rickbusarow.hermit:hermit-junit4:$version" + const val junit5 = "com.rickbusarow.hermit:hermit-junit5:$version" + const val mockk = "com.rickbusarow.hermit:hermit-mockk:$version" + const val coroutines = "com.rickbusarow.hermit:hermit-coroutines:$version" + } } object Robolectric { diff --git a/buildSrc/src/main/kotlin/DependencyGraph.kt b/buildSrc/src/main/kotlin/DependencyGraph.kt new file mode 100644 index 000000000..96c877adb --- /dev/null +++ b/buildSrc/src/main/kotlin/DependencyGraph.kt @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.codehaus.groovy.runtime.DefaultGroovyMethods.execute +import org.gradle.api.* +import org.gradle.api.artifacts.* +import java.io.* +import java.util.* +import kotlin.collections.LinkedHashMap +import kotlin.collections.LinkedHashSet +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set +import kotlin.io.println + +@Suppress("TooGenericExceptionThrown", "NestedBlockDepth", "ComplexMethod", "LongMethod") +fun Project.createDependencyGraph() { + + val dot = File(buildDir, "reports/dependency-graph/project.dot") + + dot.parentFile.mkdirs() + + dot.delete() + + var dotText = """ + digraph { + graph [label="${name}",labelloc=t,fontsize=30,ranksep=1.4]; + node [style=filled, fillcolor="#bbbbbb"]; + rankdir=TB; + + """.trimIndent() + + val rootProjects = mutableListOf() + var queue = mutableListOf(rootProject) + + while (queue.isNotEmpty()) { + val project = queue.removeAt(0) + + rootProjects.add(project) + queue.addAll(project.childProjects.values) + } + + val projects = LinkedHashSet() + val dependencies = LinkedHashMap, List>() + + val multiPlatformProjects = mutableListOf() + val jsProjects = mutableListOf() + val androidProjects = mutableListOf() + val javaProjects = mutableListOf() + + queue = mutableListOf(rootProject) + + while (queue.isNotEmpty()) { + + val project = queue.removeAt(0) + queue.addAll(project.childProjects.values) + + if (project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")) { + multiPlatformProjects.add(project) + } + if (project.plugins.hasPlugin("org.jetbrains.kotlin.js")) { + jsProjects.add(project) + } + if (project.plugins.hasPlugin("com.android.library") || project.plugins.hasPlugin("com.android.application")) { + androidProjects.add(project) + } + if (project.plugins.hasPlugin("java-library") || project.plugins.hasPlugin("java")) { + javaProjects.add(project) + } + + project.configurations.forEach { config -> + + config.dependencies + .withType(ProjectDependency::class.java) + .map { it.dependencyProject } + .forEach { dependency -> + projects.add(project) + projects.add(dependency) + rootProjects.remove(dependency) + + val graphKey = project to dependency + val traits = dependencies.computeIfAbsent(graphKey) { listOf() } + .toMutableList() + + if (config.name.toLowerCase(Locale.getDefault()) + .endsWith("implementation") + ) { + traits.add("style=dotted") + } + + dependencies[graphKey] = traits + } + + } + + } + + val sortedProjects = projects.sortedBy { it.path } + + + dotText += "\n # Projects\n\n" + + sortedProjects.forEach { project -> + + val traits = mutableListOf() + + if (rootProjects.contains(project)) { + traits.add("shape=box") + } + + val color = when { + multiPlatformProjects.contains(project) -> "#ffd2b3" + jsProjects.contains(project) -> "#ffffba" + androidProjects.contains(project) -> "#baffc9" + javaProjects.contains(project) -> "#ffb3ba" + else -> "#eeeeee" + } + + traits.add("fillcolor=\"$color\"") + + dotText += " \"${project.path}\" [${traits.joinToString(", ")}];\n" + } + + dotText += "\n {rank = same;" + + sortedProjects.forEach { project -> + + if (rootProjects.contains(project)) { + dotText += " \"${project.path}\";" + } + } + + dotText += "}\n" + + dotText += "\n # Dependencies\n\n" + + dependencies.forEach { (key, traits) -> + + dotText += " \"${key.first.path}\" -> \"${key.second.path}\"" + + if (traits.isNotEmpty()) { + dotText += " [${traits.joinToString(", ")}]" + } + dotText += "\n" + } + + dotText += "}\n" + + dot.writeText(dotText) + + @Suppress("DEPRECATION") + val process = execute("dot -Tpng -O project.dot", arrayOf(""), dot.parentFile) + process.waitFor() + if (process.exitValue() != 0) { + throw RuntimeException(process.errorStream.toString()) + } + + println("file at ${File("$dot.png")}") +} diff --git a/buildSrc/src/main/kotlin/DocsTasks.kt b/buildSrc/src/main/kotlin/DocsTasks.kt index 837c7a46a..647ec44c6 100644 --- a/buildSrc/src/main/kotlin/DocsTasks.kt +++ b/buildSrc/src/main/kotlin/DocsTasks.kt @@ -143,6 +143,10 @@ fun File.updateLibraryVersions(): File { Libs.AndroidX.Lifecycle.viewModel.toDependencyMatcher(), Libs.AndroidX.Test.runner.toDependencyMatcher(), Libs.AndroidX.Test.Espresso.core.toDependencyMatcher(), + Libs.Detekt.api.toDependencyMatcher(), + Libs.Detekt.cli.toDependencyMatcher(), + Libs.Detekt.formatting.toDependencyMatcher(), + Libs.Detekt.test.toDependencyMatcher(), Libs.JUnit.jUnit4.toDependencyMatcher(), Libs.JUnit.jUnit5Vintage.toDependencyMatcher(), Libs.JUnit.jUnit5Runtime.toDependencyMatcher(), @@ -155,21 +159,31 @@ fun File.updateLibraryVersions(): File { Libs.RickBusarow.Dispatch.detekt.toDependencyMatcher(), Libs.RickBusarow.Dispatch.espresso.toDependencyMatcher(), Libs.RickBusarow.Dispatch.extensions.toDependencyMatcher(), - Libs.RickBusarow.Dispatch.lifecycleExtensions.toDependencyMatcher(), Libs.RickBusarow.Dispatch.lifecycle.toDependencyMatcher(), + Libs.RickBusarow.Dispatch.lifecycleExtensions.toDependencyMatcher(), Libs.RickBusarow.Dispatch.viewModel.toDependencyMatcher(), + Libs.RickBusarow.Dispatch.Test.core.toDependencyMatcher(), Libs.RickBusarow.Dispatch.Test.jUnit4.toDependencyMatcher(), Libs.RickBusarow.Dispatch.Test.jUnit5.toDependencyMatcher(), - Libs.RickBusarow.Dispatch.Test.core.toDependencyMatcher(), - Libs.RickBusarow.Dispatch.core.toDependencyMatcher() + Libs.RickBusarow.Dispatch.core.toDependencyMatcher(), + Libs.RickBusarow.Hermit.core.toDependencyMatcher(), + Libs.RickBusarow.Hermit.junit4.toDependencyMatcher(), + Libs.RickBusarow.Hermit.junit5.toDependencyMatcher(), + Libs.RickBusarow.Hermit.mockk.toDependencyMatcher(), + Libs.RickBusarow.Hermit.coroutines.toDependencyMatcher(), + Libs.Kotest.assertions.toDependencyMatcher(), + Libs.Kotest.consoleRunner.toDependencyMatcher(), + Libs.Kotest.properties.toDependencyMatcher(), + Libs.Kotest.runner.toDependencyMatcher() ) + forEachLine { originalLine -> val newLine = dependencyMatchers.firstOrNull { matcher -> - matcher.regex.matches(originalLine) - } + matcher.regex.matches(originalLine) + } ?.let { matcher -> originalLine.replace(matcher) @@ -209,5 +223,5 @@ private fun String.replace( } private fun String.removeVersionSuffix(): String = split(":").subList(0, 2) - .joinToString(":") + .joinToString(":") + ":" diff --git a/buildSrc/src/main/kotlin/Modules.kt b/buildSrc/src/main/kotlin/Modules.kt index 3f95974fc..6609d369a 100644 --- a/buildSrc/src/main/kotlin/Modules.kt +++ b/buildSrc/src/main/kotlin/Modules.kt @@ -31,14 +31,15 @@ object Modules { ":dispatch-core:samples", ":dispatch-detekt", ":dispatch-internal-test", + ":dispatch-internal-test-android", ":dispatch-sample", - "dispatch-test", - "dispatch-test-junit4", - "dispatch-test-junit4:samples", - "dispatch-test-junit5", - "dispatch-test-junit5:samples", - "dispatch-test:samples", - "dispatch-test:samples" + ":dispatch-test", + ":dispatch-test-junit4", + ":dispatch-test-junit4:samples", + ":dispatch-test-junit5", + ":dispatch-test-junit5:samples", + ":dispatch-test:samples", + ":dispatch-test:samples" ) val allInternalPaths = allPaths.filter { it.matches(internalRegex) } val allProductionPaths = allPaths.filter { !it.matches(internalRegex, sampleRegex) } diff --git a/dispatch-android-espresso/README.md b/dispatch-android-espresso/README.md index 6b76c5f55..140cf6f59 100644 --- a/dispatch-android-espresso/README.md +++ b/dispatch-android-espresso/README.md @@ -88,8 +88,8 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") androidTestImplementation("com.rickbusarow.dispatch:dispatch-android-espresso:1.0.0-beta04") diff --git a/dispatch-android-espresso/build.gradle.kts b/dispatch-android-espresso/build.gradle.kts index 5f656bbb1..f5624c09d 100644 --- a/dispatch-android-espresso/build.gradle.kts +++ b/dispatch-android-espresso/build.gradle.kts @@ -54,6 +54,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit4) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.runner) testImplementation(Libs.MockK.core) testImplementation(Libs.Robolectric.core) diff --git a/dispatch-android-espresso/samples/build.gradle.kts b/dispatch-android-espresso/samples/build.gradle.kts index d687f86d9..067109985 100644 --- a/dispatch-android-espresso/samples/build.gradle.kts +++ b/dispatch-android-espresso/samples/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit4) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-android-espresso/samples/src/test/java/samples/IdlingCoroutineScopeRuleWithLifecycleSample.kt b/dispatch-android-espresso/samples/src/test/java/samples/IdlingCoroutineScopeRuleWithLifecycleSample.kt index a3587ab13..7f9b983b9 100644 --- a/dispatch-android-espresso/samples/src/test/java/samples/IdlingCoroutineScopeRuleWithLifecycleSample.kt +++ b/dispatch-android-espresso/samples/src/test/java/samples/IdlingCoroutineScopeRuleWithLifecycleSample.kt @@ -39,9 +39,7 @@ class IdlingCoroutineScopeRuleWithLifecycleSample { @Before fun setUp() { - LifecycleScopeFactory.set { - MainImmediateCoroutineScope(customDispatcherProvider) - } + LifecycleScopeFactory.set { customDispatcherProvider } ViewModelScopeFactory.set { MainImmediateCoroutineScope(customDispatcherProvider) } diff --git a/dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcherProvider.kt b/dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcherProvider.kt index f8c785973..379db14ff 100644 --- a/dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcherProvider.kt +++ b/dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcherProvider.kt @@ -61,7 +61,7 @@ class IdlingDispatcherProvider( * * @param delegate *optional* Use this [DispatcherProvider] to create a single [IdlingDispatcher] * which is used as all properties for the [IdlingDispatcherProvider]. - * Uses a [DefaultDispatcherProvider] if no instance provided. + * Uses [DefaultDispatcherProvider.get] if no instance provided. * * @see IdlingResource * @see DispatcherProvider @@ -69,7 +69,7 @@ class IdlingDispatcherProvider( * @see CoroutineDispatcher */ fun IdlingDispatcherProvider( - delegate: DispatcherProvider = DefaultDispatcherProvider() + delegate: DispatcherProvider = DefaultDispatcherProvider.get() ): IdlingDispatcherProvider = IdlingDispatcherProvider( default = IdlingDispatcher(delegate.default), io = IdlingDispatcher(delegate.io), diff --git a/dispatch-android-lifecycle-extensions/README.md b/dispatch-android-lifecycle-extensions/README.md index 3a7ad72fd..9c1e6faee 100644 --- a/dispatch-android-lifecycle-extensions/README.md +++ b/dispatch-android-lifecycle-extensions/README.md @@ -51,7 +51,7 @@ class SomeApplication : Application() { override fun onCreate() { super.onCreate() // A custom factory can be set to add elements to the CoroutineContext - LifecycleScopeFactory.set { MainImmediateCoroutineScope() + SomeCustomElement() } + LifecycleScopeFactory.set { MainImmediateContext() + SomeCustomElement() } } } ``` @@ -62,7 +62,7 @@ class SomeEspressoTest { fun setUp() { // This custom factory can be used to use custom scopes for testing, // such as an idling dispatcher - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope().coroutineContext } } @After @@ -93,7 +93,7 @@ class SomeFragmentEspressoTest { fun setUp() { // set a custom factory which is applied to all newly created lifecycleScopes LifecycleScopeFactory.set { - MainImmediateCoroutineScope() + idlingRule.dispatcherProvider + MainImmediateContext() + idlingRule.dispatcherProvider } // now SomeFragment will use an IdlingDispatcher in its CoroutineScope @@ -139,10 +139,10 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-lifecycle-extensions:1.0.0-beta04") - + implementation("androidx.lifecycle:lifecycle-common:2.2.0") } ``` diff --git a/dispatch-android-lifecycle-extensions/api/dispatch-android-lifecycle-extensions.api b/dispatch-android-lifecycle-extensions/api/dispatch-android-lifecycle-extensions.api index e3d8b4c1b..8ca84bad6 100644 --- a/dispatch-android-lifecycle-extensions/api/dispatch-android-lifecycle-extensions.api +++ b/dispatch-android-lifecycle-extensions/api/dispatch-android-lifecycle-extensions.api @@ -1,6 +1,7 @@ public final class dispatch/android/lifecycle/LifecycleScopeFactory { public static final field INSTANCE Ldispatch/android/lifecycle/LifecycleScopeFactory; public final fun reset ()V + public final fun set (Ldispatch/android/lifecycle/LifecycleCoroutineScopeFactory;)V public final fun set (Lkotlin/jvm/functions/Function0;)V } @@ -8,6 +9,10 @@ public final class dispatch/android/lifecycle/LifecycleScopeKt { public static final fun getLifecycleScope (Landroidx/lifecycle/LifecycleOwner;)Ldispatch/android/lifecycle/LifecycleCoroutineScope; } +public final class dispatch/android/lifecycle/WithViewLifecycleScopeKt { + public static final fun withViewLifecycleScope (Landroidx/fragment/app/Fragment;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job; +} + public final class dispatch/android/lifecycle/extensions/BuildConfig { public static final field BUILD_TYPE Ljava/lang/String; public static final field DEBUG Z diff --git a/dispatch-android-lifecycle-extensions/build.gradle.kts b/dispatch-android-lifecycle-extensions/build.gradle.kts index 531c641b2..5d9b4ab4c 100644 --- a/dispatch-android-lifecycle-extensions/build.gradle.kts +++ b/dispatch-android-lifecycle-extensions/build.gradle.kts @@ -45,11 +45,10 @@ android { dependencies { + implementation(Libs.AndroidX.Fragment.core) implementation(Libs.AndroidX.Lifecycle.common) testImplementation(Libs.AndroidX.Lifecycle.runtime) - implementation(Libs.JakeWharton.timber) - implementation(Libs.Kotlin.stdlib) implementation(Libs.Kotlinx.Coroutines.android) @@ -57,15 +56,22 @@ dependencies { api(project(":dispatch-android-lifecycle")) api(project(":dispatch-core")) + testImplementation(project(":dispatch-test-junit4")) testImplementation(project(":dispatch-test-junit5")) testImplementation(project(":dispatch-internal-test")) + testImplementation(project(":dispatch-internal-test-android")) testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) testImplementation(Libs.Kotlinx.Coroutines.test) testImplementation(Libs.AndroidX.Test.runner) testImplementation(Libs.AndroidX.Test.Espresso.core) + testImplementation(Libs.AndroidX.Test.Arch.core) + testImplementation(Libs.Robolectric.core) + + testImplementation(Libs.RickBusarow.Hermit.junit5) } diff --git a/dispatch-android-lifecycle-extensions/samples/build.gradle.kts b/dispatch-android-lifecycle-extensions/samples/build.gradle.kts index d11c31e30..f1cf17c9d 100644 --- a/dispatch-android-lifecycle-extensions/samples/build.gradle.kts +++ b/dispatch-android-lifecycle-extensions/samples/build.gradle.kts @@ -40,6 +40,7 @@ android { dependencies { + implementation(Libs.AndroidX.Fragment.ktx) implementation(Libs.AndroidX.Lifecycle.common) implementation(Libs.AndroidX.Lifecycle.liveData) testImplementation(Libs.AndroidX.Lifecycle.runtime) @@ -52,10 +53,12 @@ dependencies { implementation(project(":dispatch-android-lifecycle")) implementation(project(":dispatch-android-lifecycle-extensions")) implementation(project(":dispatch-core")) + implementation(project(":dispatch-internal-test-android")) implementation(project(":dispatch-test")) implementation(project(":dispatch-test-junit5")) testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) @@ -64,4 +67,9 @@ dependencies { testImplementation(Libs.Kotlinx.Coroutines.test) + testImplementation(Libs.AndroidX.Test.Arch.core) + testImplementation(Libs.AndroidX.Test.runner) + testImplementation(Libs.AndroidX.Test.Espresso.core) + testImplementation(Libs.Robolectric.core) + } diff --git a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/Fragment.kt b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/Fragment.kt index d971bd474..3f73d824a 100644 --- a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/Fragment.kt +++ b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/Fragment.kt @@ -17,6 +17,7 @@ package samples import androidx.lifecycle.* +import dispatch.internal.test.android.* abstract class Fragment( initialState: Lifecycle.State = Lifecycle.State.INITIALIZED diff --git a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleScopeFactorySample.kt b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt similarity index 73% rename from dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleScopeFactorySample.kt rename to dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt index a76259164..ccbf469ba 100644 --- a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleScopeFactorySample.kt +++ b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt @@ -20,6 +20,7 @@ package samples import dispatch.android.espresso.* import dispatch.android.lifecycle.* import dispatch.core.* +import kotlinx.coroutines.* class LifecycleScopeFactorySample { @@ -29,7 +30,8 @@ class LifecycleScopeFactorySample { class MyApplication : Application { override fun onCreate() { - LifecycleScopeFactory.set { MainImmediateCoroutineScope() } + + LifecycleScopeFactory.set { MyCustomElement() + MainImmediateContext() } } } } @@ -41,19 +43,25 @@ class LifecycleScopeFactorySample { @Before fun setUp() { - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + + val dispatcherProvider = IdlingDispatcherProvider() + + LifecycleScopeFactory.set { SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate } } } } @Sample - fun lifecycleScopeFactoryResetSample() { + fun LifecycleScopeFactoryResetSample() { class MyEspressoTest { @Before fun setUp() { - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + + val dispatcherProvider = DispatcherProvider() + + LifecycleScopeFactory.set { SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate } } @After diff --git a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleScopeExtensionSample.kt similarity index 81% rename from dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt rename to dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleScopeExtensionSample.kt index 0761c8f54..2dde633e3 100644 --- a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt +++ b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/LifecycleScopeExtensionSample.kt @@ -17,24 +17,11 @@ package samples import dispatch.android.lifecycle.* import dispatch.core.* -import dispatch.test.* -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -@CoroutineTest -@ExperimentalCoroutinesApi -class LifecycleCoroutineScopeSample( - val testScope: TestProvidedCoroutineScope -) { - - @BeforeEach - fun beforeEach() { - - LifecycleScopeFactory.set { testScope } - } +class LifecycleScopeExtensionSample { @Sample - fun lifecycleCoroutineScopeSample() { + fun lifecycleScopeExtensionSample() { // This could be any LifecycleOwner -- Fragments, Activities, Services... class SomeFragment : Fragment() { diff --git a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/WithLifecycleScopeSample.kt b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/WithLifecycleScopeSample.kt new file mode 100644 index 000000000..2ef36f44b --- /dev/null +++ b/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/WithLifecycleScopeSample.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "UNUSED_ANONYMOUS_PARAMETER") + +package samples + +import androidx.fragment.app.Fragment +import dispatch.android.lifecycle.* +import kotlinx.coroutines.flow.* +import org.junit.* +import org.junit.runner.* +import org.robolectric.* +import org.robolectric.annotation.* + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +class WithViewLifecycleScopeExtensionSample { + + @Test + fun withViewLifecycleScopeSample() { + + class MyViewModel { + + val dataFlow = flow { + // ... + } + } + + class MyFragment : Fragment() { + + val myViewModel = MyViewModel() + + val observerJob = withViewLifecycleScope { + myViewModel.dataFlow.onEach { data -> + // ... + }.launchOnCreate() + } + } + } +} + +interface Data diff --git a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt index 98b920bdc..e7b2f3555 100644 --- a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt +++ b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt @@ -15,47 +15,87 @@ package dispatch.android.lifecycle +import androidx.lifecycle.* import dispatch.android.lifecycle.LifecycleScopeFactory.reset import dispatch.core.* +import kotlinx.coroutines.* +import kotlin.coroutines.* /** * Factory holder for [LifecycleCoroutineScope]'s. * - * By default, `create` returns a [MainImmediateCoroutineScope]. + * By default, `create` returns a [MainImmediateContext]. * * This factory can be overridden for testing or to include a custom [CoroutineContext][kotlin.coroutines.CoroutineContext] - * in production code. This may be done in [Application.onCreate][android.app.Application.onCreate] + * in production code. This may be done in [Application.onCreate][android.app.Application.onCreate], + * or else as early as possible in the Application's existence. + * + * A custom factory will persist for the application's full lifecycle unless overwritten or [reset]. * * [reset] may be used to reset the factory to default at any time. + * + * @see MainImmediateContext + * @see LifecycleCoroutineScope + * @see LifecycleCoroutineScopeFactory * @sample samples.LifecycleScopeFactorySample.setLifecycleScopeFactoryProductionSample * @sample samples.LifecycleScopeFactorySample.setLifecycleScopeFactoryEspressoSample */ -public object LifecycleScopeFactory { +object LifecycleScopeFactory { + + private val defaultFactory: LifecycleCoroutineScopeFactory + get() = LifecycleCoroutineScopeFactory { MainImmediateContext() } - private var _factory: () -> MainImmediateCoroutineScope = { MainImmediateCoroutineScope() } + private var factoryInstance = defaultFactory + + internal fun create(lifecycle: Lifecycle): LifecycleCoroutineScope = + factoryInstance.create(lifecycle) + + /** + * Immediately resets the factory function to its default. + * + * @sample samples.LifecycleScopeFactorySample.LifecycleScopeFactoryResetSample + */ + @Suppress("UNUSED") + public fun reset() { + factoryInstance = defaultFactory + } /** * Override the default [MainImmediateCoroutineScope] factory, for testing or to include a custom [CoroutineContext][kotlin.coroutines.CoroutineContext] * in production code. This may be done in [Application.onCreate][android.app.Application.onCreate] * - * @param factory sets a custom [MainImmediateCoroutineScope] factory to be used for all new instance creations until reset. + * @param factory sets a custom [CoroutineContext] factory to be used for all new instance creations until reset. + * Its [Elements][CoroutineContext.Element] will be re-used, except: + * 1. If a [DispatcherProvider] element isn't present, [DefaultDispatcherProvider.get] will be added. + * 2. If a [Job] element isn't present, a [SupervisorJob] will be added. + * 3. If the [ContinuationInterceptor][kotlin.coroutines.ContinuationInterceptor] does not match + * the one referenced by the [possibly new] [DispatcherProvider.mainImmediate] property, it will be updated to match. * * @sample samples.LifecycleScopeFactorySample.setLifecycleScopeFactoryProductionSample * @sample samples.LifecycleScopeFactorySample.setLifecycleScopeFactoryEspressoSample */ - public fun set(factory: () -> MainImmediateCoroutineScope) { - _factory = factory + @Suppress("UNUSED") + public fun set(factory: LifecycleCoroutineScopeFactory) { + factoryInstance = factory } - internal fun create() = _factory.invoke() - /** - * Immediately resets the factory function to its default. + * Override the default [MainImmediateCoroutineScope] factory, for testing or to include a custom [CoroutineContext][kotlin.coroutines.CoroutineContext] + * in production code. This may be done in [Application.onCreate][android.app.Application.onCreate] * - * @sample samples.LifecycleScopeFactorySample.lifecycleScopeFactoryResetSample + * @param factory sets a custom [CoroutineContext] factory to be used for all new instance creations until reset. + * Its [Elements][CoroutineContext.Element] will be re-used, except: + * 1. If a [DispatcherProvider] element isn't present, [DefaultDispatcherProvider.get] will be added. + * 2. If a [Job] element isn't present, a [SupervisorJob] will be added. + * 3. If the [ContinuationInterceptor][kotlin.coroutines.ContinuationInterceptor] does not match + * the one referenced by the [possibly new] [DispatcherProvider.mainImmediate] property, it will be updated to match. + * + * @sample samples.LifecycleScopeFactorySample.setLifecycleScopeFactoryProductionSample + * @sample samples.LifecycleScopeFactorySample.setLifecycleScopeFactoryEspressoSample */ - public fun reset() { - _factory = { MainImmediateCoroutineScope() } + @Suppress("UNUSED") + public fun set(factory: () -> CoroutineContext) { + factoryInstance = LifecycleCoroutineScopeFactory(factory) } } diff --git a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeStore.kt b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeStore.kt index 7f7f04e68..ec5f6d1d4 100644 --- a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeStore.kt +++ b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeStore.kt @@ -19,57 +19,57 @@ import android.os.* import androidx.lifecycle.* import dispatch.android.lifecycle.* import dispatch.core.* -import kotlinx.coroutines.* -import java.util.* import java.util.concurrent.* -import kotlin.collections.set -internal object LifecycleCoroutineScopeStore { +@Suppress("MagicNumber") +internal object LifecycleCoroutineScopeStore : LifecycleEventObserver { // ConcurrentHashMap can miss "put___" operations on API 21/22 https://issuetracker.google.com/issues/37042460 - @Suppress("MagicNumber") - private val map = if (Build.VERSION.SDK_INT < 23) { - Collections.synchronizedMap(mutableMapOf()) - } else { - ConcurrentHashMap() - } - - fun get(lifecycle: Lifecycle): LifecycleCoroutineScope { + private val map: MutableMap = + if (Build.VERSION.SDK_INT < 23) { + mutableMapOf() + } else { + ConcurrentHashMap() + } - return map[lifecycle] ?: bindLifecycle(lifecycle, LifecycleScopeFactory.create()) + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + if (source.lifecycle.currentState <= Lifecycle.State.DESTROYED) { + map.remove(source.lifecycle) + } } - private fun bindLifecycle( - lifecycle: Lifecycle, coroutineScope: MainImmediateCoroutineScope - ): LifecycleCoroutineScope { - - val scope = LifecycleCoroutineScope(lifecycle, coroutineScope) - - map[lifecycle] = scope + fun get(lifecycle: Lifecycle): LifecycleCoroutineScope { - if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { - scope.coroutineContext.cancel() - return scope + if (lifecycle.currentState <= Lifecycle.State.DESTROYED) { + return LifecycleScopeFactory.create(lifecycle) } - val observer = object : LifecycleEventObserver { - - override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { - - if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { - - scope.coroutineContext.cancel() - lifecycle.removeObserver(this) + return when { + Build.VERSION.SDK_INT >= 24 -> { + map.computeIfAbsent(lifecycle) { bindLifecycle(lifecycle) } + } + Build.VERSION.SDK_INT == 23 -> { + /* + `getOrPut` by itself isn't atomic. It is guaranteed to only ever return one instance + for a given key, but the lambda argument may be invoked unnecessarily. + */ + (map as ConcurrentMap).atomicGetOrPut(lifecycle) { bindLifecycle(lifecycle) } + } + else -> { + synchronized(map) { + map.getOrPut(lifecycle) { bindLifecycle(lifecycle) } } } } + } - scope.launchMainImmediate { + private fun bindLifecycle(lifecycle: Lifecycle): LifecycleCoroutineScope { + + val scope = LifecycleScopeFactory.create(lifecycle) - if (lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { - lifecycle.addObserver(observer) - } else { - scope.coroutineContext.cancel() + scope.launchMainImmediate { + if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) { + lifecycle.addObserver(this@LifecycleCoroutineScopeStore) } } @@ -77,4 +77,3 @@ internal object LifecycleCoroutineScopeStore { } } - diff --git a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/atomic.kt b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/atomic.kt new file mode 100644 index 000000000..ce3b9aa08 --- /dev/null +++ b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/atomic.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle.internal + +import androidx.lifecycle.* +import dispatch.android.lifecycle.* +import dispatch.core.* +import kotlinx.coroutines.* +import java.util.concurrent.* + +/** + * Normal [getOrPut] is guaranteed to only return a single instance for a given key, + * but the [defaultValue] lambda may be invoked unnecessarily. This would create a new instance + * of [LifecycleCoroutineScope] without actually returning it. + * + * This extra [LifecycleCoroutineScope] would still be active and observing the [lifecycle][key]. + * + * This function compares the result of the lambda to the result of [getOrPut], + * and cancels the lambda's result if it's different. + * + * @see getOrPut + */ +internal inline fun ConcurrentMap.atomicGetOrPut( + key: Lifecycle, + defaultValue: () -> LifecycleCoroutineScope +): LifecycleCoroutineScope { + + var newInstance: LifecycleCoroutineScope? = null + + val existingOrNew = getOrPut(key) { + newInstance = defaultValue.invoke() + newInstance!! + } + + // If the second value is different, that means the first was never inserted into the map. + // Cancel the observer for `newInstance` and cancel the coroutineContext. + newInstance?.let { new -> + if (new != existingOrNew) { + existingOrNew.launchMainImmediate { + + new.coroutineContext[Job]?.cancel() + } + } + } + + return existingOrNew +} diff --git a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScope.kt b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/lifecycleScope.kt similarity index 87% rename from dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScope.kt rename to dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/lifecycleScope.kt index 208a1377b..cbd5e284f 100644 --- a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScope.kt +++ b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/lifecycleScope.kt @@ -28,9 +28,10 @@ import kotlinx.coroutines.* * * The type of [CoroutineScope] created is configurable via [LifecycleScopeFactory.set]. * - * The `viewModelScope` is automatically cancelled when the [LifecycleOwner]'s [lifecycle][LifecycleOwner.getLifecycle]'s [Lifecycle.State] drops to [Lifecycle.State.DESTROYED]. + * The `viewModelScope` is automatically cancelled when the [LifecycleOwner]'s + * [lifecycle][LifecycleOwner.getLifecycle]'s [Lifecycle.State] drops to [Lifecycle.State.DESTROYED]. * - * @sample samples.LifecycleCoroutineScopeSample.lifecycleCoroutineScopeSample + * @sample samples.LifecycleScopeExtensionSample.lifecycleScopeExtensionSample */ val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope get() = LifecycleCoroutineScopeStore.get(this.lifecycle) diff --git a/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/withViewLifecycleScope.kt b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/withViewLifecycleScope.kt new file mode 100644 index 000000000..3945e8af3 --- /dev/null +++ b/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/withViewLifecycleScope.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.fragment.app.* +import kotlinx.coroutines.* + +/** + * [CoroutineScope] helper for a [Fragment]'s [ViewLifecycleOwner][FragmentViewLifecycleOwner]. + * + * This function observes a `Fragment`'s [viewLifecycleOwnerLiveData][androidx.fragment.app.Fragment.getViewLifecycleOwnerLiveData], + * and invokes [block]. + * + * @sample samples.WithViewLifecycleScopeExtensionSample.withViewLifecycleScopeSample + */ +@ExperimentalCoroutinesApi +fun Fragment.withViewLifecycleScope( + block: ViewLifecycleCoroutineScope.() -> Unit +): Job = lifecycleScope.withViewLifecycle(this, block) diff --git a/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeExtensionTest.kt b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeExtensionTest.kt new file mode 100644 index 000000000..5fcfa3678 --- /dev/null +++ b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeExtensionTest.kt @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.lifecycle.* +import dispatch.android.lifecycle.internal.* +import dispatch.internal.test.* +import dispatch.internal.test.android.* +import dispatch.test.* +import hermit.test.* +import hermit.test.junit.* +import io.kotest.matchers.* +import kotlinx.coroutines.* +import kotlinx.coroutines.test.* +import org.junit.jupiter.api.* +import java.util.concurrent.* + +@ObsoleteCoroutinesApi +@ExperimentalCoroutinesApi +internal class LifecycleScopeExtensionTest : HermitJUnit5() { + + val storeMap: MutableMap = + LifecycleCoroutineScopeStore.getPrivateObjectFieldByName("map") + + @BeforeEach + fun beforeEach() { + + val dispatcher = TestCoroutineDispatcher() + + LifecycleScopeFactory.set { dispatcher + TestDispatcherProvider(dispatcher) + Job() } + } + + @AfterEach + fun afterEach() { + LifecycleScopeFactory.reset() + storeMap.clear() + } + + @Nested + inner class `lifecycle is already destroyed` { + + val lifecycleOwner by resets { FakeLifecycleOwner(initialState = Lifecycle.State.DESTROYED) } + + @Nested + inner class `scope is created` { + + val scope by resets { lifecycleOwner.lifecycleScope } + + @Test + fun `scope and job should already be cancelled`() = runBlocking { + + scope.isActive shouldBe false + scope.coroutineContext[Job]!!.isActive shouldBe false + } + + @Test + fun `scope should not be cached`() { + + storeMap[lifecycleOwner.lifecycle] shouldBe null + } + + // This is a change detector. + // This isn't actually desired, but the precondition should be impossible. + @Test + fun `additional scopes should be unique`() { + + lifecycleOwner.lifecycleScope shouldNotBe scope + } + } + } + + @Nested + inner class `initial lifecycle of Lifecycle State INITIALIZED` { + + val lifecycleOwner by resets { FakeLifecycleOwner(initialState = Lifecycle.State.INITIALIZED) } + + @Nested + inner class `scope is created` { + + val scope by resets { lifecycleOwner.lifecycleScope } + + @Test + fun `scope and job should be active`() { + + scope.isActive shouldBe true + } + + @Test + fun `scope should be cached`() { + + scope + + storeMap[lifecycleOwner.lifecycle] shouldBe scope + } + + @Test + fun `repeated access should return the same scope`() { + + lifecycleOwner.lifecycleScope shouldBe scope + } + + @Nested + inner class `lifecycle passes to destroyed` { + + @BeforeEach + fun beforeEach() { + // special case for Initialized state + lifecycleOwner.create() + + lifecycleOwner.destroy() + } + + @Test + fun `scope should be cancelled`() { + + scope.isActive shouldBe false + } + + @Test + fun `scope should be removed from the cache`() { + + storeMap[lifecycleOwner.lifecycle] shouldBe null + } + } + } + + @Nested + inner class `multiple threads access lifecycleScope at once` { + + @Test + fun `all threads should get the same instance`() = runBlocking { + + val hugeExecutor = ThreadPoolExecutor( + 200, 200, 5000, TimeUnit.MILLISECONDS, LinkedBlockingQueue() + ) + + val dispatcher = hugeExecutor.asCoroutineDispatcher() + + val lock = CompletableDeferred() + + val all = List(200) { + async(dispatcher) { + lock.await() + lifecycleOwner.lifecycleScope + } + } + + yield() + lock.complete(Unit) + + all.awaitAll().distinct() shouldBe listOf(lifecycleOwner.lifecycleScope) + } + } + } + + @Nested + inner class `initial lifecycle of CREATED` { + + val lifecycleOwner by resets { FakeLifecycleOwner(initialState = Lifecycle.State.CREATED) } + + @Nested + inner class `scope is created` { + + val scope by resets { lifecycleOwner.lifecycleScope } + + @Test + fun `scope and job should be active`() { + + scope.isActive shouldBe true + } + + @Test + fun `scope should be cached`() { + + scope + + storeMap[lifecycleOwner.lifecycle] shouldBe scope + } + + @Test + fun `repeated access should return the same scope`() { + + lifecycleOwner.lifecycleScope shouldBe scope + } + + @Nested + inner class `lifecycle passes to destroyed` { + + @BeforeEach + fun beforeEach() { + lifecycleOwner.destroy() + } + + @Test + fun `scope should be cancelled`() { + + scope.isActive shouldBe false + } + + @Test + fun `scope should be removed from the cache`() { + + storeMap[lifecycleOwner.lifecycle] shouldBe null + } + } + } + + @Nested + inner class `multiple threads access lifecycleScope at once` { + + @Test + fun `all threads should get the same instance`() = runBlocking { + + val hugeExecutor = ThreadPoolExecutor( + 200, 200, 5000, TimeUnit.MILLISECONDS, LinkedBlockingQueue() + ) + + val dispatcher = hugeExecutor.asCoroutineDispatcher() + + val lock = CompletableDeferred() + + val all = List(200) { + async(dispatcher) { + lock.await() + lifecycleOwner.lifecycleScope + } + } + + yield() + lock.complete(Unit) + + all.awaitAll().distinct() shouldBe listOf(lifecycleOwner.lifecycleScope) + } + } + } + + @Nested + inner class `initial lifecycle of STARTED` { + + val lifecycleOwner by resets { FakeLifecycleOwner(initialState = Lifecycle.State.STARTED) } + + @Nested + inner class `scope is created` { + + val scope by resets { lifecycleOwner.lifecycleScope } + + @Test + fun `scope and job should be active`() { + + scope.isActive shouldBe true + } + + @Test + fun `scope should be cached`() { + + scope + + storeMap[lifecycleOwner.lifecycle] shouldBe scope + } + + @Test + fun `repeated access should return the same scope`() { + + lifecycleOwner.lifecycleScope shouldBe scope + } + + @Nested + inner class `lifecycle passes to destroyed` { + + @BeforeEach + fun beforeEach() { + lifecycleOwner.destroy() + } + + @Test + fun `scope should be cancelled`() { + + scope.isActive shouldBe false + } + + @Test + fun `scope should be removed from the cache`() { + + storeMap[lifecycleOwner.lifecycle] shouldBe null + } + } + } + + @Nested + inner class `multiple threads access lifecycleScope at once` { + + @Test + fun `all threads should get the same instance`() = runBlocking { + + val hugeExecutor = ThreadPoolExecutor( + 200, 200, 5000, TimeUnit.MILLISECONDS, LinkedBlockingQueue() + ) + + val dispatcher = hugeExecutor.asCoroutineDispatcher() + + val lock = CompletableDeferred() + + val all = List(200) { + async(dispatcher) { + lock.await() + lifecycleOwner.lifecycleScope + } + } + + yield() + lock.complete(Unit) + + all.awaitAll().distinct() shouldBe listOf(lifecycleOwner.lifecycleScope) + } + } + } + + @Nested + inner class `initial lifecycle of RESUMED` { + + val lifecycleOwner by resets { FakeLifecycleOwner(initialState = Lifecycle.State.RESUMED) } + + @Nested + inner class `scope is created` { + + val scope by resets { lifecycleOwner.lifecycleScope } + + @Test + fun `scope and job should be active`() { + + scope.isActive shouldBe true + } + + @Test + fun `scope should be cached`() { + + scope + + storeMap[lifecycleOwner.lifecycle] shouldBe scope + } + + @Test + fun `repeated access should return the same scope`() { + + lifecycleOwner.lifecycleScope shouldBe scope + } + + @Nested + inner class `lifecycle passes to destroyed` { + + @BeforeEach + fun beforeEach() { + + lifecycleOwner.destroy() + } + + @Test + fun `scope should be cancelled`() { + + scope.isActive shouldBe false + } + + @Test + fun `scope should be removed from the cache`() { + + storeMap[lifecycleOwner.lifecycle] shouldBe null + } + } + } + + @Nested + inner class `multiple threads access lifecycleScope at once` { + + @Test + fun `all threads should get the same instance`() = runBlocking { + + val hugeExecutor = ThreadPoolExecutor( + 200, 200, 5000, TimeUnit.MILLISECONDS, LinkedBlockingQueue() + ) + + val dispatcher = hugeExecutor.asCoroutineDispatcher() + + val lock = CompletableDeferred() + + val all = List(200) { + async(dispatcher) { + lock.await() + lifecycleOwner.lifecycleScope + } + } + + yield() + lock.complete(Unit) + + all.awaitAll().distinct() shouldBe listOf(lifecycleOwner.lifecycleScope) + } + } + } + +} diff --git a/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeFactoryTest.kt b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeFactoryTest.kt index 41b923e11..7c555c84e 100644 --- a/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeFactoryTest.kt +++ b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/LifecycleScopeFactoryTest.kt @@ -17,6 +17,9 @@ package dispatch.android.lifecycle import dispatch.core.* import dispatch.internal.test.* +import dispatch.internal.test.android.* +import hermit.test.* +import hermit.test.junit.* import io.kotest.matchers.* import io.kotest.matchers.types.* import kotlinx.coroutines.* @@ -26,7 +29,7 @@ import kotlin.coroutines.* @ObsoleteCoroutinesApi @ExperimentalCoroutinesApi -internal class LifecycleScopeFactoryTest { +internal class LifecycleScopeFactoryTest : HermitJUnit5() { val job = Job() val dispatcher = newSingleThreadContext("single thread dispatcher") @@ -38,8 +41,11 @@ internal class LifecycleScopeFactoryTest { val mainDispatcher = newSingleThreadContext("main dispatcher") + val lifecycleOwner by resets { FakeLifecycleOwner() } + @BeforeAll fun beforeAll() { + LifecycleScopeFactory.reset() Dispatchers.setMain(mainDispatcher) } @@ -54,25 +60,23 @@ internal class LifecycleScopeFactoryTest { } @Test - fun `default factory should be a default MainImmediateCoroutineScope`() = runBlockingTest { + fun `default factory should be a default MainImmediateContext`() = runBlockingTest { - val scope = LifecycleScopeFactory.create() + val scope = LifecycleScopeFactory.create(lifecycleOwner.lifecycle) - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() scope.coroutineContext[Job]!!.shouldBeSupervisorJob() scope.coroutineContext[ContinuationInterceptor] shouldBe Dispatchers.Main - - scope.shouldBeInstanceOf() } @Test fun `a custom factory should be used after being set`() = runBlockingTest { - LifecycleScopeFactory.set { MainImmediateCoroutineScope(originContext) } + LifecycleScopeFactory.set { originContext } - val scope = LifecycleScopeFactory.create() + val scope = LifecycleScopeFactory.create(lifecycleOwner.lifecycle) scope.coroutineContext shouldEqualFolded originContext + mainDispatcher } @@ -80,17 +84,17 @@ internal class LifecycleScopeFactoryTest { @Test fun `reset after setting a custom factory should return to the default`() = runBlockingTest { - LifecycleScopeFactory.set { MainImmediateCoroutineScope(originContext) } + LifecycleScopeFactory.set { originContext } - val custom = LifecycleScopeFactory.create() + val custom = LifecycleScopeFactory.create(lifecycleOwner.lifecycle) custom.coroutineContext shouldEqualFolded originContext + mainDispatcher LifecycleScopeFactory.reset() - val default = LifecycleScopeFactory.create() + val default = LifecycleScopeFactory.create(lifecycleOwner.lifecycle) - default.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + default.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() default.coroutineContext[Job]!!.shouldBeSupervisorJob() diff --git a/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt new file mode 100644 index 000000000..95f9c1a0d --- /dev/null +++ b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.arch.core.executor.testing.* +import dispatch.internal.test.android.* +import dispatch.test.* +import io.kotest.matchers.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import org.junit.* +import org.junit.runner.* +import org.robolectric.* +import org.robolectric.annotation.* + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +@ExperimentalCoroutinesApi +internal class ViewLifecycleScopeFlowCollectionTest { + + @JvmField + @Rule + val rule = TestCoroutineRule() + + @JvmField + @Rule + val instantTaskRule = InstantTaskExecutorRule() + + val fragmentLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + val viewLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + + @Before + fun setUp() { + fragmentLifecycleOwner.start() + viewLifecycleOwner.create() + } + + @Test + fun `launchOnCreate collection should only happen while at least CREATED`() = runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val flow = MutableStateFlow(0) + val collected = mutableListOf() + + with(fragment) { + withViewLifecycleScope { + flow.onEach { collected.add(it) }.launchOnCreate() + } + } + + collected shouldBe listOf() + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.create() + + collected shouldBe listOf(0) + + flow.value = 1 + + collected shouldBe listOf(0, 1) + + viewLifecycleOwner.destroy() + + flow.value = 2 + + collected shouldBe listOf(0, 1) + } + + @Test + fun `launchOnStart collection should only happen while at least STARTED`() = runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val flow = MutableStateFlow(0) + val collected = mutableListOf() + + with(fragment) { + withViewLifecycleScope { + flow.onEach { collected.add(it) } + .launchOnStart() + } + } + + collected shouldBe listOf() + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.start() + + collected shouldBe listOf(0) + + flow.value = 1 + + collected shouldBe listOf(0, 1) + + viewLifecycleOwner.stop() + + flow.value = 2 + + collected shouldBe listOf(0, 1) + } + + @Test + fun `launchOnResume collection should only happen while RESUMED`() = runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val flow = MutableStateFlow(0) + val collected = mutableListOf() + + with(fragment) { + withViewLifecycleScope { + flow.onEach { collected.add(it) }.launchOnResume() + } + } + + collected shouldBe listOf() + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.resume() + + collected shouldBe listOf(0) + + flow.value = 1 + + collected shouldBe listOf(0, 1) + + viewLifecycleOwner.pause() + + flow.value = 2 + + collected shouldBe listOf(0, 1) + + } +} diff --git a/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/WithViewLifecycleScopeExtensionTest.kt b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/WithViewLifecycleScopeExtensionTest.kt new file mode 100644 index 000000000..5fe8f5535 --- /dev/null +++ b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/WithViewLifecycleScopeExtensionTest.kt @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.arch.core.executor.testing.* +import dispatch.internal.test.android.* +import dispatch.test.* +import io.kotest.matchers.* +import io.kotest.matchers.types.* +import kotlinx.coroutines.* +import org.junit.* +import org.junit.runner.* +import org.robolectric.* +import org.robolectric.annotation.* + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +@ExperimentalCoroutinesApi +internal class WithViewLifecycleScopeExtensionTest { + + @JvmField + @Rule + val rule = TestCoroutineRule() + + @JvmField + @Rule + val instantTaskRule = InstantTaskExecutorRule() + + val fragmentLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + val viewLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + + @Before + fun setUp() { + fragmentLifecycleOwner.start() + viewLifecycleOwner.create() + } + + @Test + fun `when the livedata goes from null to non-null, lambda should be invoked`() { + + var invocations = 0 + + val fragment = FakeFragment(fragmentLifecycleOwner) + + with(fragment) { + withViewLifecycleScope { invocations++ } + } + + invocations shouldBe 0 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 1 + } + + @Test + fun `when the livedata goes from null to non-null, lambda should be invoked every time`() { + + var invocations = 0 + + val fragment = FakeFragment(fragmentLifecycleOwner) + + with(fragment) { + withViewLifecycleScope { invocations++ } + } + + invocations shouldBe 0 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 1 + + fragment.setFakeViewLifecycleOwner(null) + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 2 + + fragment.setFakeViewLifecycleOwner(null) + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 3 + + } + + @Test + fun `when the livedata gets set to non-null, lambda should be invoked every time`() { + + var invocations = 0 + + val fragment = FakeFragment(fragmentLifecycleOwner) + + with(fragment) { + withViewLifecycleScope { invocations++ } + } + + invocations shouldBe 0 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 1 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 2 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 3 + + } + + @Test + fun `when the view lifecycle is destroyed, lambda should be cancelled`() { + + lateinit var job: Job + + val fragment = FakeFragment(fragmentLifecycleOwner) + + with(fragment) { + withViewLifecycleScope { + job = launch { + // never completes, so the Job should be active until the scope is destroyed + CompletableDeferred().await() + } + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.create() + viewLifecycleOwner.destroy() + + job.isCancelled shouldBe true + + } + + @Test + fun `when the fragment lifecycle is destroyed, lambda be cancelled`() { + + lateinit var job: Job + + val fragment = FakeFragment(fragmentLifecycleOwner) + + with(fragment) { + withViewLifecycleScope { + job = launch { + // never completes, so the Job should be active until the scope is destroyed + CompletableDeferred().await() + } + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + fragmentLifecycleOwner.create() + fragmentLifecycleOwner.destroy() + + job.isActive shouldBe false + + } + + @Test + fun `the lambda's LifecycleScope should correspond to the view lifecycle`() = runBlocking { + + lateinit var job: Job + + val fragment = FakeFragment(fragmentLifecycleOwner) + + with(fragment) { + withViewLifecycleScope { + job = launch { + + lifecycle shouldBeSameInstanceAs viewLifecycleOwner.lifecycle + + } + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + job.join() + + } +} + diff --git a/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/internal/AtomicGetOrPutTest.kt b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/internal/AtomicGetOrPutTest.kt new file mode 100644 index 000000000..9bd190416 --- /dev/null +++ b/dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/internal/AtomicGetOrPutTest.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle.internal + +import androidx.lifecycle.* +import dispatch.android.lifecycle.LifecycleCoroutineScope +import dispatch.core.* +import dispatch.internal.test.android.* +import dispatch.test.* +import hermit.test.junit.* +import io.kotest.matchers.* +import kotlinx.coroutines.* +import org.junit.jupiter.api.* +import java.util.concurrent.* + +@ObsoleteCoroutinesApi +@ExperimentalCoroutinesApi +internal class AtomicGetOrPutTest : HermitJUnit5() { + + @Nested + inner class `API level 23` { + + @Nested + inner class `multiple threads access lifecycleScope at once` { + @Test + fun `all threads should get the same instance`() = runBlocking { + + val main = newSingleThreadContext("main") + + val storeMap = ConcurrentHashMap() + + val lifecycleOwner = FakeLifecycleOwner(Lifecycle.State.INITIALIZED) + + val androidLifecycle = lifecycleOwner.lifecycle + + val hugeExecutor = ThreadPoolExecutor( + 200, 200, 5000, TimeUnit.MILLISECONDS, LinkedBlockingQueue() + ).asCoroutineDispatcher() + + val lock = CompletableDeferred() + + val all = List(200) { + async(hugeExecutor) { + + lock.await() + + storeMap.atomicGetOrPut(androidLifecycle) { + val scope = LifecycleCoroutineScope( + lifecycle = androidLifecycle, + coroutineScope = MainImmediateCoroutineScope(Job(), TestDispatcherProvider(main)) + ) + withContext(main) { + + androidLifecycle.addObserver(LifecycleCoroutineScopeStore) + } + scope + } + } + } + + yield() + lock.complete(Unit) + + all.awaitAll().distinct().size shouldBe 1 + + delay(100) + + androidLifecycle.observerCount shouldBe 2 + } + + } + } +} diff --git a/dispatch-android-lifecycle/README.md b/dispatch-android-lifecycle/README.md index ccff73d5f..fe7857687 100644 --- a/dispatch-android-lifecycle/README.md +++ b/dispatch-android-lifecycle/README.md @@ -57,10 +57,9 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-lifecycle:1.0.0-beta04") - implementation("androidx.lifecycle:lifecycle-common:2.2.0") } ``` @@ -72,9 +71,9 @@ dependencies { [LifecycleCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.html [MinimumStatePolicy]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html -[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.html -[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.html -[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.html +[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.html +[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.html +[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.html [LifecycleOwner.onNextCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.html [LifecycleOwner.onNextStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.html [LifecycleOwner.onNextResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.html diff --git a/dispatch-android-lifecycle/api/dispatch-android-lifecycle.api b/dispatch-android-lifecycle/api/dispatch-android-lifecycle.api index 886eb7de1..4158bd931 100644 --- a/dispatch-android-lifecycle/api/dispatch-android-lifecycle.api +++ b/dispatch-android-lifecycle/api/dispatch-android-lifecycle.api @@ -7,16 +7,22 @@ public final class dispatch/android/lifecycle/BuildConfig { public fun ()V } -public final class dispatch/android/lifecycle/LifecycleCoroutineScope : dispatch/core/MainImmediateCoroutineScope { - public fun (Landroidx/lifecycle/Lifecycle;Ldispatch/core/MainImmediateCoroutineScope;)V +public class dispatch/android/lifecycle/LifecycleCoroutineScope : dispatch/core/MainImmediateCoroutineScope { + public static final field Companion Ldispatch/android/lifecycle/LifecycleCoroutineScope$Companion; + public fun (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;)V + public synthetic fun (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; public final fun getLifecycle ()Landroidx/lifecycle/Lifecycle; - public final fun launchOnCreate (Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job; - public static synthetic fun launchOnCreate$default (Ldispatch/android/lifecycle/LifecycleCoroutineScope;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job; - public final fun launchOnResume (Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job; - public static synthetic fun launchOnResume$default (Ldispatch/android/lifecycle/LifecycleCoroutineScope;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job; - public final fun launchOnStart (Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job; - public static synthetic fun launchOnStart$default (Ldispatch/android/lifecycle/LifecycleCoroutineScope;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job; + public final fun launchOnCreate (Lkotlin/coroutines/CoroutineContext;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job; + public static synthetic fun launchOnCreate$default (Ldispatch/android/lifecycle/LifecycleCoroutineScope;Lkotlin/coroutines/CoroutineContext;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job; + public final fun launchOnResume (Lkotlin/coroutines/CoroutineContext;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job; + public static synthetic fun launchOnResume$default (Ldispatch/android/lifecycle/LifecycleCoroutineScope;Lkotlin/coroutines/CoroutineContext;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job; + public final fun launchOnStart (Lkotlin/coroutines/CoroutineContext;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job; + public static synthetic fun launchOnStart$default (Ldispatch/android/lifecycle/LifecycleCoroutineScope;Lkotlin/coroutines/CoroutineContext;Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job; +} + +public final class dispatch/android/lifecycle/LifecycleCoroutineScope$Companion { + public final fun invoke (Landroidx/lifecycle/Lifecycle;Lkotlinx/coroutines/CoroutineScope;)Ldispatch/android/lifecycle/LifecycleCoroutineScope; } public final class dispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy : java/lang/Enum { @@ -26,12 +32,37 @@ public final class dispatch/android/lifecycle/LifecycleCoroutineScope$MinimumSta public static fun values ()[Ldispatch/android/lifecycle/LifecycleCoroutineScope$MinimumStatePolicy; } -public final class dispatch/android/lifecycle/LifecycleSuspendExtKt { - public static final fun onNextCreate (Landroidx/lifecycle/Lifecycle;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun onNextCreate (Landroidx/lifecycle/LifecycleOwner;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun onNextResume (Landroidx/lifecycle/Lifecycle;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun onNextResume (Landroidx/lifecycle/LifecycleOwner;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun onNextStart (Landroidx/lifecycle/Lifecycle;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun onNextStart (Landroidx/lifecycle/LifecycleOwner;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +public final class dispatch/android/lifecycle/LifecycleCoroutineScopeFactory { + public fun (Lkotlin/jvm/functions/Function0;)V + public final fun create (Landroidx/lifecycle/Lifecycle;)Ldispatch/android/lifecycle/LifecycleCoroutineScope; +} + +public final class dispatch/android/lifecycle/LifecycleCoroutineScopeKt { + public static final fun MainImmediateContext ()Lkotlin/coroutines/CoroutineContext; +} + +public final class dispatch/android/lifecycle/SuspendKt { + public static final fun onNextCreate (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun onNextCreate (Landroidx/lifecycle/LifecycleOwner;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun onNextCreate$default (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun onNextCreate$default (Landroidx/lifecycle/LifecycleOwner;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static final fun onNextResume (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun onNextResume (Landroidx/lifecycle/LifecycleOwner;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun onNextResume$default (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun onNextResume$default (Landroidx/lifecycle/LifecycleOwner;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static final fun onNextStart (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun onNextStart (Landroidx/lifecycle/LifecycleOwner;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun onNextStart$default (Landroidx/lifecycle/Lifecycle;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun onNextStart$default (Landroidx/lifecycle/LifecycleOwner;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; +} + +public final class dispatch/android/lifecycle/ViewLifecycleCoroutineScope : dispatch/android/lifecycle/LifecycleCoroutineScope { + public final fun launchOnCreate (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/Job; + public final fun launchOnResume (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/Job; + public final fun launchOnStart (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/Job; +} + +public final class dispatch/android/lifecycle/ViewLifecycleCoroutineScopeKt { + public static final fun withViewLifecycle (Lkotlinx/coroutines/CoroutineScope;Landroidx/fragment/app/Fragment;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job; } diff --git a/dispatch-android-lifecycle/build.gradle.kts b/dispatch-android-lifecycle/build.gradle.kts index bb8b207cb..4494207bd 100644 --- a/dispatch-android-lifecycle/build.gradle.kts +++ b/dispatch-android-lifecycle/build.gradle.kts @@ -45,10 +45,9 @@ android { dependencies { + implementation(Libs.AndroidX.Fragment.core) implementation(Libs.AndroidX.Lifecycle.common) - testImplementation(Libs.AndroidX.Lifecycle.runtime) - - implementation(Libs.JakeWharton.timber) + implementation(Libs.AndroidX.Lifecycle.liveData) implementation(Libs.Kotlin.stdlib) @@ -56,16 +55,28 @@ dependencies { implementation(Libs.Kotlinx.Coroutines.core) api(project(":dispatch-core")) - testImplementation(project(":dispatch-test")) + testImplementation(project(":dispatch-test-junit4")) testImplementation(project(":dispatch-test-junit5")) testImplementation(project(":dispatch-internal-test")) + testImplementation(project(":dispatch-internal-test-android")) + + testImplementation(Libs.AndroidX.Lifecycle.runtime) + + testImplementation(Libs.AndroidX.Test.Arch.core) + testImplementation(Libs.AndroidX.Test.Espresso.core) + testImplementation(Libs.AndroidX.Test.runner) testImplementation(Libs.JUnit.jUnit5) + testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) + testImplementation(Libs.Kotlinx.Coroutines.test) - testImplementation(Libs.AndroidX.Test.runner) - testImplementation(Libs.AndroidX.Test.Espresso.core) + testImplementation(Libs.RickBusarow.Hermit.coroutines) + testImplementation(Libs.RickBusarow.Hermit.junit5) + + testImplementation(Libs.Robolectric.core) } diff --git a/dispatch-android-lifecycle/samples/build.gradle.kts b/dispatch-android-lifecycle/samples/build.gradle.kts index 076a8fd42..638287516 100644 --- a/dispatch-android-lifecycle/samples/build.gradle.kts +++ b/dispatch-android-lifecycle/samples/build.gradle.kts @@ -42,6 +42,8 @@ dependencies { implementation(Libs.AndroidX.Lifecycle.common) implementation(Libs.AndroidX.Lifecycle.liveData) + implementation(Libs.AndroidX.Lifecycle.extensions) + implementation(Libs.AndroidX.Lifecycle.viewModel) testImplementation(Libs.AndroidX.Lifecycle.runtime) implementation(Libs.Kotlin.stdlib) @@ -52,10 +54,12 @@ dependencies { implementation(project(":dispatch-android-lifecycle")) implementation(project(":dispatch-android-lifecycle-extensions")) implementation(project(":dispatch-core")) + implementation(project(":dispatch-internal-test-android")) implementation(project(":dispatch-test")) implementation(project(":dispatch-test-junit5")) testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) @@ -65,4 +69,13 @@ dependencies { testImplementation(Libs.Kotlinx.Coroutines.test) testImplementation(Libs.Kotlinx.Knit.test) + testImplementation(Libs.RickBusarow.Hermit.coroutines) + testImplementation(Libs.RickBusarow.Hermit.junit5) + + testImplementation(Libs.AndroidX.Fragment.ktx) + testImplementation(Libs.AndroidX.Test.Arch.core) + testImplementation(Libs.AndroidX.Test.runner) + testImplementation(Libs.AndroidX.Test.Espresso.core) + testImplementation(Libs.Robolectric.core) + } diff --git a/dispatch-android-lifecycle/samples/src/test/java/samples/FakeLifecycleOwner.kt b/dispatch-android-lifecycle/samples/src/test/java/samples/FakeLifecycleOwner.kt deleted file mode 100644 index f9cceec29..000000000 --- a/dispatch-android-lifecycle/samples/src/test/java/samples/FakeLifecycleOwner.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2020 Rick Busarow - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples - -import androidx.lifecycle.* -import kotlinx.coroutines.* - -@Suppress("EXPERIMENTAL_API_USAGE") -open class FakeLifecycleOwner( - private val mainDispatcher: CoroutineDispatcher = fakeMainDispatcher(), - initialState: Lifecycle.State = Lifecycle.State.INITIALIZED -) : LifecycleOwner { - - private val registry: LifecycleRegistry by lazy { LifecycleRegistry(this) } - - init { - when (initialState) { - Lifecycle.State.DESTROYED -> destroy() - Lifecycle.State.CREATED -> create() - Lifecycle.State.STARTED -> start() - Lifecycle.State.RESUMED -> resume() - else -> Unit - } - } - - override fun getLifecycle(): LifecycleRegistry = registry - - fun create() = runBlocking(mainDispatcher) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - } - - fun start() = runBlocking(mainDispatcher) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) - } - - fun resume() = runBlocking(mainDispatcher) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) - } - - fun pause() = runBlocking(mainDispatcher) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) - } - - fun stop() = runBlocking(mainDispatcher) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) - } - - fun initialize() = runBlocking(mainDispatcher) { - lifecycle.currentState = Lifecycle.State.INITIALIZED - } - - fun destroy() = runBlocking(mainDispatcher) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) - } - - fun getObserverCount(): Int = runBlocking(mainDispatcher) { registry.observerCount } -} - -@Suppress("EXPERIMENTAL_API_USAGE") -private fun fakeMainDispatcher() = newSingleThreadContext("FakeLifecycleOwner main") diff --git a/dispatch-android-lifecycle/samples/src/test/java/samples/Fragment.kt b/dispatch-android-lifecycle/samples/src/test/java/samples/Fragment.kt index d971bd474..3f73d824a 100644 --- a/dispatch-android-lifecycle/samples/src/test/java/samples/Fragment.kt +++ b/dispatch-android-lifecycle/samples/src/test/java/samples/Fragment.kt @@ -17,6 +17,7 @@ package samples import androidx.lifecycle.* +import dispatch.internal.test.android.* abstract class Fragment( initialState: Lifecycle.State = Lifecycle.State.INITIALIZED diff --git a/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt b/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt new file mode 100644 index 000000000..6097155e7 --- /dev/null +++ b/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeFactorySample.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package samples + +import dispatch.android.lifecycle.* + +class LifecycleCoroutineScopeFactorySample { + + @Sample + fun factorySample() { + + @Provides + fun provideFactory(): LifecycleCoroutineScopeFactory = LifecycleCoroutineScopeFactory { + // other elements are added automatically + MyCustomElement() + } + + class MyFragment @Inject constructor( + factory: LifecycleCoroutineScopeFactory + ) : Fragment() { + + val lifecycleScope = factory.create(lifecycle) + + init { + lifecycleScope.launchOnStart { + // ... + } + } + } + } +} + +internal annotation class Before +internal annotation class After +internal annotation class Module +internal annotation class Provides +internal annotation class Inject diff --git a/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt b/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt index 2ee8efd46..ae69489d3 100644 --- a/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt +++ b/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleCoroutineScopeSample.kt @@ -23,38 +23,65 @@ import io.kotest.matchers.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* -import org.junit.jupiter.api.* @CoroutineTest @ExperimentalCoroutinesApi -class LifecycleCoroutineScopeSample( - val testScope: TestProvidedCoroutineScope -) { +class LifecycleCoroutineScopeSample { - @BeforeEach - fun beforeEach() { + @Sample + fun lifecycleCoroutineScopeFromScopeSample() = runBlocking { + + // This could be any LifecycleOwner -- Fragments, Activities, Services... + class SomeFragment @Inject constructor( + coroutineScope: CoroutineScope // could be any type of CoroutineScope + ) : Fragment() { + + val lifecycleScope = LifecycleCoroutineScope(lifecycle, coroutineScope) + + init { + + // active only when "resumed". starts a fresh coroutine each time + lifecycleScope.launchOnResume { } + + // active only when "started". starts a fresh coroutine each time + // this is a rough proxy for LiveData behavior + lifecycleScope.launchOnStart { } + + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } - LifecycleScopeFactory.set { testScope } + // launch when created, automatically stop on destroy + lifecycleScope.launchOnCreate { } + + // it works as a normal CoroutineScope as well (because it is) + lifecycleScope.launchMain { } + + } + } } @Sample - fun lifecycleCoroutineScopeSample() = runBlocking { + fun lifecycleCoroutineScopeFromContextSample() = runBlocking { // This could be any LifecycleOwner -- Fragments, Activities, Services... class SomeFragment : Fragment() { - init { + val context = Job() + DispatcherProvider() + + val lifecycleScope = LifecycleCoroutineScope(lifecycle, context) - // auto-created MainImmediateCoroutineScope which is lifecycle-aware - lifecycleScope //... + init { // active only when "resumed". starts a fresh coroutine each time - // this is a rough proxy for LiveData behavior lifecycleScope.launchOnResume { } // active only when "started". starts a fresh coroutine each time + // this is a rough proxy for LiveData behavior lifecycleScope.launchOnStart { } + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + // launch when created, automatically stop on destroy lifecycleScope.launchOnCreate { } @@ -65,6 +92,35 @@ class LifecycleCoroutineScopeSample( } } + @Sample + fun lifecycleCoroutineScopeDefaultSample() = runBlocking { + + // This could be any LifecycleOwner -- Fragments, Activities, Services... + class SomeFragment : Fragment() { + + val lifecycleScope = LifecycleCoroutineScope(lifecycle) + + init { + + // active only when "resumed". starts a fresh coroutine each time + lifecycleScope.launchOnResume { } + + // active only when "started". starts a fresh coroutine each time + // this is a rough proxy for LiveData behavior + lifecycleScope.launchOnStart { } + + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + + // launch when created, automatically stop on destroy + lifecycleScope.launchOnCreate { } + + // it works as a normal CoroutineScope as well (because it is) + lifecycleScope.launchMain { } + } + } + } + @Sample fun launchOnCreateOnceSample() = runBlocking { diff --git a/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleSuspendSample.kt b/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleSuspendSample.kt index 8260a398e..412486fbf 100644 --- a/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleSuspendSample.kt +++ b/dispatch-android-lifecycle/samples/src/test/java/samples/LifecycleSuspendSample.kt @@ -31,7 +31,7 @@ class LifecycleSuspendSample( @BeforeEach fun beforeEach() { - LifecycleScopeFactory.set { testScope } + LifecycleScopeFactory.set { testScope.coroutineContext } } @Sample diff --git a/dispatch-android-lifecycle/samples/src/test/java/samples/WithLifecycleScopeSample.kt b/dispatch-android-lifecycle/samples/src/test/java/samples/WithLifecycleScopeSample.kt new file mode 100644 index 000000000..91df56057 --- /dev/null +++ b/dispatch-android-lifecycle/samples/src/test/java/samples/WithLifecycleScopeSample.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "UNUSED_ANONYMOUS_PARAMETER") + +package samples + +import androidx.fragment.app.* +import androidx.fragment.app.Fragment +import androidx.lifecycle.* +import dispatch.android.lifecycle.* +import dispatch.core.* +import kotlinx.coroutines.flow.* +import org.junit.* +import org.junit.runner.* +import org.robolectric.* +import org.robolectric.annotation.* + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +class WithViewLifecycleScopeSample { + + @Test + fun withViewLifecycleScopeSample() { + + class MyFragment @Inject constructor( + scope: MainImmediateCoroutineScope + ) : Fragment() { + + val myViewModel by viewModels() + + val observerJob = scope.withViewLifecycle(this) { + // this lambda is invoked every time the View lifecycle is set + myViewModel.dataFlow.onEach { data -> + // ... + }.launchOnCreate() + } + } + } +} + +interface Data + +class MyViewModel : ViewModel() { + + val dataFlow = flow { + // ... + } +} diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt index 472de2e66..c36c9b9d5 100644 --- a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt @@ -19,33 +19,59 @@ import androidx.lifecycle.* import dispatch.android.lifecycle.internal.* import dispatch.core.* import kotlinx.coroutines.* +import kotlin.coroutines.* /** - * [MainImmediateCoroutineScope] instance which is tied to a [Lifecycle]. + * Default implementation of a [CoroutineContext] as seen in a `MainImmediateCoroutineScope`. + * + * @see MainImmediateCoroutineScope + */ +public fun MainImmediateContext(): CoroutineContext { + val dispatcherProvider = DispatcherProvider() + + return SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate +} + +/** + * [MainImmediateCoroutineScope] which is tied to a [Lifecycle]. * * The [CoroutineScope] provides lifecycle-aware [launch] functions * which will automatically start upon reaching their associated [Lifecycle.Event], - * then automatically cancel upon the [lifecycle] dropping below that state. Reaching + * then automatically cancel upon the lifecycle dropping below that state. Reaching * that state again will start a new [Job]. * - * @sample samples.LifecycleCoroutineScopeSample.lifecycleCoroutineScopeSample + * This `CoroutineScope`'s [Job] will be cancelled automatically + * as soon as the `lifecycle` reaches [DESTROYED][Lifecycle.State.DESTROYED]. + * + * @sample samples.LifecycleCoroutineScopeSample.lifecycleCoroutineScopeDefaultSample + * @sample samples.LifecycleCoroutineScopeSample.lifecycleCoroutineScopeFromContextSample * @param lifecycle the lifecycle to which this [MainImmediateCoroutineScope] is linked. + * @param coroutineContext the source CoroutineContext which will be converted to a [MainImmediateCoroutineScope]. + * Its [Elements][CoroutineContext.Element] will be re-used, except: + * 1. If a [DispatcherProvider] element isn't present, [DefaultDispatcherProvider.get] will be added. + * 2. If a [Job] element isn't present, a [SupervisorJob] will be added. + * 3. If the [ContinuationInterceptor][kotlin.coroutines.ContinuationInterceptor] does not match the one referenced by the [possibly new] [DispatcherProvider.mainImmediate] property, it will be updated to match. */ -class LifecycleCoroutineScope( +open class LifecycleCoroutineScope( val lifecycle: Lifecycle, - private val coroutineScope: MainImmediateCoroutineScope -) : MainImmediateCoroutineScope by coroutineScope { + coroutineContext: CoroutineContext = MainImmediateContext() +) : MainImmediateCoroutineScope by MainImmediateCoroutineScope(coroutineContext) { + + init { + LifecycleCoroutineScopeBinding(lifecycle, coroutineContext).bind() + } /** * Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State] * is at least [Lifecycle.State.CREATED]. * - * [block] is executed using the receiver [CoroutineScope]'s [Job] as a parent, + * `block` is executed using the receiver [CoroutineScope]'s [Job] as a parent, * but always executes using [Dispatchers.Main] as its [CoroutineDispatcher]. * - * Execution of [block] is cancelled when the receiver [CoroutineScope] is cancelled, + * Execution of `block` is cancelled when the receiver [CoroutineScope] is cancelled, * or when [lifecycle]'s [Lifecycle.State] drops below [Lifecycle.State.CREATED]. * + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param minimumStatePolicy *optional* - the way this [Job] will behave when passing below the minimum * state or re-entering. Uses [MinimumStatePolicy.RESTART_EVERY] by default. Note that for a normal Lifecycle, * there is no returning from below a [CREATED][Lifecycle.State.CREATED] state, @@ -55,49 +81,54 @@ class LifecycleCoroutineScope( * @sample samples.LifecycleCoroutineScopeSample.launchOnCreateRestartingSample */ fun launchOnCreate( + context: CoroutineContext = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend CoroutineScope.() -> Unit - ): Job = launchOn(Lifecycle.State.CREATED, minimumStatePolicy, block) + ): Job = launchOn(context, Lifecycle.State.CREATED, minimumStatePolicy, block) /** * Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State] * is at least [Lifecycle.State.STARTED]. * - * [block] is executed using the receiver [CoroutineScope]'s [Job] as a parent, + * `block` is executed using the receiver [CoroutineScope]'s [Job] as a parent, * but always executes using [Dispatchers.Main] as its [CoroutineDispatcher]. * - * Execution of [block] is cancelled when the receiver [CoroutineScope] is cancelled, + * Execution of `block` is cancelled when the receiver [CoroutineScope] is cancelled, * or when [lifecycle]'s [Lifecycle.State] drops below [Lifecycle.State.STARTED]. * + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param minimumStatePolicy *optional* - the way this [Job] will behave when passing below the minimum * state or re-entering. Uses [MinimumStatePolicy.RESTART_EVERY] by default. * @sample samples.LifecycleCoroutineScopeSample.launchOnStartOnceSample * @sample samples.LifecycleCoroutineScopeSample.launchOnStartRestartingSample */ fun launchOnStart( + context: CoroutineContext = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend CoroutineScope.() -> Unit - ): Job = launchOn(Lifecycle.State.STARTED, minimumStatePolicy, block) + ): Job = launchOn(context, Lifecycle.State.STARTED, minimumStatePolicy, block) /** * Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State] * is at least [Lifecycle.State.RESUMED]. * - * [block] is executed using the receiver [CoroutineScope]'s [Job] as a parent, + * `block` is executed using the receiver [CoroutineScope]'s [Job] as a parent, * but always executes using [Dispatchers.Main] as its [CoroutineDispatcher]. * - * Execution of [block] is cancelled when the receiver [CoroutineScope] is cancelled, + * Execution of `block` is cancelled when the receiver [CoroutineScope] is cancelled, * or when [lifecycle]'s [Lifecycle.State] drops below [Lifecycle.State.RESUMED]. * + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param minimumStatePolicy *optional* - the way this [Job] will behave when passing below the minimum * state or re-entering. Uses [MinimumStatePolicy.RESTART_EVERY] by default. * @sample samples.LifecycleCoroutineScopeSample.launchOnResumeOnceSample * @sample samples.LifecycleCoroutineScopeSample.launchOnResumeRestartingSample */ fun launchOnResume( + context: CoroutineContext = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend CoroutineScope.() -> Unit - ): Job = launchOn(Lifecycle.State.RESUMED, minimumStatePolicy, block) + ): Job = launchOn(context, Lifecycle.State.RESUMED, minimumStatePolicy, block) /** * Describes the way a particular [Job] will behave if the [lifecycle] passes below the minimum state @@ -128,4 +159,34 @@ class LifecycleCoroutineScope( */ RESTART_EVERY } + + companion object { + + /** + * [MainImmediateCoroutineScope] which is tied to a [Lifecycle]. + * + * The [CoroutineScope] provides lifecycle-aware [launch] functions + * which will automatically start upon reaching their associated [Lifecycle.Event], + * then automatically cancel upon the lifecycle dropping below that state. Reaching + * that state again will start a new [Job]. + * + * If this `CoroutineScope` has a [Job], it will be cancelled automatically + * as soon as the `lifecycle` reaches [DESTROYED][Lifecycle.State.DESTROYED]. + * + * @sample samples.LifecycleCoroutineScopeSample.lifecycleCoroutineScopeFromScopeSample + * @param lifecycle the lifecycle to which this [MainImmediateCoroutineScope] is linked. + * @param coroutineScope the source CoroutineScope which will be converted to a [MainImmediateCoroutineScope]. + * Its [CoroutineContext][kotlin.coroutines.CoroutineContext] will be re-used, except: + * 1. If a [DispatcherProvider] element isn't present, [DefaultDispatcherProvider.get] will be added. + * 2. If a [Job] element isn't present, a [SupervisorJob] will be added. + * 3. If the [ContinuationInterceptor][kotlin.coroutines.ContinuationInterceptor] does not match the one referenced by the [possibly new] [DispatcherProvider.mainImmediate] property, it will be updated to match. + */ + operator fun invoke( + lifecycle: Lifecycle, + coroutineScope: CoroutineScope + ): LifecycleCoroutineScope = LifecycleCoroutineScope( + lifecycle, coroutineScope.coroutineContext + ) + + } } diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScopeFactory.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScopeFactory.kt new file mode 100644 index 000000000..036dbf02f --- /dev/null +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScopeFactory.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.lifecycle.* +import kotlin.coroutines.* + +/** + * Factory for [LifecycleCoroutineScope]s. This may be injected into a lifecycle-aware class + * to provide custom [CoroutineContexts][CoroutineContext]. + * + * @sample samples.LifecycleCoroutineScopeFactorySample.factorySample + * @param coroutineContextFactory the lambda defining the creating of a [CoroutineContext] + */ +public class LifecycleCoroutineScopeFactory( + private val coroutineContextFactory: () -> CoroutineContext +) { + + /** + * Creates a new [LifecycleCoroutineScope] using `coroutineContextFactory` + * + * @param lifecycle the lifecycle which will be bound to the [LifecycleCoroutineScope] + */ + public fun create( + lifecycle: Lifecycle + ): LifecycleCoroutineScope = LifecycleCoroutineScope(lifecycle, coroutineContextFactory.invoke()) +} diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt new file mode 100644 index 000000000..71ef97d5d --- /dev/null +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.fragment.app.* +import androidx.lifecycle.* +import dispatch.android.lifecycle.internal.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import kotlin.coroutines.* + +/** + * [LifecycleCoroutineScope] instance which is tied to a [Fragment's][Fragment] View [lifecycle][Lifecycle]. + */ +class ViewLifecycleCoroutineScope internal constructor( + lifecycle: Lifecycle, + coroutineContext: CoroutineContext +) : LifecycleCoroutineScope(lifecycle, coroutineContext) { + + /** + * Every time the View [Lifecycle State][androidx.lifecycle.Lifecycle.State] reaches [CREATED][androidx.lifecycle.Lifecycle.State.CREATED], create a new coroutine and collect this [Flow]. + * + * @see kotlinx.coroutines.flow.launchIn + */ + fun Flow.launchOnCreate() = launchOnCreate( + minimumStatePolicy = MinimumStatePolicy.RESTART_EVERY + ) { collect() } + + /** + * Every time the View [Lifecycle State][androidx.lifecycle.Lifecycle.State] reaches [STARTED][androidx.lifecycle.Lifecycle.State.STARTED], create a new coroutine and collect this [Flow]. + * + * @see kotlinx.coroutines.flow.launchIn + */ + fun Flow.launchOnStart() = launchOnStart( + minimumStatePolicy = MinimumStatePolicy.RESTART_EVERY + ) { collect() } + + /** + * Every time the View [Lifecycle State][androidx.lifecycle.Lifecycle.State] reaches [RESUMED][androidx.lifecycle.Lifecycle.State.RESUMED], create a new coroutine and collect this [Flow]. + * + * @see kotlinx.coroutines.flow.launchIn + */ + fun Flow.launchOnResume() = launchOnResume( + minimumStatePolicy = MinimumStatePolicy.RESTART_EVERY + ) { collect() } +} + +/** + * [CoroutineScope] helper for a [Fragment]'s [ViewLifecycleOwner][FragmentViewLifecycleOwner]. + * + * This function observes a `Fragment`'s [viewLifecycleOwnerLiveData][androidx.fragment.app.Fragment.getViewLifecycleOwnerLiveData], + * and invokes [block]. + * + * @sample samples.WithViewLifecycleScopeSample.withViewLifecycleScopeSample + */ +@ExperimentalCoroutinesApi +fun CoroutineScope.withViewLifecycle( + fragment: Fragment, + block: ViewLifecycleCoroutineScope.() -> Unit +): Job { + + return bindViewLifecycleCoroutineScope(this, fragment, block) +} diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeBinding.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeBinding.kt new file mode 100644 index 000000000..58ecb9c61 --- /dev/null +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleCoroutineScopeBinding.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle.internal + +import androidx.lifecycle.* +import dispatch.core.* +import kotlinx.coroutines.* +import java.util.concurrent.CancellationException +import kotlin.coroutines.* + +internal class LifecycleCoroutineScopeBinding( + private val lifecycle: Lifecycle, + private val coroutineContext: CoroutineContext +) : LifecycleEventObserver { + + fun bind() { + + if (lifecycle.currentState == Lifecycle.State.DESTROYED) { + cancelDestroyed() + } else { + CoroutineScope(coroutineContext).launchMainImmediate { + + if (lifecycle.currentState == Lifecycle.State.DESTROYED) { + cancelDestroyed() + } else { + lifecycle.addObserver(this@LifecycleCoroutineScopeBinding) + } + } + } + coroutineContext[Job]?.invokeOnCompletion { + lifecycle.removeObserver(this) + } + } + + private fun cancelDestroyed() { + lifecycle.removeObserver(this) + coroutineContext.cancel( + LifecycleCancellationException( + lifecycle = lifecycle, + minimumState = Lifecycle.State.INITIALIZED + ) + ) + } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { + cancelDestroyed() + } + } +} + +internal class LifecycleCancellationException( + lifecycle: Lifecycle, + minimumState: Lifecycle.State +) : CancellationException("Lifecycle $lifecycle dropped below minimum state: $minimumState") diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleScopeExt.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/lifecycleCoroutineScope.kt similarity index 86% rename from dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleScopeExt.kt rename to dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/lifecycleCoroutineScope.kt index f66bd68b5..c35e49246 100644 --- a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/LifecycleScopeExt.kt +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/lifecycleCoroutineScope.kt @@ -24,20 +24,24 @@ import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* import java.util.concurrent.atomic.* +import kotlin.coroutines.* @Suppress("EXPERIMENTAL_API_USAGE") internal fun LifecycleCoroutineScope.launchOn( + context: CoroutineContext, minimumState: Lifecycle.State, statePolicy: LifecycleCoroutineScope.MinimumStatePolicy, block: suspend CoroutineScope.() -> Unit ): Job = when (statePolicy) { - CANCEL -> launch { lifecycle.onNext(minimumState, block) } - RESTART_EVERY -> launchEvery(minimumState, block) + CANCEL -> launch { lifecycle.onNext(context, minimumState, block) } + RESTART_EVERY -> launchEvery(context, minimumState, block) } @Suppress("EXPERIMENTAL_API_USAGE") internal suspend fun Lifecycle.onNext( - minimumState: Lifecycle.State, block: suspend CoroutineScope.() -> T + context: CoroutineContext, + minimumState: Lifecycle.State, + block: suspend CoroutineScope.() -> T ): T? { var result: T? = null @@ -49,7 +53,11 @@ internal suspend fun Lifecycle.onNext( .onEachLatest { stateIsHighEnough -> if (stateIsHighEnough) { stateReached.compareAndSet(false, true) - coroutineScope { result = block() } + coroutineScope { + withContext(context + coroutineContext[Job]!!) { + result = block() + } + } throw FlowCancellationException() } } @@ -65,7 +73,9 @@ internal suspend fun Lifecycle.onNext( @Suppress("EXPERIMENTAL_API_USAGE") internal fun LifecycleCoroutineScope.launchEvery( - minimumState: Lifecycle.State, block: suspend CoroutineScope.() -> Unit + context: CoroutineContext, + minimumState: Lifecycle.State, + block: suspend CoroutineScope.() -> Unit ): Job = lifecycle.eventFlow(minimumState) // Respond to every change in the Flow, cancelling execution of the previous onEach if it hasn't already finished. // This is responsible for cancelling Jobs when a Lifecycle.State dips below the threshold, @@ -76,7 +86,9 @@ internal fun LifecycleCoroutineScope.launchEvery( // Create a CoroutineScope which is tied to the receiver LifecycleCoroutineScope. // This new CoroutineScope will be automatically cancelled when the parent scope is cancelled, // or when onEachLatest executes for a new value. - coroutineScope { block() } + coroutineScope { + withContext(context + coroutineContext[Job]!!) { block() } + } } } // Use the receiver LifecycleCoroutineScope's Job, but ensure that this coroutine is launch immediately from Main. @@ -126,12 +138,11 @@ private suspend fun Flow.collectUntil( /** * Returns a flow which performs the given [action] on each value of the original flow. * - * * The crucial difference from [onEach] is that when the original flow emits a new value, the [action] block for previous * value is cancelled. */ @ExperimentalCoroutinesApi -private fun Flow.onEachLatest(action: suspend (T) -> Unit) = transformLatest { value -> +internal fun Flow.onEachLatest(action: suspend (T) -> Unit) = transformLatest { value -> action(value) return@transformLatest emit(value) } diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/viewLifecycleCoroutineScope.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/viewLifecycleCoroutineScope.kt new file mode 100644 index 000000000..b2f6e686e --- /dev/null +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/internal/viewLifecycleCoroutineScope.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle.internal + +import androidx.fragment.app.* +import androidx.lifecycle.* +import dispatch.android.lifecycle.* +import dispatch.core.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import kotlin.coroutines.* + +@ExperimentalCoroutinesApi +internal fun bindViewLifecycleCoroutineScope( + receiverScope: CoroutineScope, + fragment: Fragment, + block: ViewLifecycleCoroutineScope.() -> Unit +): Job { + + val observerJob = fragment.viewLifecycleOwnerLiveData.asFlow() + .onEachLatest { owner: LifecycleOwner? -> + + if (owner != null) { + + /* + Create a new ViewLifecycleCoroutineScope for each update to the LiveData. + + This new scope has the same CoroutineContext as the "receiverScope" parent, + except that its Job is automatically cancelled for each new LiveData event + without affecting the Job contained in the receiver scope. + */ + val viewScope = ViewLifecycleCoroutineScope( + lifecycle = owner.lifecycle, + coroutineContext = coroutineContext + ) + + viewScope.block() + + } + }.flowOnMainImmediate() + .launchIn(receiverScope) + + fragment.lifecycle.addObserver(LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_DESTROY) { + observerJob.cancel() + } + }) + + return observerJob +} + diff --git a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt similarity index 54% rename from dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt rename to dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt index 54bc3aedf..1c419bfad 100644 --- a/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt +++ b/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt @@ -18,76 +18,89 @@ package dispatch.android.lifecycle import androidx.lifecycle.* import dispatch.android.lifecycle.internal.* import kotlinx.coroutines.* +import kotlin.coroutines.* /** - * Executes [block] one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.CREATED]. + * Executes `block` one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.CREATED]. * - * If the lifecycle is already in this state, [block] will be executed immediately. + * If the lifecycle is already in this state, `block` will be executed immediately. * * @see [LifecycleCoroutineScope.launchOnCreate] for repeating behavior. + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @sample samples.LifecycleSuspendSample.lifecycleOwnerOnNextCreateSample */ suspend fun LifecycleOwner.onNextCreate( + context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T -): T? = lifecycle.onNext(Lifecycle.State.CREATED, block) +): T? = lifecycle.onNext(context, Lifecycle.State.CREATED, block) /** - * Executes [block] one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.CREATED]. + * Executes `block` one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.CREATED]. * - * If the lifecycle is already in this state, [block] will be executed immediately. + * If the lifecycle is already in this state, `block` will be executed immediately. * * @see [LifecycleCoroutineScope.launchOnCreate] for repeating behavior. + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @sample samples.LifecycleSuspendSample.lifecycleOnNextCreateSample */ suspend fun Lifecycle.onNextCreate( + context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T -): T? = onNext(Lifecycle.State.CREATED, block) +): T? = onNext(context, Lifecycle.State.CREATED, block) /** - * Executes [block] one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.STARTED]. + * Executes `block` one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.STARTED]. * - * If the lifecycle is already in this state, [block] will be executed immediately. + * If the lifecycle is already in this state, `block` will be executed immediately. * * @see [LifecycleCoroutineScope.launchOnStart] for repeating behavior. + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @sample samples.LifecycleSuspendSample.lifecycleOwnerOnNextStartSample */ suspend fun LifecycleOwner.onNextStart( + context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T -): T? = lifecycle.onNext(Lifecycle.State.STARTED, block) +): T? = lifecycle.onNext(context, Lifecycle.State.STARTED, block) /** - * Executes [block] one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.STARTED]. + * Executes `block` one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.STARTED]. * - * If the lifecycle is already in this state, [block] will be executed immediately. + * If the lifecycle is already in this state, `block` will be executed immediately. * * @see [LifecycleCoroutineScope.launchOnStart] for repeating behavior. + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @sample samples.LifecycleSuspendSample.lifecycleOnNextStartSample */ suspend fun Lifecycle.onNextStart( + context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T -): T? = onNext(Lifecycle.State.STARTED, block) +): T? = onNext(context, Lifecycle.State.STARTED, block) /** - * Executes [block] one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.RESUMED]. + * Executes `block` one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.RESUMED]. * - * If the lifecycle is already in this state, [block] will be executed immediately. + * If the lifecycle is already in this state, `block` will be executed immediately. * * @see [LifecycleCoroutineScope.launchOnResume] for repeating behavior. + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @sample samples.LifecycleSuspendSample.lifecycleOwnerOnNextResumeSample */ suspend fun LifecycleOwner.onNextResume( + context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T -): T? = lifecycle.onNext(Lifecycle.State.RESUMED, block) +): T? = lifecycle.onNext(context, Lifecycle.State.RESUMED, block) /** - * Executes [block] one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.RESUMED]. + * Executes `block` one time, the next time the [Lifecycle]'s state is at least [Lifecycle.State.RESUMED]. * - * If the lifecycle is already in this state, [block] will be executed immediately. + * If the lifecycle is already in this state, `block` will be executed immediately. * * @see [LifecycleCoroutineScope.launchOnResume] for repeating behavior. + * @param context *optional* - additional to [CoroutineScope.coroutineContext] context of the coroutine. * @sample samples.LifecycleSuspendSample.lifecycleOnNextResumeSample */ suspend fun Lifecycle.onNextResume( + context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T -): T? = onNext(Lifecycle.State.RESUMED, block) +): T? = onNext(context, Lifecycle.State.RESUMED, block) diff --git a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/LifecycleCoroutineScopeTest.kt b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/LifecycleCoroutineScopeTest.kt index 056d6914b..f968f44b1 100644 --- a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/LifecycleCoroutineScopeTest.kt +++ b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/LifecycleCoroutineScopeTest.kt @@ -16,36 +16,72 @@ package dispatch.android.lifecycle import androidx.lifecycle.* +import dispatch.core.* +import dispatch.internal.test.android.* import dispatch.test.* +import hermit.test.* +import hermit.test.junit.* import io.kotest.matchers.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* import org.junit.jupiter.api.* +import kotlin.coroutines.* @FlowPreview -@CoroutineTest @ExperimentalCoroutinesApi -class LifecycleCoroutineScopeTest( - val testScope: TestProvidedCoroutineScope -) { +class LifecycleCoroutineScopeTest : HermitJUnit5() { - lateinit var lifecycleOwner: LifecycleOwner - lateinit var lifecycle: LifecycleRegistry + val testScope by resets { TestProvidedCoroutineScope(context = Job()) } - lateinit var scope: LifecycleCoroutineScope + val lifecycleOwner by resets { FakeLifecycleOwner() } + val lifecycle by resets { lifecycleOwner.lifecycle } + val scope by resets { LifecycleCoroutineScope(lifecycle, testScope) } - @BeforeEach - fun beforeEach() { + @Nested + inner class cancellation { + + @Test + fun `scope with Job should cancel on init if lifecycle is destroyed`() = runBlocking { + + lifecycleOwner.destroy() - lifecycleOwner = LifecycleOwner { lifecycle } - lifecycle = LifecycleRegistry(lifecycleOwner) + val scope = LifecycleCoroutineScope(lifecycle, testScope) - scope = LifecycleCoroutineScope(lifecycle, testScope) + scope.isActive shouldBe false + } + + @Test + fun `scope should cancel when lifecycle is destroyed`() = runBlocking { + + lifecycleOwner.create() + + val scope = LifecycleCoroutineScope(lifecycle, testScope) + + scope.isActive shouldBe true + + lifecycleOwner.destroy() + + scope.isActive shouldBe false + } + + @Test + fun `lifecycle observer should be removed when scope is cancelled`() = runBlocking { + + lifecycleOwner.create() + + val scope = LifecycleCoroutineScope(lifecycle, testScope) + + lifecycle.observerCount shouldBe 1 + + scope.cancel() + + lifecycle.observerCount shouldBe 0 + } } @Nested - inner class `launch every create` { + inner class `launch on create` { @Test fun `block should immediately execute if already created`() = runBlocking { @@ -62,8 +98,6 @@ class LifecycleCoroutineScopeTest( @Test fun `block should not immediately execute if screen is not created`() = runBlocking { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) - var executed = false scope.launchOnCreate { executed = true } @@ -71,6 +105,20 @@ class LifecycleCoroutineScopeTest( executed shouldBe false } + @Test + fun `block context should respect context parameter`() = runBlocking { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + + var dispatcher: ContinuationInterceptor? = null + + scope.launchOnCreate(testScope.ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe testScope.ioDispatcher + } + @Test fun `block should stop when screen is destroyed`() = runBlocking { @@ -98,7 +146,7 @@ class LifecycleCoroutineScopeTest( } @Nested - inner class `launch every start` { + inner class `launch on start` { @Test fun `block should immediately execute if already started`() = runBlocking { @@ -136,6 +184,20 @@ class LifecycleCoroutineScopeTest( } } + @Test + fun `block context should respect context parameter`() = runBlocking { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) + + var dispatcher: ContinuationInterceptor? = null + + scope.launchOnStart(testScope.ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe testScope.ioDispatcher + } + @Test fun `block should stop when screen is stopped`() = runBlocking { @@ -163,7 +225,7 @@ class LifecycleCoroutineScopeTest( } @Nested - inner class `launch every resume` { + inner class `launch on resume` { @Test fun `block should immediately execute if already resumed`() = runBlocking { @@ -203,6 +265,20 @@ class LifecycleCoroutineScopeTest( } } + @Test + fun `block context should respect context parameter`() = runBlocking { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) + + var dispatcher: ContinuationInterceptor? = null + + scope.launchOnResume(testScope.ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe testScope.ioDispatcher + } + @Test fun `block should stop when screen is paused`() = runBlocking { diff --git a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextCreateTest.kt b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextCreateTest.kt index 65230a06c..e30fd4e98 100644 --- a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextCreateTest.kt +++ b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextCreateTest.kt @@ -16,6 +16,7 @@ package dispatch.android.lifecycle import androidx.lifecycle.* +import dispatch.core.* import dispatch.internal.test.* import dispatch.test.* import io.kotest.matchers.* @@ -24,6 +25,7 @@ import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.* import org.junit.jupiter.api.* +import kotlin.coroutines.* @FlowPreview @ExperimentalCoroutinesApi @@ -141,6 +143,20 @@ class OnNextCreateTest : BaseTest() { resultDeferred.await() shouldBe null } + + @Test + fun `block context should respect context parameter`() = testProvided { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + + var dispatcher: ContinuationInterceptor? = null + + lifecycle.onNextCreate(ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe ioDispatcher + } } @Nested @@ -153,7 +169,7 @@ class OnNextCreateTest : BaseTest() { var executed = false - launch { lifecycle.onNextCreate { executed = true } } + launch { lifecycleOwner.onNextCreate { executed = true } } executed shouldBe true } @@ -165,7 +181,7 @@ class OnNextCreateTest : BaseTest() { var executed = false - val job = launch { lifecycle.onNextCreate { executed = true } } + val job = launch { lifecycleOwner.onNextCreate { executed = true } } executed shouldBe false @@ -182,7 +198,7 @@ class OnNextCreateTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) launch { - lifecycle.onNextCreate { + lifecycleOwner.onNextCreate { input.consumeAsFlow() .onCompletion { completed = true } .collect { output.add(it) } @@ -204,7 +220,7 @@ class OnNextCreateTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - lifecycle.onNextCreate { expect(1) } + lifecycleOwner.onNextCreate { expect(1) } lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) @@ -220,7 +236,7 @@ class OnNextCreateTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - val result = lifecycle.onNextCreate { true } + val result = lifecycleOwner.onNextCreate { true } result shouldBe true } @@ -233,7 +249,7 @@ class OnNextCreateTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) val resultDeferred = async { - lifecycle.onNextCreate { + lifecycleOwner.onNextCreate { lock.withLock { // unreachable true @@ -245,5 +261,19 @@ class OnNextCreateTest : BaseTest() { resultDeferred.await() shouldBe null } + + @Test + fun `block context should respect context parameter`() = testProvided { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + + var dispatcher: ContinuationInterceptor? = null + + lifecycleOwner.onNextCreate(ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe ioDispatcher + } } } diff --git a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextResumeTest.kt b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextResumeTest.kt index 187a52403..f4ece5a31 100644 --- a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextResumeTest.kt +++ b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextResumeTest.kt @@ -16,6 +16,7 @@ package dispatch.android.lifecycle import androidx.lifecycle.* +import dispatch.core.* import dispatch.internal.test.* import dispatch.test.* import io.kotest.matchers.* @@ -24,6 +25,7 @@ import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.* import org.junit.jupiter.api.* +import kotlin.coroutines.* @FlowPreview @ExperimentalCoroutinesApi @@ -141,6 +143,20 @@ class OnNextResumeTest : BaseTest() { resultDeferred.await() shouldBe null } + + @Test + fun `block context should respect context parameter`() = testProvided { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) + + var dispatcher: ContinuationInterceptor? = null + + lifecycle.onNextResume(ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe ioDispatcher + } } @Nested @@ -153,7 +169,7 @@ class OnNextResumeTest : BaseTest() { var executed = false - launch { lifecycle.onNextResume { executed = true } } + launch { lifecycleOwner.onNextResume { executed = true } } executed shouldBe true } @@ -165,7 +181,7 @@ class OnNextResumeTest : BaseTest() { var executed = false - val job = launch { lifecycle.onNextResume { executed = true } } + val job = launch { lifecycleOwner.onNextResume { executed = true } } executed shouldBe false @@ -182,7 +198,7 @@ class OnNextResumeTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) launch { - lifecycle.onNextResume { + lifecycleOwner.onNextResume { input.consumeAsFlow() .onCompletion { completed = true } .collect { output.add(it) } @@ -204,7 +220,7 @@ class OnNextResumeTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) - lifecycle.onNextResume { expect(1) } + lifecycleOwner.onNextResume { expect(1) } lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) @@ -220,7 +236,7 @@ class OnNextResumeTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) - val result = lifecycle.onNextResume { true } + val result = lifecycleOwner.onNextResume { true } result shouldBe true } @@ -233,7 +249,7 @@ class OnNextResumeTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) val resultDeferred = async { - lifecycle.onNextResume { + lifecycleOwner.onNextResume { lock.withLock { // unreachable true @@ -245,5 +261,19 @@ class OnNextResumeTest : BaseTest() { resultDeferred.await() shouldBe null } + + @Test + fun `block context should respect context parameter`() = testProvided { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) + + var dispatcher: ContinuationInterceptor? = null + + lifecycleOwner.onNextResume(ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe ioDispatcher + } } } diff --git a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextStartTest.kt b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextStartTest.kt index 3155e449a..8190f5c3d 100644 --- a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextStartTest.kt +++ b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/OnNextStartTest.kt @@ -16,6 +16,7 @@ package dispatch.android.lifecycle import androidx.lifecycle.* +import dispatch.core.* import dispatch.internal.test.* import dispatch.test.* import io.kotest.matchers.* @@ -24,6 +25,7 @@ import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.* import org.junit.jupiter.api.* +import kotlin.coroutines.* @FlowPreview @ExperimentalCoroutinesApi @@ -141,6 +143,20 @@ class OnNextStartTest : BaseTest() { resultDeferred.await() shouldBe null } + + @Test + fun `block context should respect context parameter`() = testProvided { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) + + var dispatcher: ContinuationInterceptor? = null + + lifecycle.onNextStart(ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe ioDispatcher + } } @Nested @@ -153,7 +169,7 @@ class OnNextStartTest : BaseTest() { var executed = false - launch { lifecycle.onNextStart { executed = true } } + launch { lifecycleOwner.onNextStart { executed = true } } executed shouldBe true } @@ -165,7 +181,7 @@ class OnNextStartTest : BaseTest() { var executed = false - val job = launch { lifecycle.onNextStart { executed = true } } + val job = launch { lifecycleOwner.onNextStart { executed = true } } executed shouldBe false @@ -182,7 +198,7 @@ class OnNextStartTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) launch { - lifecycle.onNextStart { + lifecycleOwner.onNextStart { input.consumeAsFlow() .onCompletion { completed = true } .collect { output.add(it) } @@ -204,7 +220,7 @@ class OnNextStartTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) - lifecycle.onNextStart { expect(1) } + lifecycleOwner.onNextStart { expect(1) } lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) @@ -220,7 +236,7 @@ class OnNextStartTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) - val result = lifecycle.onNextStart { true } + val result = lifecycleOwner.onNextStart { true } result shouldBe true } @@ -233,7 +249,7 @@ class OnNextStartTest : BaseTest() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) val resultDeferred = async { - lifecycle.onNextStart { + lifecycleOwner.onNextStart { lock.withLock { // unreachable true @@ -245,5 +261,19 @@ class OnNextStartTest : BaseTest() { resultDeferred.await() shouldBe null } + + @Test + fun `block context should respect context parameter`() = testProvided { + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) + + var dispatcher: ContinuationInterceptor? = null + + lifecycleOwner.onNextStart(ioDispatcher) { + dispatcher = coroutineContext[ContinuationInterceptor] + } + + dispatcher shouldBe ioDispatcher + } } } diff --git a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt new file mode 100644 index 000000000..09c016e77 --- /dev/null +++ b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/ViewLifecycleScopeFlowCollectionTest.kt @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.arch.core.executor.testing.* +import dispatch.internal.test.android.* +import dispatch.test.* +import io.kotest.matchers.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import org.junit.* +import org.junit.runner.* +import org.robolectric.* +import org.robolectric.annotation.* + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +@ExperimentalCoroutinesApi +internal class ViewLifecycleScopeFlowCollectionTest { + + @JvmField + @Rule + val rule = TestCoroutineRule() + + @JvmField + @Rule + val instantTaskRule = InstantTaskExecutorRule() + + val fragmentLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + val viewLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + + @Before + fun setUp() { + fragmentLifecycleOwner.start() + viewLifecycleOwner.create() + } + + @Test + fun `launchOnCreate collection should only happen while at least CREATED`() = runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val flow = MutableStateFlow(0) + val collected = mutableListOf() + + + rule.withViewLifecycle(fragment) { + flow.onEach { collected.add(it) }.launchOnCreate() + } + + collected shouldBe listOf() + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.create() + + collected shouldBe listOf(0) + + flow.value = 1 + + collected shouldBe listOf(0, 1) + + viewLifecycleOwner.destroy() + + flow.value = 2 + + collected shouldBe listOf(0, 1) + } + + @Test + fun `launchOnStart collection should only happen while at least STARTED`() = runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val flow = MutableStateFlow(0) + val collected = mutableListOf() + + rule.withViewLifecycle(fragment) { + flow.onEach { collected.add(it) } + .launchOnStart() + } + + collected shouldBe listOf() + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.start() + + collected shouldBe listOf(0) + + flow.value = 1 + + collected shouldBe listOf(0, 1) + + viewLifecycleOwner.stop() + + flow.value = 2 + + collected shouldBe listOf(0, 1) + } + + @Test + fun `launchOnResume collection should only happen while RESUMED`() = runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val flow = MutableStateFlow(0) + val collected = mutableListOf() + + rule.withViewLifecycle(fragment) { + flow.onEach { collected.add(it) }.launchOnResume() + } + + collected shouldBe listOf() + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.resume() + + collected shouldBe listOf(0) + + flow.value = 1 + + collected shouldBe listOf(0, 1) + + viewLifecycleOwner.pause() + + flow.value = 2 + + collected shouldBe listOf(0, 1) + + } +} diff --git a/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/WithViewLifecycleTest.kt b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/WithViewLifecycleTest.kt new file mode 100644 index 000000000..136079aab --- /dev/null +++ b/dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/WithViewLifecycleTest.kt @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.android.lifecycle + +import androidx.arch.core.executor.testing.* +import dispatch.core.* +import dispatch.internal.test.* +import dispatch.internal.test.android.* +import dispatch.test.* +import io.kotest.matchers.* +import io.kotest.matchers.types.* +import kotlinx.coroutines.* +import org.junit.* +import org.junit.runner.* +import org.robolectric.* +import org.robolectric.annotation.* + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +@ExperimentalCoroutinesApi +internal class WithViewLifecycleTest { + + @JvmField + @Rule + val rule = TestCoroutineRule() + + @JvmField + @Rule + val instantTaskRule = InstantTaskExecutorRule() + + val fragmentLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + val viewLifecycleOwner = FakeLifecycleOwner(mainDispatcher = rule.dispatcherProvider.main) + + @Before + fun setUp() { + fragmentLifecycleOwner.start() + viewLifecycleOwner.create() + } + + @Test + fun `when the livedata goes from null to non-null, lambda should be invoked`() { + + var invocations = 0 + + val fragment = FakeFragment(fragmentLifecycleOwner) + + rule.withViewLifecycle(fragment) { invocations++ } + + invocations shouldBe 0 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 1 + } + + @Test + fun `when the livedata goes from null to non-null, lambda should be invoked every time`() { + + var invocations = 0 + + val fragment = FakeFragment(fragmentLifecycleOwner) + + rule.withViewLifecycle(fragment) { invocations++ } + + invocations shouldBe 0 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 1 + + fragment.setFakeViewLifecycleOwner(null) + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 2 + + fragment.setFakeViewLifecycleOwner(null) + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 3 + + } + + @Test + fun `when the livedata gets set to non-null, lambda should be invoked every time`() { + + var invocations = 0 + + val fragment = FakeFragment(fragmentLifecycleOwner) + + rule.withViewLifecycle(fragment) { invocations++ } + + invocations shouldBe 0 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 1 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 2 + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + invocations shouldBe 3 + + } + + @Test + fun `when the view lifecycle is destroyed, lambda should be cancelled`() { + + lateinit var job: Job + + val fragment = FakeFragment(fragmentLifecycleOwner) + + rule.withViewLifecycle(fragment) { + job = launch { + // never completes, so the Job should be active until the scope is destroyed + CompletableDeferred().await() + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.create() + viewLifecycleOwner.destroy() + + job.isCancelled shouldBe true + + } + + @Test + fun `when the fragment lifecycle is destroyed, lambda be cancelled`() { + + lateinit var job: Job + + val fragment = FakeFragment(fragmentLifecycleOwner) + + rule.withViewLifecycle(fragment) { + job = launch { + // never completes, so the Job should be active until the scope is destroyed + CompletableDeferred().await() + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + fragmentLifecycleOwner.create() + fragmentLifecycleOwner.destroy() + + job.isActive shouldBe false + + } + + @Test + fun `the lambda's LifecycleScope should correspond to the view lifecycle`() = runBlocking { + + lateinit var job: Job + + val fragment = FakeFragment(fragmentLifecycleOwner) + + rule.withViewLifecycle(fragment) { + job = launch { + + lifecycle shouldBeSameInstanceAs viewLifecycleOwner.lifecycle + + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + job.join() + + } + + @Test + fun `receiver CoroutineScope should not be cancelled when Fragment's lifecycle is destroyed`() = + runBlocking { + + /* + This extension creates a ViewLifecycleScope without knowing where the receiver CoroutineScope came from. + + It creates a child scope from the receiver, and that scope is automatically cancelled when the Fragment is destroyed, + but the source scope should be unchanged. + */ + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val receiverScope = + MainImmediateCoroutineScope(Job() + rule.coroutineContext) + + var internalScope: CoroutineScope? = null + + receiverScope.withViewLifecycle(fragment) { + launch { + + internalScope = this + + lifecycle shouldBeSameInstanceAs viewLifecycleOwner.lifecycle + + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.destroy() + fragmentLifecycleOwner.destroy() + internalScope!!.coroutineContext[Job]!!.isActive shouldBe false + + receiverScope.coroutineContext[Job]!!.isActive shouldBe true + } + + @Test + fun `receiver CoroutineScope and View scope contexts should be identical except for the Job`() = + runBlocking { + + val fragment = FakeFragment(fragmentLifecycleOwner) + + val receiverScope = + MainImmediateCoroutineScope(Job() + rule.coroutineContext) + + var internalScope: CoroutineScope? = null + + receiverScope.withViewLifecycle(fragment) { + launch { + + internalScope = this + + lifecycle shouldBeSameInstanceAs viewLifecycleOwner.lifecycle + + } + } + + fragment.setFakeViewLifecycleOwner(viewLifecycleOwner) + + viewLifecycleOwner.destroy() + fragmentLifecycleOwner.destroy() + + val receiverContext = receiverScope.coroutineContext + + val internalContext = internalScope!!.coroutineContext + + val internalJob = internalContext[Job]!! + + receiverContext shouldNotEqualFolded internalContext + + receiverContext + internalJob shouldEqualFolded internalContext + } + +} + diff --git a/dispatch-android-viewmodel/README.md b/dispatch-android-viewmodel/README.md index c94e4a7fc..7ea8e2d29 100644 --- a/dispatch-android-viewmodel/README.md +++ b/dispatch-android-viewmodel/README.md @@ -176,8 +176,8 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-viewmodel:1.0.0-beta04") } ``` diff --git a/dispatch-android-viewmodel/build.gradle.kts b/dispatch-android-viewmodel/build.gradle.kts index be6b3784d..491f0b008 100644 --- a/dispatch-android-viewmodel/build.gradle.kts +++ b/dispatch-android-viewmodel/build.gradle.kts @@ -54,6 +54,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) testImplementation(Libs.Kotlinx.Coroutines.test) diff --git a/dispatch-android-viewmodel/samples/build.gradle.kts b/dispatch-android-viewmodel/samples/build.gradle.kts index 253cce72c..983f0c0f3 100644 --- a/dispatch-android-viewmodel/samples/build.gradle.kts +++ b/dispatch-android-viewmodel/samples/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/CoroutineViewModelTest.kt b/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/CoroutineViewModelTest.kt index 077782843..c50d465aa 100644 --- a/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/CoroutineViewModelTest.kt +++ b/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/CoroutineViewModelTest.kt @@ -81,7 +81,7 @@ internal class CoroutineViewModelTest { val scope = TestViewModel().viewModelScope - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() scope.coroutineContext[Job]!!.shouldBeSupervisorJob() diff --git a/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/ViewModelScopeFactoryTest.kt b/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/ViewModelScopeFactoryTest.kt index b2c0da7b4..9ce690188 100644 --- a/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/ViewModelScopeFactoryTest.kt +++ b/dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/ViewModelScopeFactoryTest.kt @@ -58,7 +58,7 @@ internal class ViewModelScopeFactoryTest { val scope = ViewModelScopeFactory.create() - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() scope.coroutineContext[Job]!!.shouldBeSupervisorJob() @@ -90,7 +90,7 @@ internal class ViewModelScopeFactoryTest { val default = ViewModelScopeFactory.create() - default.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + default.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() default.coroutineContext[Job]!!.shouldBeSupervisorJob() diff --git a/dispatch-core/README.md b/dispatch-core/README.md index 40382b851..b939f7c33 100644 --- a/dispatch-core/README.md +++ b/dispatch-core/README.md @@ -60,6 +60,9 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { * [Async](#async) * [WithContext](#withcontext) * [Flow](#flow) +* [DefaultDispatcherProvider](#defaultdispatcherprovider) + * [Out-of-box default functionality](#out-of-box-default-functionality) + * [Easy global dispatcher overrides](#easy-global-dispatcher-overrides) * [Minimum Gradle Config](#minimum-gradle-config) @@ -69,8 +72,7 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { | **Name** | **Description** | ------------- | --------------- | | [DispatcherProvider] | Interface which provides the 5 standard [CoroutineDispatcher] properties of the [Dispatchers] object, but which can be embedded in a [CoroutineContext] -| [DefaultDispatcherProvider] | Default implementation of [DispatcherProvider] which simply delegates to the corresponding properties in the [Dispatchers] singleton - +| [DefaultDispatcherProvider] | Mutable singleton holder for an implementation of [DispatcherProvider]. By default, it simply delegates to the corresponding properties in the [Dispatchers] singleton. Whenever a [CoroutineContext] does not have a [DispatcherProvider], this singleton's value will be used by default. ### Marker interfaces and factories @@ -91,8 +93,6 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { | `suspend T` | [withDefault] | [withIO] | [withMain] | [withMainImmediate] | [withUnconfined] | `Flow` | [flowOnDefault] | [flowOnIO] | [flowOnMain] | [flowOnMainImmediate] | [flowOnUnconfined] - - ### Launch ``` kotlin fun foo(scope: CoroutineScope) { @@ -131,6 +131,7 @@ suspend fun foo() { ``` ### Flow + Like [withContext], [Flow] typically doesn’t get a [CoroutineScope] of its own. They inherit the [coroutineContext][kotlin.coroutineContext] from the collector in a pattern called [context preservation][context_preservation]. These new operators maintain context preservation (*they’re forced to, actually*), and extract the [coroutineContext][kotlin.coroutineContext] from the collector. ``` kotlin @@ -142,6 +143,53 @@ val someFlow = flow { } .flowOnUnconfined() ``` +## DefaultDispatcherProvider + +The simplest way to get up and running with Dispatch. All library access to a +[CoroutineContext's][CoroutineContext] [DispatcherProvider] filters through a single extension +property: + +``` kotlin +public val CoroutineContext.dispatcherProvider: DispatcherProvider + get() = get(DispatcherProvider) ?: DefaultDispatcherProvider.get() +``` + +If the receiver does not have a `DispatcherProvider`, the value from [DefaultDispatcherProvider] +will be returned. In practice, this brings at least two benefits: + +### Out-of-box default functionality + +Calls such as `launchIO { ... }`or `withMain { ... }` are safe to use (guaranteed to have a +`DispatcherProvider`) regardless of the source of the `CoroutineContext` or [CoroutineScope] and +without any additional configuration. By default, they will access the corresponding +[CoroutineDispatchers][CoroutineDispatcher] from the [Dispatchers] singleton. + +### Easy global dispatcher overrides + +`DefaultDispatcherProvider` has similar +[set][DefaultDispatcherProvider.set]/[reset][DefaultDispatcherProvider.set] functionality to the +[Dispatchers.setMain]/[Dispatchers.resetMain] extensions in `kotlinx-coroutines-test`, except it +doesn't need to be confined to testing. + +You can use [DefaultDispatcherProvider.set] to globally set a custom implementation at the beginning +of an application's lifecycle, but the most likely use-case is certainly in testing. + +``` kotlin +@Test +fun `my test`() = runBlocking { + + DefaultDispatcherProvider.set(TestDispatcherProvider()) + + withMain { + // this would normally crash without using Dispatchers.setMain + // but "main" here comes from the TestDispatcherProvider created above -- not Dispatchers.Main + } + + DefaultDispatcherProvider.reset() // from dispatch-test +} +``` +> See [dispatch-test] and [TestDispatcherProvider] + ## Minimum Gradle Config Add to your module's `build.gradle.kts`: @@ -153,8 +201,8 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") } ``` @@ -193,14 +241,20 @@ dependencies { [flowOnMain]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/kotlinx.coroutines.flow.-flow/flow-on-main.html [flowOnMainImmediate]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/kotlinx.coroutines.flow.-flow/flow-on-main-immediate.html [flowOnUnconfined]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/kotlinx.coroutines.flow.-flow/flow-on-unconfined.html +[DefaultDispatcherProvider.set]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/set.html + + +[TestDispatcherProvider]: https://rbusarow.github.io/Dispatch/dispatch-test//dispatch.test/-test-dispatcher-provider/index.html - [context_preservation]: https://medium.com/@elizarov/execution-context-of-kotlin-flows-b8c151c9309b [CoroutineContext]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/ [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html [CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html [Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html +[dispatch-test]: https://rbusarow.github.io/Dispatch/dispatch-test//index.html +[Dispatchers.resetMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/reset-main.html +[Dispatchers.setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html [Dispatchers]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html [Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html [Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html diff --git a/dispatch-core/api/dispatch-core.api b/dispatch-core/api/dispatch-core.api index 2f5b29157..bf33275b4 100644 --- a/dispatch-core/api/dispatch-core.api +++ b/dispatch-core/api/dispatch-core.api @@ -42,18 +42,15 @@ public final class dispatch/core/CoroutineScopesKt { public abstract interface class dispatch/core/DefaultCoroutineScope : kotlinx/coroutines/CoroutineScope { } -public final class dispatch/core/DefaultDispatcherProvider : dispatch/core/DispatcherProvider { - public fun ()V - public fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public fun get (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element; - public fun getDefault ()Lkotlinx/coroutines/CoroutineDispatcher; - public fun getIo ()Lkotlinx/coroutines/CoroutineDispatcher; - public fun getKey ()Lkotlin/coroutines/CoroutineContext$Key; - public fun getMain ()Lkotlinx/coroutines/CoroutineDispatcher; - public fun getMainImmediate ()Lkotlinx/coroutines/CoroutineDispatcher; - public fun getUnconfined ()Lkotlinx/coroutines/CoroutineDispatcher; - public fun minusKey (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext; - public fun plus (Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext; +public final class dispatch/core/DefaultDispatcherProvider { + public static final field INSTANCE Ldispatch/core/DefaultDispatcherProvider; + public final fun get ()Ldispatch/core/DispatcherProvider; + public final synthetic fun invoke ()Ldispatch/core/DispatcherProvider; + public final fun set (Ldispatch/core/DispatcherProvider;)V +} + +public synthetic class dispatch/core/DefaultDispatcherProviderHolderRefVolatile { + public fun (Ljava/lang/Object;)V } public abstract interface class dispatch/core/DispatcherProvider : kotlin/coroutines/CoroutineContext$Element { @@ -69,16 +66,18 @@ public abstract interface class dispatch/core/DispatcherProvider : kotlin/corout public final class dispatch/core/DispatcherProvider$DefaultImpls { public static fun fold (Ldispatch/core/DispatcherProvider;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static fun get (Ldispatch/core/DispatcherProvider;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element; + public static fun getDefault (Ldispatch/core/DispatcherProvider;)Lkotlinx/coroutines/CoroutineDispatcher; + public static fun getIo (Ldispatch/core/DispatcherProvider;)Lkotlinx/coroutines/CoroutineDispatcher; public static fun getKey (Ldispatch/core/DispatcherProvider;)Lkotlin/coroutines/CoroutineContext$Key; + public static fun getMain (Ldispatch/core/DispatcherProvider;)Lkotlinx/coroutines/CoroutineDispatcher; + public static fun getMainImmediate (Ldispatch/core/DispatcherProvider;)Lkotlinx/coroutines/CoroutineDispatcher; + public static fun getUnconfined (Ldispatch/core/DispatcherProvider;)Lkotlinx/coroutines/CoroutineDispatcher; public static fun minusKey (Ldispatch/core/DispatcherProvider;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext; public static fun plus (Ldispatch/core/DispatcherProvider;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext; } public final class dispatch/core/DispatcherProvider$Key : kotlin/coroutines/CoroutineContext$Key { -} - -public final class dispatch/core/DispatcherProviderKt { - public static final fun DispatcherProvider ()Ldispatch/core/DispatcherProvider; + public final fun invoke ()Ldispatch/core/DispatcherProvider; } public final class dispatch/core/FlowKt { diff --git a/dispatch-core/build.gradle.kts b/dispatch-core/build.gradle.kts index 257536b25..68796f2c2 100644 --- a/dispatch-core/build.gradle.kts +++ b/dispatch-core/build.gradle.kts @@ -18,6 +18,7 @@ plugins { id(Plugins.kotlin) id(Plugins.mavenPublish) id(Plugins.dokka) + id(Plugins.atomicFu) } dependencies { @@ -27,6 +28,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) @@ -37,6 +39,8 @@ dependencies { testImplementation(Libs.Kotlinx.Coroutines.test) + testImplementation(Libs.RickBusarow.Hermit.junit5) + testImplementation(project(":dispatch-internal-test")) } diff --git a/dispatch-core/samples/build.gradle.kts b/dispatch-core/samples/build.gradle.kts index 3e8eef15a..e2a002b95 100644 --- a/dispatch-core/samples/build.gradle.kts +++ b/dispatch-core/samples/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-core/samples/test/samples/DefaultDispatcherProviderSample.kt b/dispatch-core/samples/test/samples/DefaultDispatcherProviderSample.kt new file mode 100644 index 000000000..24ada6f0c --- /dev/null +++ b/dispatch-core/samples/test/samples/DefaultDispatcherProviderSample.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package samples + +import dispatch.core.* +import io.kotest.matchers.* +import kotlinx.coroutines.* +import kotlinx.coroutines.test.* +import org.junit.jupiter.api.* + +@ObsoleteCoroutinesApi +@ExperimentalCoroutinesApi +class DefaultDispatcherProviderSample { + + val main = newSingleThreadContext("main") + + @BeforeEach + fun beforeEach() { + Dispatchers.setMain(main) + } + + @AfterEach + fun afterEach() { + Dispatchers.resetMain() + } + + @Sample + fun defaultDispatcherProviderSetSample() { + + val custom = CustomDispatcherProvider() + DefaultDispatcherProvider.set(custom) + + val scope = MainImmediateCoroutineScope() + + scope.mainImmediateDispatcher shouldBe custom.mainImmediate + DefaultDispatcherProvider.get().mainImmediate shouldBe custom.mainImmediate + } + + @Suppress("TestFunctionName") + private fun CustomDispatcherProvider(): DispatcherProvider = object : DispatcherProvider { + + override val default: CoroutineDispatcher = Dispatchers.Default + override val io: CoroutineDispatcher = Dispatchers.IO + override val main: CoroutineDispatcher get() = Dispatchers.Main + override val mainImmediate: CoroutineDispatcher get() = Dispatchers.Main.immediate + override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined + } +} diff --git a/dispatch-core/src/main/java/dispatch/core/Async.kt b/dispatch-core/src/main/java/dispatch/core/Async.kt index 5c7a0afa7..f044731c8 100644 --- a/dispatch-core/src/main/java/dispatch/core/Async.kt +++ b/dispatch-core/src/main/java/dispatch/core/Async.kt @@ -13,6 +13,8 @@ * limitations under the License. */ +@file:Suppress("DeferredIsResult") + package dispatch.core import kotlinx.coroutines.* diff --git a/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt b/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt index 417941f0c..be970ac89 100644 --- a/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt +++ b/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt @@ -20,72 +20,84 @@ import kotlin.coroutines.* /** * Extracts the **default** [CoroutineDispatcher] out of the [CoroutineScope], - * creating a new instance of a [DefaultDispatcherProvider] to provide one if necessary. + * using [DefaultDispatcherProvider.get] to provide one if necessary. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. + * + * @see CoroutineScope.dispatcherProvider */ public val CoroutineScope.defaultDispatcher: CoroutineDispatcher get() = dispatcherProvider.default /** * Extracts the **io** [CoroutineDispatcher] out of the [CoroutineScope], - * creating a new instance of a [DefaultDispatcherProvider] to provide one if necessary. + * using [DefaultDispatcherProvider.get] to provide one if necessary. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. + * + * @see CoroutineScope.dispatcherProvider */ public val CoroutineScope.ioDispatcher: CoroutineDispatcher get() = dispatcherProvider.io /** * Extracts the **main** [CoroutineDispatcher] out of the [CoroutineScope], - * creating a new instance of a [DefaultDispatcherProvider] to provide one if necessary. + * using [DefaultDispatcherProvider.get] to provide one if necessary. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. + * + * @see CoroutineScope.dispatcherProvider */ public val CoroutineScope.mainDispatcher: CoroutineDispatcher get() = dispatcherProvider.main /** * Extracts the **mainImmediate** [CoroutineDispatcher] out of the [CoroutineScope], - * creating a new instance of a [DefaultDispatcherProvider] to provide one if necessary. + * using [DefaultDispatcherProvider.get] to provide one if necessary. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. + * + * @see CoroutineScope.dispatcherProvider */ public val CoroutineScope.mainImmediateDispatcher: CoroutineDispatcher get() = dispatcherProvider.mainImmediate /** * Extracts the **unconfined** [CoroutineDispatcher] out of the [CoroutineScope], - * creating a new instance of a [DefaultDispatcherProvider] to provide one if necessary. + * using [DefaultDispatcherProvider.get] to provide one if necessary. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. + * + * @see CoroutineScope.dispatcherProvider */ public val CoroutineScope.unconfinedDispatcher: CoroutineDispatcher get() = dispatcherProvider.unconfined /** * Extracts the [DispatcherProvider] out of the [CoroutineScope], - * or returns a new instance of a [DefaultDispatcherProvider] if the `coroutineContext` + * or returns a new instance of [DefaultDispatcherProvider.get] if the `coroutineContext` * does not have one specified. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. + * + * @see CoroutineContext.dispatcherProvider */ public val CoroutineScope.dispatcherProvider: DispatcherProvider get() = coroutineContext.dispatcherProvider /** * Extracts the [DispatcherProvider] out of the [CoroutineContext], - * or returns a new instance of a [DefaultDispatcherProvider] if the `CoroutineContext` + * or returns a default from [DefaultDispatcherProvider.get] if the `CoroutineContext` * does not have one specified. * * Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, * a new instance will be created each time. */ public val CoroutineContext.dispatcherProvider: DispatcherProvider - get() = get(DispatcherProvider) ?: DefaultDispatcherProvider() + get() = get(DispatcherProvider) ?: DefaultDispatcherProvider.get() diff --git a/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt b/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt index dfb991adb..4fe0a695d 100644 --- a/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt +++ b/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt @@ -50,13 +50,13 @@ public interface UnconfinedCoroutineScope : CoroutineScope * Dispatch defaults to the `default` property of the `DispatcherProvider`. * * @param job [Job] to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob] if one is not provided. - * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider] if one is not provided. + * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get] if one is not provided. * * @see CoroutineScope */ public fun DefaultCoroutineScope( job: Job = SupervisorJob(), - dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider() + dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider.get() ): DefaultCoroutineScope = object : DefaultCoroutineScope { override val coroutineContext = job + dispatcherProvider.default + dispatcherProvider } @@ -67,7 +67,7 @@ public fun DefaultCoroutineScope( * * @param coroutineContext [CoroutineContext] to be used for the resulting `CoroutineScope`. * Any existing [ContinuationInterceptor] will be overwritten. - * If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider] will be added. + * If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get] will be added. * * @see CoroutineScope */ @@ -82,13 +82,13 @@ public fun DefaultCoroutineScope( * Dispatch defaults to the `io` property of the `DispatcherProvider`. * * @param job [Job] to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob] if one is not provided. - * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider] if one is not provided. + * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get] if one is not provided. * * @see CoroutineScope */ public fun IOCoroutineScope( job: Job = SupervisorJob(), - dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider() + dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider.get() ): IOCoroutineScope = object : IOCoroutineScope { override val coroutineContext = job + dispatcherProvider.io + dispatcherProvider } @@ -99,7 +99,7 @@ public fun IOCoroutineScope( * * @param coroutineContext [CoroutineContext] to be used for the resulting `CoroutineScope`. * Any existing [ContinuationInterceptor] will be overwritten. - * If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider] will be added. + * If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get] will be added. * * @see CoroutineScope */ @@ -114,13 +114,13 @@ public fun IOCoroutineScope( * Dispatch defaults to the `main` property of the `DispatcherProvider`. * * @param job [Job] to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob] if one is not provided. - * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider] if one is not provided. + * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get] if one is not provided. * * @see CoroutineScope */ public fun MainCoroutineScope( job: Job = SupervisorJob(), - dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider() + dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider.get() ): MainCoroutineScope = object : MainCoroutineScope { override val coroutineContext = job + dispatcherProvider.main + dispatcherProvider } @@ -131,7 +131,7 @@ public fun MainCoroutineScope( * * @param coroutineContext [CoroutineContext] to be used for the resulting `CoroutineScope`. * Any existing [ContinuationInterceptor] will be overwritten. - * If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider] will be added. + * If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get] will be added. * * @see CoroutineScope */ @@ -146,13 +146,13 @@ public fun MainCoroutineScope( * Dispatch defaults to the `mainImmediate` property of the `DispatcherProvider`. * * @param job [Job] to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob] if one is not provided. - * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider] if one is not provided. + * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get] if one is not provided. * * @see CoroutineScope */ public fun MainImmediateCoroutineScope( - job: Job = SupervisorJob(), dispatcherProvider: - DispatcherProvider = DefaultDispatcherProvider() + job: Job = SupervisorJob(), + dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider.get() ): MainImmediateCoroutineScope = object : MainImmediateCoroutineScope { override val coroutineContext = job + dispatcherProvider.mainImmediate + dispatcherProvider @@ -164,7 +164,7 @@ public fun MainImmediateCoroutineScope( * * @param coroutineContext [CoroutineContext] to be used for the resulting `CoroutineScope`. * Any existing [ContinuationInterceptor] will be overwritten. - * If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider] will be added. + * If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get] will be added. * * @see CoroutineScope */ @@ -179,13 +179,13 @@ public fun MainImmediateCoroutineScope( * Dispatch defaults to the `unconfined` property of the `DispatcherProvider`. * * @param job [Job] to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob] if one is not provided. - * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider] if one is not provided. + * @param dispatcherProvider [DispatcherProvider] to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get] if one is not provided. * * @see CoroutineScope */ public fun UnconfinedCoroutineScope( job: Job = SupervisorJob(), - dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider() + dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider.get() ): UnconfinedCoroutineScope = object : UnconfinedCoroutineScope { override val coroutineContext = job + dispatcherProvider.unconfined + dispatcherProvider } @@ -196,7 +196,7 @@ public fun UnconfinedCoroutineScope( * * @param coroutineContext [CoroutineContext] to be used for the resulting `CoroutineScope`. * Any existing [ContinuationInterceptor] will be overwritten. - * If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider] will be added. + * If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get] will be added. * * @see CoroutineScope */ @@ -211,7 +211,7 @@ private inline fun CoroutineContext.withDefaultElements( ): CoroutineContext { val job = get(Job) ?: SupervisorJob() - val provider = get(DispatcherProvider) ?: DefaultDispatcherProvider() + val provider = get(DispatcherProvider) ?: DefaultDispatcherProvider.get() return this + job + provider + provider.dispatcherPromise() } diff --git a/dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt b/dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt new file mode 100644 index 000000000..a0202eabf --- /dev/null +++ b/dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.core + +import kotlinx.atomicfu.* +import kotlinx.coroutines.* + +/** + * Holder singleton for a [DispatcherProvider] instance. + * + * If [CoroutineScope.dispatcherProvider][dispatch.core.dispatcherProvider] or [CoroutineContext.dispatcherProvider][dispatch.core.dispatcherProvider] is referenced + * in a [CoroutineContext][kotlin.coroutines.CoroutineContext] which does not have one, + * it will use a default defined by this object. + * + * @sample samples.DefaultDispatcherProviderSample.defaultDispatcherProviderSetSample + */ +object DefaultDispatcherProvider { + + private val holder = atomic(default()) + + /** + * Returns the current configured default [DispatcherProvider] + * + * @see set + */ + fun get(): DispatcherProvider = holder.value + + /** + * Atomically sets a default [DispatcherProvider] instance. + * + * @see get + * @sample samples.DefaultDispatcherProviderSample.defaultDispatcherProviderSetSample + */ + fun set(value: DispatcherProvider) { + while (true) { + val cur = holder.value + if (holder.compareAndSet(cur, value)) return + } + } + + private fun default(): DispatcherProvider = object : DispatcherProvider {} + + /** + * Default implementation of [DispatcherProvider] which simply delegates to the corresponding + * properties in the [Dispatchers] singleton. + * + * This should be suitable for most production code. + * + * **Deprecated** + * The DefaultDispatcherProvider class has been replaced with this singleton object. + * To create a DispatcherProvider with the default implementation, use the DispatcherProvider companion object factory. + * This function will be removed before the 1.0 release. + * + * @see DispatcherProvider + */ + @Deprecated( + message = "The DefaultDispatcherProvider class has been replaced with this singleton object. " + + "To create a DispatcherProvider with the default implementation, use the DispatcherProvider companion object factory. " + + "This function will be removed before the 1.0 release.", + replaceWith = ReplaceWith("DispatcherProvider()"), + level = DeprecationLevel.HIDDEN + ) + operator fun invoke(): DispatcherProvider = DispatcherProvider() +} diff --git a/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt b/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt index 5cb021d32..03070eeb8 100644 --- a/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt +++ b/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt @@ -41,7 +41,7 @@ public interface DispatcherProvider : CoroutineContext.Element { * * @see Dispatchers.Default */ - val default: CoroutineDispatcher + val default: CoroutineDispatcher get() = Dispatchers.Default /** * [CoroutineDispatcher] generally intended for blocking I/O tasks. @@ -50,7 +50,7 @@ public interface DispatcherProvider : CoroutineContext.Element { * * @see Dispatchers.IO */ - val io: CoroutineDispatcher + val io: CoroutineDispatcher get() = Dispatchers.IO /** * [CoroutineDispatcher] which is confined to the "main" thread. @@ -59,7 +59,7 @@ public interface DispatcherProvider : CoroutineContext.Element { * * @see Dispatchers.Main */ - val main: CoroutineDispatcher + val main: CoroutineDispatcher get() = Dispatchers.Main /** * [CoroutineDispatcher] which is confined to the "main" thread with immediate dispatch. @@ -68,7 +68,7 @@ public interface DispatcherProvider : CoroutineContext.Element { * * @see MainCoroutineDispatcher.immediate */ - val mainImmediate: CoroutineDispatcher + val mainImmediate: CoroutineDispatcher get() = Dispatchers.Main.immediate /** * [CoroutineDispatcher] which is unconfined. @@ -77,32 +77,21 @@ public interface DispatcherProvider : CoroutineContext.Element { * * @see Dispatchers.Unconfined */ - val unconfined: CoroutineDispatcher + val unconfined: CoroutineDispatcher get() = Dispatchers.Unconfined /** * Unique [Key] definition which allows the `DispatcherProvider` to be stored in the [CoroutineContext]. */ - companion object Key : CoroutineContext.Key -} - -/** - * Creates a default implementation of [DispatcherProvider]. - * - * @see DefaultDispatcherProvider - */ -public fun DispatcherProvider(): DispatcherProvider = DefaultDispatcherProvider() - -/** - * Default implementation of [DispatcherProvider] which simply delegates to the corresponding - * properties in the [Dispatchers] singleton. - * - * This should be suitable for most production code. - */ -public class DefaultDispatcherProvider : DispatcherProvider { + companion object Key : CoroutineContext.Key { - override val default: CoroutineDispatcher = Dispatchers.Default - override val io: CoroutineDispatcher = Dispatchers.IO - override val main: CoroutineDispatcher get() = Dispatchers.Main - override val mainImmediate: CoroutineDispatcher get() = Dispatchers.Main.immediate - override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined + /** + * Default implementation of [DispatcherProvider] which simply delegates to the corresponding + * properties in the [Dispatchers] singleton. + * + * This should be suitable for most production code. + * + * @see DefaultDispatcherProvider + */ + operator fun invoke(): DispatcherProvider = DefaultDispatcherProvider.get() + } } diff --git a/dispatch-core/src/test/java/dispatch/core/CoroutineScopesTest.kt b/dispatch-core/src/test/java/dispatch/core/CoroutineScopesTest.kt index d9fc51779..04316f85c 100644 --- a/dispatch-core/src/test/java/dispatch/core/CoroutineScopesTest.kt +++ b/dispatch-core/src/test/java/dispatch/core/CoroutineScopesTest.kt @@ -17,7 +17,6 @@ package dispatch.core import dispatch.internal.test.* import io.kotest.matchers.* -import io.kotest.matchers.types.* import kotlinx.coroutines.* import kotlinx.coroutines.test.* import org.junit.jupiter.api.* @@ -73,7 +72,7 @@ internal class CoroutineScopesTest { val scope = DefaultCoroutineScope() - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -117,7 +116,7 @@ internal class CoroutineScopesTest { val scope = DefaultCoroutineScope(EmptyCoroutineContext) - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -165,7 +164,7 @@ internal class CoroutineScopesTest { val scope = IOCoroutineScope() - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -209,7 +208,7 @@ internal class CoroutineScopesTest { val scope = IOCoroutineScope(EmptyCoroutineContext) - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -256,7 +255,7 @@ internal class CoroutineScopesTest { val scope = MainCoroutineScope() - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -300,7 +299,7 @@ internal class CoroutineScopesTest { val scope = MainCoroutineScope(EmptyCoroutineContext) - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -349,7 +348,7 @@ internal class CoroutineScopesTest { val scope = MainImmediateCoroutineScope() - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -394,7 +393,7 @@ internal class CoroutineScopesTest { val scope = MainImmediateCoroutineScope(EmptyCoroutineContext) - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -441,7 +440,7 @@ internal class CoroutineScopesTest { val scope = UnconfinedCoroutineScope() - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test @@ -485,7 +484,7 @@ internal class CoroutineScopesTest { val scope = UnconfinedCoroutineScope(EmptyCoroutineContext) - scope.coroutineContext[DispatcherProvider]!!.shouldBeTypeOf() + scope.coroutineContext[DispatcherProvider] shouldBe DefaultDispatcherProvider.get() } @Test diff --git a/dispatch-core/src/test/java/dispatch/core/DispatcherProviderTest2.kt b/dispatch-core/src/test/java/dispatch/core/DispatcherProviderTest.kt similarity index 65% rename from dispatch-core/src/test/java/dispatch/core/DispatcherProviderTest2.kt rename to dispatch-core/src/test/java/dispatch/core/DispatcherProviderTest.kt index c8c1c9897..135bebf47 100644 --- a/dispatch-core/src/test/java/dispatch/core/DispatcherProviderTest2.kt +++ b/dispatch-core/src/test/java/dispatch/core/DispatcherProviderTest.kt @@ -16,7 +16,6 @@ package dispatch.core import io.kotest.matchers.* -import io.kotest.matchers.types.* import kotlinx.coroutines.* import kotlinx.coroutines.test.* import org.junit.jupiter.api.* @@ -73,42 +72,9 @@ internal class DispatcherProviderTest { @Test fun `DispatcherProvider factory should create DefaultDispatcherProvider`() { - DispatcherProvider().shouldBeTypeOf() + DispatcherProvider() shouldBe DefaultDispatcherProvider.get() } } - @Nested - inner class `Default DispatcherProvider` { - - @Test - fun `DefaultDispatcherProvider default dispatcher should use Dispatchers Default`() { - - DefaultDispatcherProvider().default shouldBe Dispatchers.Default - } - - @Test - fun `DefaultDispatcherProvider io dispatcher should use Dispatchers IO`() { - - DefaultDispatcherProvider().io shouldBe Dispatchers.IO - } - - @Test - fun `DefaultDispatcherProvider main dispatcher should use Dispatchers Main`() { - - DefaultDispatcherProvider().main shouldBe Dispatchers.Main - } - - @Test - fun `DefaultDispatcherProvider mainImmediate dispatcher should use Dispatchers Main immediate`() { - - DefaultDispatcherProvider().mainImmediate shouldBe Dispatchers.Main.immediate - } - - @Test - fun `DefaultDispatcherProvider unconfined dispatcher should use Dispatchers Unconfined`() { - - DefaultDispatcherProvider().unconfined shouldBe Dispatchers.Unconfined - } - } } diff --git a/dispatch-detekt/README.md b/dispatch-detekt/README.md index 66ee7ca9c..258eb685c 100644 --- a/dispatch-detekt/README.md +++ b/dispatch-detekt/README.md @@ -32,7 +32,7 @@ In root project-level `build.gradle` or `build.gradle.kts`: ``` kotlin allprojects { dependencies { - detekt("io.gitlab.arturbosch.detekt:detekt-cli:1.9.1") + detekt("io.gitlab.arturbosch.detekt:detekt-cli:1.10.0") detektPlugins("com.rickbusarow.dispatch:dispatch-detekt:1.0.0-beta04") } diff --git a/dispatch-detekt/build.gradle.kts b/dispatch-detekt/build.gradle.kts index 5f662234e..4f2c94c48 100644 --- a/dispatch-detekt/build.gradle.kts +++ b/dispatch-detekt/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { testImplementation(Libs.Detekt.test) testImplementation(Libs.JUnit.jUnit5Api) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-detekt/samples/build.gradle.kts b/dispatch-detekt/samples/build.gradle.kts index 7b3c599db..a13f2d64f 100644 --- a/dispatch-detekt/samples/build.gradle.kts +++ b/dispatch-detekt/samples/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-detekt/src/test/java/dispatch/detekt/rules/AndroidxLifecycleScopeUsageTest.kt b/dispatch-detekt/src/test/java/dispatch/detekt/rules/AndroidxLifecycleScopeUsageTest.kt index 222256d44..5fe3ed15e 100644 --- a/dispatch-detekt/src/test/java/dispatch/detekt/rules/AndroidxLifecycleScopeUsageTest.kt +++ b/dispatch-detekt/src/test/java/dispatch/detekt/rules/AndroidxLifecycleScopeUsageTest.kt @@ -124,6 +124,3 @@ internal class AndroidXLifecycleScopeTest : FreeSpec( findings shouldBe emptyList() } }) - - - diff --git a/dispatch-internal-test-android/api/dispatch-internal-test-android.api b/dispatch-internal-test-android/api/dispatch-internal-test-android.api new file mode 100644 index 000000000..26ceff729 --- /dev/null +++ b/dispatch-internal-test-android/api/dispatch-internal-test-android.api @@ -0,0 +1,33 @@ +public final class dispatch/internal/test/android/BuildConfig { + public static final field BUILD_TYPE Ljava/lang/String; + public static final field DEBUG Z + public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String; + public static final field VERSION_CODE I + public static final field VERSION_NAME Ljava/lang/String; + public fun ()V +} + +public class dispatch/internal/test/android/FakeFragment : androidx/fragment/app/Fragment { + public fun (Landroidx/lifecycle/LifecycleOwner;)V + public fun getLifecycle ()Landroidx/lifecycle/Lifecycle; + public fun getViewLifecycleOwner ()Landroidx/lifecycle/LifecycleOwner; + public fun getViewLifecycleOwnerLiveData ()Landroidx/lifecycle/LiveData; + public fun setFakeViewLifecycleOwner (Landroidx/lifecycle/LifecycleOwner;)V +} + +public class dispatch/internal/test/android/FakeLifecycleOwner : androidx/lifecycle/LifecycleOwner { + public fun ()V + public fun (Lkotlinx/coroutines/CoroutineDispatcher;Landroidx/lifecycle/Lifecycle$State;)V + public synthetic fun (Lkotlinx/coroutines/CoroutineDispatcher;Landroidx/lifecycle/Lifecycle$State;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun create ()V + public final fun destroy ()V + public synthetic fun getLifecycle ()Landroidx/lifecycle/Lifecycle; + public fun getLifecycle ()Landroidx/lifecycle/LifecycleRegistry; + public final fun getObserverCount ()I + public final fun initialize ()V + public final fun pause ()V + public final fun resume ()V + public final fun start ()V + public final fun stop ()V +} + diff --git a/dispatch-internal-test-android/build.gradle.kts b/dispatch-internal-test-android/build.gradle.kts new file mode 100644 index 000000000..a1efd7642 --- /dev/null +++ b/dispatch-internal-test-android/build.gradle.kts @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id(Plugins.androidLibrary) + id(Plugins.kotlinAndroid) + id(Plugins.kotlinAndroidExtensions) +} + +android { + compileSdkVersion(Versions.compileSdk) + + defaultConfig { + minSdkVersion(Versions.minSdk) + targetSdkVersion(Versions.targetSdk) + versionName = Versions.versionName + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + getByName("release") { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } +} +dependencies { + implementation(Libs.AndroidX.Fragment.core) + implementation(Libs.AndroidX.Lifecycle.common) + implementation(Libs.AndroidX.Lifecycle.runtime) + implementation(Libs.Kotlin.reflect) + implementation(Libs.Kotlin.stdlib) + implementation(Libs.Kotlinx.Coroutines.android) + implementation(Libs.Kotlinx.Coroutines.core) +} diff --git a/dispatch-internal-test-android/src/main/AndroidManifest.xml b/dispatch-internal-test-android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ef707610b --- /dev/null +++ b/dispatch-internal-test-android/src/main/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + diff --git a/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeFragment.java b/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeFragment.java new file mode 100644 index 000000000..28847084c --- /dev/null +++ b/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeFragment.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.internal.test.android; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import org.jetbrains.annotations.Nullable; + +public class FakeFragment extends Fragment { + + LifecycleOwner fragmentLifecycleOwner; + MutableLiveData fakeViewLifecycleOwnerLiveData = new MutableLiveData<>(null); + private LifecycleOwner fakeViewLifecycleOwner = null; + + public FakeFragment(LifecycleOwner fragmentLifecycleOwner) { + this.fragmentLifecycleOwner = fragmentLifecycleOwner; + } + + public void setFakeViewLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) { + fakeViewLifecycleOwner = lifecycleOwner; + fakeViewLifecycleOwnerLiveData.postValue(lifecycleOwner); + } + + @NonNull + @Override + public LifecycleOwner getViewLifecycleOwner() { + return fakeViewLifecycleOwner; + } + + @NonNull + @Override + public LiveData getViewLifecycleOwnerLiveData() { + return fakeViewLifecycleOwnerLiveData; + } + + @NonNull + @Override + public Lifecycle getLifecycle() { + return fragmentLifecycleOwner.getLifecycle(); + } + +} diff --git a/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycle.kt b/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycle.kt new file mode 100644 index 000000000..270db0a6f --- /dev/null +++ b/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycle.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.internal.test.android + +import androidx.lifecycle.* +import kotlinx.coroutines.channels.* + +class FakeLifecycle(lifecycleOwner: FakeLifecycleOwner) : Lifecycle() { + + val delegate = LifecycleRegistry(lifecycleOwner) + + val observerEvents = Channel(1200) + + val observerCount: Int get() = delegate.observerCount + + sealed class ObserverEvent { + abstract val observer: LifecycleObserver + + data class Add(override val observer: LifecycleObserver) : ObserverEvent() + data class Remove(override val observer: LifecycleObserver) : ObserverEvent() + } + + override fun addObserver(observer: LifecycleObserver) { + delegate.addObserver(observer) + observerEvents.sendBlocking(ObserverEvent.Add(observer)) + } + + override fun removeObserver(observer: LifecycleObserver) { + delegate.removeObserver(observer) + observerEvents.sendBlocking(ObserverEvent.Remove(observer)) + } + + override fun getCurrentState(): State = delegate.currentState + fun setCurrentState(state: State) { + delegate.currentState = state + } + + fun handleLifecycleEvent(event: Event) { + delegate.handleLifecycleEvent(event) + } + +} diff --git a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/FakeLifecycleOwner.kt b/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycleOwner.kt similarity index 64% rename from dispatch-android-lifecycle-extensions/samples/src/test/java/samples/FakeLifecycleOwner.kt rename to dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycleOwner.kt index f9cceec29..6acdfe3c2 100644 --- a/dispatch-android-lifecycle-extensions/samples/src/test/java/samples/FakeLifecycleOwner.kt +++ b/dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycleOwner.kt @@ -13,18 +13,18 @@ * limitations under the License. */ -package samples +package dispatch.internal.test.android import androidx.lifecycle.* import kotlinx.coroutines.* @Suppress("EXPERIMENTAL_API_USAGE") open class FakeLifecycleOwner( - private val mainDispatcher: CoroutineDispatcher = fakeMainDispatcher(), - initialState: Lifecycle.State = Lifecycle.State.INITIALIZED + initialState: Lifecycle.State = Lifecycle.State.INITIALIZED, + private val mainDispatcher: CoroutineDispatcher = fakeMainDispatcher() ) : LifecycleOwner { - private val registry: LifecycleRegistry by lazy { LifecycleRegistry(this) } + val fakeLifecycle: FakeLifecycle by lazy { FakeLifecycle(this) } init { when (initialState) { @@ -36,7 +36,25 @@ open class FakeLifecycleOwner( } } - override fun getLifecycle(): LifecycleRegistry = registry + override fun getLifecycle(): FakeLifecycle = fakeLifecycle + + fun stepDown() = when (lifecycle.currentState) { + Lifecycle.State.DESTROYED -> throw IllegalArgumentException("already destroyed") + Lifecycle.State.INITIALIZED -> throw IllegalArgumentException( + "cannot transition straight from initialized to destroyed" + ) + Lifecycle.State.CREATED -> destroy() + Lifecycle.State.STARTED -> stop() + Lifecycle.State.RESUMED -> pause() + } + + fun stepUp() = when (lifecycle.currentState) { + Lifecycle.State.DESTROYED -> throw IllegalArgumentException("already destroyed") + Lifecycle.State.INITIALIZED -> create() + Lifecycle.State.CREATED -> start() + Lifecycle.State.STARTED -> resume() + Lifecycle.State.RESUMED -> throw IllegalArgumentException("already resumed") + } fun create() = runBlocking(mainDispatcher) { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) @@ -66,7 +84,7 @@ open class FakeLifecycleOwner( lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) } - fun getObserverCount(): Int = runBlocking(mainDispatcher) { registry.observerCount } + fun getObserverCount(): Int = runBlocking(mainDispatcher) { fakeLifecycle.observerCount } } @Suppress("EXPERIMENTAL_API_USAGE") diff --git a/dispatch-internal-test-android/src/test/resources/junit-platform.properties b/dispatch-internal-test-android/src/test/resources/junit-platform.properties new file mode 100644 index 000000000..0e863bea1 --- /dev/null +++ b/dispatch-internal-test-android/src/test/resources/junit-platform.properties @@ -0,0 +1,15 @@ +# +# Copyright (C) 2020 Rick Busarow +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +junit.jupiter.testinstance.lifecycle.default=per_class diff --git a/dispatch-internal-test/build.gradle.kts b/dispatch-internal-test/build.gradle.kts index 0f595161f..1d3197118 100644 --- a/dispatch-internal-test/build.gradle.kts +++ b/dispatch-internal-test/build.gradle.kts @@ -20,6 +20,7 @@ plugins { } dependencies { + implementation(Libs.Kotlin.reflect) implementation(Libs.Kotlin.stdlib) implementation(Libs.Kotlinx.Coroutines.core) @@ -27,6 +28,7 @@ dependencies { implementation(Libs.JUnit.jUnit5) implementation(Libs.JUnit.jUnit5Vintage) implementation(Libs.Kotest.assertions) + implementation(Libs.Kotest.consoleRunner) implementation(Libs.Kotest.properties) implementation(Libs.Kotest.runner) diff --git a/dispatch-internal-test/src/main/java/dispatch/internal/test/Assertions.kt b/dispatch-internal-test/src/main/java/dispatch/internal/test/assertions.kt similarity index 77% rename from dispatch-internal-test/src/main/java/dispatch/internal/test/Assertions.kt rename to dispatch-internal-test/src/main/java/dispatch/internal/test/assertions.kt index 5540390f5..d0ece5e07 100644 --- a/dispatch-internal-test/src/main/java/dispatch/internal/test/Assertions.kt +++ b/dispatch-internal-test/src/main/java/dispatch/internal/test/assertions.kt @@ -16,6 +16,7 @@ package dispatch.internal.test import dispatch.core.* +import io.kotest.assertions.* import io.kotest.matchers.* import io.kotest.matchers.collections.* import kotlinx.coroutines.* @@ -47,3 +48,13 @@ infix fun CoroutineContext.shouldEqualFolded(other: CoroutineContext) { get(DispatcherProvider) shouldBe other[DispatcherProvider] } +infix fun CoroutineContext.shouldNotEqualFolded(other: CoroutineContext) { + shouldFail { + get(Job) shouldBeOrChildOf other[Job] + get(ContinuationInterceptor) shouldBe other[ContinuationInterceptor] + get(CoroutineExceptionHandler) shouldBe other[CoroutineExceptionHandler] + get(CoroutineName) shouldBe other[CoroutineName] + get(DispatcherProvider) shouldBe other[DispatcherProvider] + } +} + diff --git a/dispatch-internal-test/src/main/java/dispatch/internal/test/reflect.kt b/dispatch-internal-test/src/main/java/dispatch/internal/test/reflect.kt new file mode 100644 index 000000000..cf13c3644 --- /dev/null +++ b/dispatch-internal-test/src/main/java/dispatch/internal/test/reflect.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.internal.test + +import kotlin.reflect.full.* +import kotlin.reflect.jvm.* + +inline fun T.getPrivateObjectFieldByName(name: String): R { + + val kClass = T::class + + val property = kClass.members.find { it.name == name } + + require(property != null) { "Cannot find a property named `$name` in ${kClass::qualifiedName}." } + + property.isAccessible = true + + return property.call() as R +} + +inline fun T.getPrivateFieldByName(name: String): R { + + val kClass = T::class + + val property = kClass.memberProperties.find { it.name == name } + + require(property != null) { "Cannot find a property named `$name` in ${kClass::qualifiedName}." } + + property.isAccessible = true + + return property.get(this) as R +} diff --git a/dispatch-sample/build.gradle.kts b/dispatch-sample/build.gradle.kts index 7a896e303..5884f4fd2 100644 --- a/dispatch-sample/build.gradle.kts +++ b/dispatch-sample/build.gradle.kts @@ -66,6 +66,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit4) testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) testImplementation(Libs.Kotlinx.Coroutines.test) diff --git a/dispatch-sample/src/main/java/dispatch/sample/MainFragment.kt b/dispatch-sample/src/main/java/dispatch/sample/MainFragment.kt index be31d9c6e..155d4d543 100644 --- a/dispatch-sample/src/main/java/dispatch/sample/MainFragment.kt +++ b/dispatch-sample/src/main/java/dispatch/sample/MainFragment.kt @@ -15,11 +15,13 @@ package dispatch.sample +import android.annotation.* import android.content.* import android.os.* import android.view.* import androidx.fragment.app.* import androidx.lifecycle.* +import dispatch.android.lifecycle.* import dispatch.core.* import dispatch.sample.databinding.* import kotlinx.coroutines.* @@ -38,6 +40,26 @@ class MainFragment : Fragment() { } val viewModel: MainViewModel by viewModels { factory } + @SuppressLint("SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + scope.withViewLifecycle(this) { + + launchOnCreate { + + var count = 0 + + while (true) { + @Suppress("MagicNumber") + delay(1000) + binding.tvMessage.text = "new message with a count of ${++count}" + } + } + } + + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/dispatch-test-junit4/README.md b/dispatch-test-junit4/README.md index 67458558f..9abe9d0d6 100644 --- a/dispatch-test-junit4/README.md +++ b/dispatch-test-junit4/README.md @@ -71,13 +71,13 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 artifact also provides the dispatch-test artifact testImplementation("com.rickbusarow.dispatch:dispatch-test-junit4:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` @@ -95,14 +95,14 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 and junit5 artifacts also provides the dispatch-test artifact testImplementation("ccom.rickbusarow.dispatch:dispatch-test-junit4:1.0.0-beta03") testImplementation("ccom.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta03") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/dispatch-test-junit4/build.gradle.kts b/dispatch-test-junit4/build.gradle.kts index c02382e74..b990ea711 100644 --- a/dispatch-test-junit4/build.gradle.kts +++ b/dispatch-test-junit4/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { implementation(Libs.JUnit.jUnit4) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-test-junit4/samples/build.gradle.kts b/dispatch-test-junit4/samples/build.gradle.kts index 5bcb76da3..17b9ab59e 100644 --- a/dispatch-test-junit4/samples/build.gradle.kts +++ b/dispatch-test-junit4/samples/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit4) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-test-junit5/README.md b/dispatch-test-junit5/README.md index 45b4f0057..e095aacc1 100644 --- a/dispatch-test-junit5/README.md +++ b/dispatch-test-junit5/README.md @@ -101,13 +101,13 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit5 artifact also provides the dispatch-test artifact testImplementation("com.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") } ``` @@ -126,8 +126,8 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 and junit5 artifacts also provides the dispatch-test artifact @@ -135,7 +135,7 @@ dependencies { testImplementation("com.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta04") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") testImplementation("org.junit.vintage:junit-vintage-engine:5.6.2") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/dispatch-test-junit5/build.gradle.kts b/dispatch-test-junit5/build.gradle.kts index 59a191ab9..2e0e083f9 100644 --- a/dispatch-test-junit5/build.gradle.kts +++ b/dispatch-test-junit5/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { implementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-test-junit5/samples/build.gradle.kts b/dispatch-test-junit5/samples/build.gradle.kts index e97168792..ff675057e 100644 --- a/dispatch-test-junit5/samples/build.gradle.kts +++ b/dispatch-test-junit5/samples/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-test/README.md b/dispatch-test/README.md index 83ff9a9fc..e344c6be6 100644 --- a/dispatch-test/README.md +++ b/dispatch-test/README.md @@ -120,12 +120,12 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") testImplementation("com.rickbusarow.dispatch:dispatch-test:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/dispatch-test/api/dispatch-test.api b/dispatch-test/api/dispatch-test.api index ce4b1701d..50eb40c7f 100644 --- a/dispatch-test/api/dispatch-test.api +++ b/dispatch-test/api/dispatch-test.api @@ -6,6 +6,10 @@ public final class dispatch/test/BuildersKt { public static synthetic fun testProvided$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V } +public final class dispatch/test/DefaultDispatcherProviderKt { + public static final fun reset (Ldispatch/core/DefaultDispatcherProvider;)V +} + public final class dispatch/test/TestDispatcherProvider : dispatch/core/DispatcherProvider { public fun ()V public fun (Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineDispatcher;)V diff --git a/dispatch-test/build.gradle.kts b/dispatch-test/build.gradle.kts index 1d2cda897..5c800e241 100644 --- a/dispatch-test/build.gradle.kts +++ b/dispatch-test/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { implementation(Libs.JUnit.jUnit5) implementation(Libs.JUnit.jUnit5Vintage) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-test/samples/build.gradle.kts b/dispatch-test/samples/build.gradle.kts index 7b3c599db..a13f2d64f 100644 --- a/dispatch-test/samples/build.gradle.kts +++ b/dispatch-test/samples/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { testImplementation(Libs.JUnit.jUnit5) testImplementation(Libs.Kotest.assertions) + testImplementation(Libs.Kotest.consoleRunner) testImplementation(Libs.Kotest.properties) testImplementation(Libs.Kotest.runner) diff --git a/dispatch-test/samples/test/samples/DefaultDispatcherProviderSample.kt b/dispatch-test/samples/test/samples/DefaultDispatcherProviderSample.kt new file mode 100644 index 000000000..cc1759c32 --- /dev/null +++ b/dispatch-test/samples/test/samples/DefaultDispatcherProviderSample.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package samples + +import dispatch.core.* +import dispatch.test.* +import io.kotest.matchers.* +import kotlinx.coroutines.* +import kotlinx.coroutines.test.* +import org.junit.jupiter.api.* + +@ObsoleteCoroutinesApi +@ExperimentalCoroutinesApi +class DefaultDispatcherProviderExtensionSample { + + val main = newSingleThreadContext("main") + + @BeforeEach + fun beforeEach() { + Dispatchers.setMain(main) + } + + @AfterEach + fun afterEach() { + Dispatchers.resetMain() + } + + @Sample + fun defaultDispatcherProviderResetSample() { + + val custom = CustomDispatcherProvider() + DefaultDispatcherProvider.set(custom) + + DefaultDispatcherProvider.get() shouldBe custom + + DefaultDispatcherProvider.reset() + + val default = DefaultDispatcherProvider.get() + + default shouldNotBe custom + + default.default shouldBe Dispatchers.Default + default.io shouldBe Dispatchers.IO + default.main shouldBe Dispatchers.Main + default.mainImmediate shouldBe Dispatchers.Main.immediate + default.unconfined shouldBe Dispatchers.Unconfined + + } + + @Suppress("TestFunctionName") + private fun CustomDispatcherProvider(): DispatcherProvider = object : DispatcherProvider { + + override val default: CoroutineDispatcher = Dispatchers.Default + override val io: CoroutineDispatcher = Dispatchers.IO + override val main: CoroutineDispatcher get() = Dispatchers.Main + override val mainImmediate: CoroutineDispatcher get() = Dispatchers.Main.immediate + override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined + } +} diff --git a/dispatch-test/src/main/java/dispatch/test/defaultDispatcherProvider.kt b/dispatch-test/src/main/java/dispatch/test/defaultDispatcherProvider.kt new file mode 100644 index 000000000..1f7ce7970 --- /dev/null +++ b/dispatch-test/src/main/java/dispatch/test/defaultDispatcherProvider.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 Rick Busarow + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dispatch.test + +import dispatch.core.* + +/** + * Resets the singleton [DispatcherProvider] instance to the true default. + * This default instance delegates to the [Dispatchers][kotlinx.coroutines.Dispatchers] singleton object properties. + * + * @see DefaultDispatcherProvider + * @sample samples.DefaultDispatcherProviderExtensionSample.defaultDispatcherProviderResetSample + */ +@Suppress("unused") +fun DefaultDispatcherProvider.reset() { + set(object : DispatcherProvider {}) +} diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0e7b3bd97..f8613e6fd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,12 +2,37 @@ ## Version 1.0.0-beta04 +### Features +* [DefaultDispatcherProvider] is now a mutable singleton which allows for a custom global default. + ### Bug fixes +#### dispatch-test-junit5 * [CoroutineTestExtension] will now properly call `Dispatchers.setMain(...)` when injecting a CoroutineScope into a function or when not injecting at all. ([#130](https://github.com/RBusarow/Dispatch/issues/130)) +#### dispatch-android-lifecycle +* [LifecycleCoroutineScope] will now be automatically cancelled when the associated [Lifecycle][Android Lifecycle] drops to the [Destroyed][Android Lifecycle] state. + ([#135](https://github.com/RBusarow/Dispatch/issues/135)) + +#### dispatch-android-lifecycle-extensions +* Cached [LifecycleCoroutineScopes][LifecycleCoroutineScope] will now be removed from the cache when + they are destroyed. ([#136](https://github.com/RBusarow/Dispatch/issues/136)) +* Fixed a race condition where multiple [LifecycleCoroutineScopes][LifecycleCoroutineScope] may be + created for concurrent cache misses. ([#136](https://github.com/RBusarow/Dispatch/issues/136)) + +### Deprecations +* The [DefaultDispatcherProvider] class constructor has been changed to an object factory function + (`operator fun invoke(): DispatcherProvider`) and deprecated. This function will be removed prior + to the 1.0 release. + +### Breaking changes +* [DefaultDispatcherProvider] has been changed from a `class` to an `object`, and its functionality + changed. It is now a singleton holder for a default `DispatcherProvider` instance. To create a + default `DispatcherProvider`, use the interface's companion object factory function + (`DispatcherProvider()`). + ## Version 1.0.0-beta03 ### Renames @@ -52,6 +77,7 @@ +[DefaultDispatcherProvider]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/index.html [TestProvidedCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-test//dispatch.test/-test-provided-coroutine-scope/index.html @@ -64,6 +90,7 @@ +[LifecycleCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.html [lifecycleScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle-extensions//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.html @@ -72,6 +99,7 @@ [viewModelScope]: https://rbusarow.github.io/Dispatch/dispatch-android-viewmodel//dispatch.android.viewmodel/-coroutine-view-model/view-model-scope.html +[Android Lifecycle]: https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html [androidx-lifecycleScope]: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-runtime-ktx/src/main/java/androidx/lifecycle/Lifecycle.kt;l=44 [Detekt]: https://github.com/detekt/detekt [dispatch-android-espresso]: https://rbusarow.github.io/Dispatch/android-espresso//index.html diff --git a/docs/index.md b/docs/index.md index 57774b9b8..3adac5f26 100644 --- a/docs/index.md +++ b/docs/index.md @@ -361,8 +361,8 @@ dependencies { */ // core coroutines - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") // everything provides :core via "api", so you only need this if you have no other "implementation" dispatch artifacts implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") @@ -386,7 +386,7 @@ dependencies { */ // core coroutines-test - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") // you only need this if you don't have the -junit4 or -junit5 artifacts testImplementation("com.rickbusarow.dispatch:dispatch-test:1.0.0-beta04") @@ -480,9 +480,9 @@ limitations under the License. [LifecycleCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.html -[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.html -[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.html -[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.html +[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.html +[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.html +[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.html [onNextCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.html [onNextStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.html [onNextResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.html diff --git a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/-init-.md b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/-init-.md index d3618c171..9f826b4dd 100644 --- a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/-init-.md +++ b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/-init-.md @@ -75,9 +75,7 @@ class IdlingCoroutineScopeRuleWithLifecycleSample { @Before fun setUp() { - LifecycleScopeFactory.set { - MainImmediateCoroutineScope(customDispatcherProvider) - } + LifecycleScopeFactory.set { customDispatcherProvider } ViewModelScopeFactory.set { MainImmediateCoroutineScope(customDispatcherProvider) } diff --git a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/index.md b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/index.md index 6c44779c3..e13c829a9 100644 --- a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/index.md +++ b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider-rule/index.md @@ -75,9 +75,7 @@ class IdlingCoroutineScopeRuleWithLifecycleSample { @Before fun setUp() { - LifecycleScopeFactory.set { - MainImmediateCoroutineScope(customDispatcherProvider) - } + LifecycleScopeFactory.set { customDispatcherProvider } ViewModelScopeFactory.set { MainImmediateCoroutineScope(customDispatcherProvider) } diff --git a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider.md b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider.md index f48808452..5a60a2937 100644 --- a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider.md +++ b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider.md @@ -2,7 +2,7 @@ # IdlingDispatcherProvider -`fun IdlingDispatcherProvider(delegate: `[`DispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcherProvider.kt#L71) +`fun IdlingDispatcherProvider(delegate: `[`DispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcherProvider.kt#L71) [IdlingDispatcherProvider](-idling-dispatcher-provider/index.md) factory function, which creates an instance using an existing [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md). @@ -10,7 +10,7 @@ `delegate` - *optional* Use this [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md) to create a single [IdlingDispatcher](-idling-dispatcher/index.md) which is used as all properties for the [IdlingDispatcherProvider](-idling-dispatcher-provider/index.md). -Uses a [DefaultDispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md) if no instance provided. +Uses [DefaultDispatcherProvider.get](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-default-dispatcher-provider/get.md) if no instance provided. **See Also** diff --git a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/index.md b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/index.md index 6e08480e7..598e6d1b3 100644 --- a/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/index.md +++ b/docs/kdoc/dispatch-android-espresso/dispatch.android.espresso/index.md @@ -22,7 +22,7 @@ |---|---| | [DefaultIdlingCoroutineScope](-default-idling-coroutine-scope.md) | Factory function for a [DefaultIdlingCoroutineScope](-default-idling-coroutine-scope.md).`fun DefaultIdlingCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md)` = IdlingDispatcherProvider()): `[`DefaultIdlingCoroutineScope`](-default-idling-coroutine-scope.md) | | [IdlingCoroutineScope](-idling-coroutine-scope.md) | Factory function for an [IdlingCoroutineScope](-idling-coroutine-scope/index.md).`fun IdlingCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md)` = IdlingDispatcherProvider()): `[`IdlingCoroutineScope`](-idling-coroutine-scope/index.md) | -| [IdlingDispatcherProvider](-idling-dispatcher-provider.md) | [IdlingDispatcherProvider](-idling-dispatcher-provider/index.md) factory function, which creates an instance using an existing [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md).`fun IdlingDispatcherProvider(delegate: `[`DispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md) | +| [IdlingDispatcherProvider](-idling-dispatcher-provider.md) | [IdlingDispatcherProvider](-idling-dispatcher-provider/index.md) factory function, which creates an instance using an existing [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md).`fun IdlingDispatcherProvider(delegate: `[`DispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md) | | [IOIdlingCoroutineScope](-i-o-idling-coroutine-scope.md) | Factory function for an [IOIdlingCoroutineScope](-i-o-idling-coroutine-scope.md).`fun IOIdlingCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md)` = IdlingDispatcherProvider()): `[`IOIdlingCoroutineScope`](-i-o-idling-coroutine-scope.md) | | [MainIdlingCoroutineScope](-main-idling-coroutine-scope.md) | Factory function for a [MainIdlingCoroutineScope](-main-idling-coroutine-scope.md).`fun MainIdlingCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md)` = IdlingDispatcherProvider()): `[`MainIdlingCoroutineScope`](-main-idling-coroutine-scope.md) | | [MainImmediateIdlingCoroutineScope](-main-immediate-idling-coroutine-scope.md) | Factory function for a [MainImmediateIdlingCoroutineScope](-main-immediate-idling-coroutine-scope.md).`fun MainImmediateIdlingCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`IdlingDispatcherProvider`](-idling-dispatcher-provider/index.md)` = IdlingDispatcherProvider()): `[`MainImmediateIdlingCoroutineScope`](-main-immediate-idling-coroutine-scope.md) | diff --git a/docs/kdoc/dispatch-android-espresso/index.md b/docs/kdoc/dispatch-android-espresso/index.md index 068f0e8d3..4eee83460 100644 --- a/docs/kdoc/dispatch-android-espresso/index.md +++ b/docs/kdoc/dispatch-android-espresso/index.md @@ -84,8 +84,8 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") androidTestImplementation("com.rickbusarow.dispatch:dispatch-android-espresso:1.0.0-beta04") diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/alltypes/index.md b/docs/kdoc/dispatch-android-lifecycle-extensions/alltypes/index.md index d7660b82a..916c7369f 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/alltypes/index.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/alltypes/index.md @@ -8,6 +8,11 @@ |---|---| | (extensions in package dispatch.android.lifecycle) +##### [androidx.fragment.app.Fragment](../dispatch.android.lifecycle/androidx.fragment.app.-fragment/index.md) + + +| (extensions in package dispatch.android.lifecycle) + ##### [androidx.lifecycle.LifecycleOwner](../dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/index.md) diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/index.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/index.md index a2cc498ba..20d2fc528 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/index.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/index.md @@ -2,14 +2,17 @@ # LifecycleScopeFactory -`object LifecycleScopeFactory` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L33) +`object LifecycleScopeFactory` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L43) Factory holder for [LifecycleCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md)'s. -By default, `create` returns a [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md). +By default, `create` returns a [MainImmediateContext](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-main-immediate-context.md). This factory can be overridden for testing or to include a custom [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) -in production code. This may be done in [Application.onCreate](https://developer.android.com/reference/android/app/Application.html#onCreate()) +in production code. This may be done in [Application.onCreate](https://developer.android.com/reference/android/app/Application.html#onCreate()), +or else as early as possible in the Application's existence. + +A custom factory will persist for the application's full lifecycle unless overwritten or [reset](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-scope-factory/reset.md). [reset](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-scope-factory/reset.md) may be used to reset the factory to default at any time. @@ -17,7 +20,8 @@ in production code. This may be done in [Application.onCreate](https://develope class MyApplication : Application { override fun onCreate() { - LifecycleScopeFactory.set { MainImmediateCoroutineScope() } + + LifecycleScopeFactory.set { MyCustomElement() + MainImmediateContext() } } } ``` @@ -27,14 +31,25 @@ class MyEspressoTest { @Before fun setUp() { - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + + val dispatcherProvider = IdlingDispatcherProvider() + + LifecycleScopeFactory.set { SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate } } } ``` +**See Also** + +[MainImmediateContext](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-main-immediate-context.md) + +[LifecycleCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md) + +[LifecycleCoroutineScopeFactory](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md) + ### Functions | Name | Summary | |---|---| | [reset](reset.md) | Immediately resets the factory function to its default.`fun reset(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | -| [set](set.md) | Override the default [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) factory, for testing or to include a custom [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) in production code. This may be done in [Application.onCreate](https://developer.android.com/reference/android/app/Application.html#onCreate())`fun set(factory: () -> `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | +| [set](set.md) | Override the default [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) factory, for testing or to include a custom [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) in production code. This may be done in [Application.onCreate](https://developer.android.com/reference/android/app/Application.html#onCreate())`fun set(factory: `[`LifecycleCoroutineScopeFactory`](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
`fun set(factory: () -> `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/reset.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/reset.md index 336ba115e..715a007a1 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/reset.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/reset.md @@ -2,7 +2,7 @@ # reset -`fun reset(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L57) +`fun reset(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L59) Immediately resets the factory function to its default. @@ -11,7 +11,10 @@ class MyEspressoTest { @Before fun setUp() { - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + + val dispatcherProvider = DispatcherProvider() + + LifecycleScopeFactory.set { SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate } } @After diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/set.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/set.md index 3c07f9f6d..9a9d59542 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/set.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/set.md @@ -2,7 +2,8 @@ # set -`fun set(factory: () -> `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L46) +`fun set(factory: `[`LifecycleCoroutineScopeFactory`](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L78) +`fun set(factory: () -> `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScopeFactory.kt#L97) Override the default [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) factory, for testing or to include a custom [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) in production code. This may be done in [Application.onCreate](https://developer.android.com/reference/android/app/Application.html#onCreate()) @@ -11,7 +12,8 @@ in production code. This may be done in [Application.onCreate](https://develope class MyApplication : Application { override fun onCreate() { - LifecycleScopeFactory.set { MainImmediateCoroutineScope() } + + LifecycleScopeFactory.set { MyCustomElement() + MainImmediateContext() } } } ``` @@ -21,11 +23,15 @@ class MyEspressoTest { @Before fun setUp() { - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + + val dispatcherProvider = IdlingDispatcherProvider() + + LifecycleScopeFactory.set { SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate } } } ``` ### Parameters -`factory` - sets a custom [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) factory to be used for all new instance creations until reset. \ No newline at end of file +`factory` - sets a custom [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) factory to be used for all new instance creations until reset. +Its [Elements](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-element/index.html) will be re-used, except: \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/index.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/index.md new file mode 100644 index 000000000..f587a7d69 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/index.md @@ -0,0 +1,7 @@ +[dispatch-android-lifecycle-extensions](../../index.md) / [dispatch.android.lifecycle](../index.md) / [androidx.fragment.app.Fragment](./index.md) + +### Extensions for androidx.fragment.app.Fragment + +| Name | Summary | +|---|---| +| [withViewLifecycleScope](with-view-lifecycle-scope.md) | [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) helper for a [Fragment](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)'s [ViewLifecycleOwner](https://developer.android.com/reference/androidx/androidx/fragment/app/FragmentViewLifecycleOwner.html).`fun `[`Fragment`](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)`.withViewLifecycleScope(block: `[`ViewLifecycleCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/with-view-lifecycle-scope.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/with-view-lifecycle-scope.md new file mode 100644 index 000000000..db2b311cb --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.fragment.app.-fragment/with-view-lifecycle-scope.md @@ -0,0 +1,31 @@ +[dispatch-android-lifecycle-extensions](../../index.md) / [dispatch.android.lifecycle](../index.md) / [androidx.fragment.app.Fragment](index.md) / [withViewLifecycleScope](./with-view-lifecycle-scope.md) + +# withViewLifecycleScope + +`@ExperimentalCoroutinesApi fun `[`Fragment`](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)`.withViewLifecycleScope(block: `[`ViewLifecycleCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/withViewLifecycleScope.kt#L30) + +[CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) helper for a [Fragment](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)'s [ViewLifecycleOwner](https://developer.android.com/reference/androidx/androidx/fragment/app/FragmentViewLifecycleOwner.html). + +This function observes a `Fragment`'s [viewLifecycleOwnerLiveData](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html#getViewLifecycleOwnerLiveData()), +and invokes [block](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/with-view-lifecycle-scope/block.md). + +``` kotlin +class MyViewModel { + + val dataFlow = flow { + // ... + } +} + +class MyFragment : Fragment() { + + val myViewModel = MyViewModel() + + val observerJob = withViewLifecycleScope { + myViewModel.dataFlow.onEach { data -> + // ... + }.launchOnCreate() + } +} +``` + diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.md index dccaa185a..d2cde88d0 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.md @@ -2,7 +2,7 @@ # lifecycleScope -`val `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.lifecycleScope: `[`LifecycleCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/LifecycleScope.kt#L35) +`val `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.lifecycleScope: `[`LifecycleCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/lifecycleScope.kt#L36) [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) instance for the [LifecycleOwner](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html). By default, it uses the [Dispatchers.Main.immediate](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-coroutine-dispatcher/immediate.html) dispatcher. @@ -12,7 +12,8 @@ from the factory set in [LifecycleScopeFactory](https://rbusarow.github.io/Dispa The type of [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) created is configurable via [LifecycleScopeFactory.set](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-scope-factory/set.md). -The `viewModelScope` is automatically cancelled when the [LifecycleOwner](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)'s [lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html#getLifecycle())'s [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) drops to [Lifecycle.State.DESTROYED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#DESTROYED). +The `viewModelScope` is automatically cancelled when the [LifecycleOwner](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)'s +[lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html#getLifecycle())'s [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) drops to [Lifecycle.State.DESTROYED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#DESTROYED). ``` kotlin // This could be any LifecycleOwner -- Fragments, Activities, Services... diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/index.md b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/index.md index 95da18ebe..c95fdf682 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/index.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/index.md @@ -12,4 +12,5 @@ | Name | Summary | |---|---| +| [androidx.fragment.app.Fragment](androidx.fragment.app.-fragment/index.md) | | | [androidx.lifecycle.LifecycleOwner](androidx.lifecycle.-lifecycle-owner/index.md) | | diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/index.md b/docs/kdoc/dispatch-android-lifecycle-extensions/index.md index 99611cb84..e13036275 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/index.md +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/index.md @@ -48,7 +48,7 @@ class SomeApplication : Application() { override fun onCreate() { super.onCreate() // A custom factory can be set to add elements to the CoroutineContext - LifecycleScopeFactory.set { MainImmediateCoroutineScope() + SomeCustomElement() } + LifecycleScopeFactory.set { MainImmediateContext() + SomeCustomElement() } } } ``` @@ -59,7 +59,7 @@ class SomeEspressoTest { fun setUp() { // This custom factory can be used to use custom scopes for testing, // such as an idling dispatcher - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope().coroutineContext } } @After @@ -90,7 +90,7 @@ class SomeFragmentEspressoTest { fun setUp() { // set a custom factory which is applied to all newly created lifecycleScopes LifecycleScopeFactory.set { - MainImmediateCoroutineScope() + idlingRule.dispatcherProvider + MainImmediateContext() + idlingRule.dispatcherProvider } // now SomeFragment will use an IdlingDispatcher in its CoroutineScope @@ -136,10 +136,10 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-lifecycle-extensions:1.0.0-beta04") - + implementation("androidx.lifecycle:lifecycle-common:2.2.0") } ``` diff --git a/docs/kdoc/dispatch-android-lifecycle-extensions/package-list b/docs/kdoc/dispatch-android-lifecycle-extensions/package-list index 14d6dbc7f..8a2cf9385 100644 --- a/docs/kdoc/dispatch-android-lifecycle-extensions/package-list +++ b/docs/kdoc/dispatch-android-lifecycle-extensions/package-list @@ -1,4 +1,5 @@ $dokka.format:gfm $dokka.linkExtension:md $dokka.location:dispatch.android.lifecycle$lifecycleScope#androidx.lifecycle.LifecycleOwnerdispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/lifecycle-scope.md +$dokka.location:dispatch.android.lifecycle$withViewLifecycleScope(androidx.fragment.app.Fragment, kotlin.Function1((dispatch.android.lifecycle.ViewLifecycleCoroutineScope, kotlin.Unit)))dispatch.android.lifecycle/androidx.fragment.app.-fragment/with-view-lifecycle-scope.md dispatch.android.lifecycle diff --git a/docs/kdoc/dispatch-android-lifecycle/alltypes/index.md b/docs/kdoc/dispatch-android-lifecycle/alltypes/index.md index febfd574d..73b759f8d 100644 --- a/docs/kdoc/dispatch-android-lifecycle/alltypes/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/alltypes/index.md @@ -8,6 +8,11 @@ |---|---| | (extensions in package dispatch.android.lifecycle) +##### [kotlinx.coroutines.CoroutineScope](../dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/index.md) + + +| (extensions in package dispatch.android.lifecycle) + ##### [androidx.lifecycle.Lifecycle](../dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/index.md) @@ -15,7 +20,15 @@ ##### [dispatch.android.lifecycle.LifecycleCoroutineScope](../dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md) -[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) instance which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). +[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). + + +| + +##### [dispatch.android.lifecycle.LifecycleCoroutineScopeFactory](../dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md) + +Factory for [LifecycleCoroutineScope](../dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md)s. This may be injected into a lifecycle-aware class +to provide custom [CoroutineContexts](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). | (extensions in package dispatch.android.lifecycle) @@ -23,3 +36,10 @@ ##### [androidx.lifecycle.LifecycleOwner](../dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/index.md) +| + +##### [dispatch.android.lifecycle.ViewLifecycleCoroutineScope](../dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md) + +[LifecycleCoroutineScope](../dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md) instance which is tied to a [Fragment's](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html) View [lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). + + diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/-init-.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/-init-.md new file mode 100644 index 000000000..3bc5bdbe8 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/-init-.md @@ -0,0 +1,33 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [LifecycleCoroutineScopeFactory](index.md) / [<init>](./-init-.md) + +# <init> + +`LifecycleCoroutineScopeFactory(coroutineContextFactory: () -> `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`)` + +Factory for [LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md)s. This may be injected into a lifecycle-aware class +to provide custom [CoroutineContexts](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). + +``` kotlin +@Provides +fun provideFactory(): LifecycleCoroutineScopeFactory = LifecycleCoroutineScopeFactory { + // other elements are added automatically + MyCustomElement() +} + +class MyFragment @Inject constructor( + factory: LifecycleCoroutineScopeFactory +) : Fragment() { + + val lifecycleScope = factory.create(lifecycle) + + init { + lifecycleScope.launchOnStart { + // ... + } + } +} +``` + +### Parameters + +`coroutineContextFactory` - the lambda defining the creating of a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/create.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/create.md new file mode 100644 index 000000000..eaa1b14ee --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/create.md @@ -0,0 +1,11 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [LifecycleCoroutineScopeFactory](index.md) / [create](./create.md) + +# create + +`fun create(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`): `[`LifecycleCoroutineScope`](../-lifecycle-coroutine-scope/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScopeFactory.kt#L37) + +Creates a new [LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md) using `coroutineContextFactory` + +### Parameters + +`lifecycle` - the lifecycle which will be bound to the [LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md) \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md new file mode 100644 index 000000000..192699eab --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope-factory/index.md @@ -0,0 +1,45 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [LifecycleCoroutineScopeFactory](./index.md) + +# LifecycleCoroutineScopeFactory + +`class LifecycleCoroutineScopeFactory` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScopeFactory.kt#L28) + +Factory for [LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md)s. This may be injected into a lifecycle-aware class +to provide custom [CoroutineContexts](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). + +``` kotlin +@Provides +fun provideFactory(): LifecycleCoroutineScopeFactory = LifecycleCoroutineScopeFactory { + // other elements are added automatically + MyCustomElement() +} + +class MyFragment @Inject constructor( + factory: LifecycleCoroutineScopeFactory +) : Fragment() { + + val lifecycleScope = factory.create(lifecycle) + + init { + lifecycleScope.launchOnStart { + // ... + } + } +} +``` + +### Parameters + +`coroutineContextFactory` - the lambda defining the creating of a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) + +### Constructors + +| Name | Summary | +|---|---| +| [<init>](-init-.md) | Factory for [LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md)s. This may be injected into a lifecycle-aware class to provide custom [CoroutineContexts](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html).`LifecycleCoroutineScopeFactory(coroutineContextFactory: () -> `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`)` | + +### Functions + +| Name | Summary | +|---|---| +| [create](create.md) | Creates a new [LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md) using `coroutineContextFactory``fun create(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`): `[`LifecycleCoroutineScope`](../-lifecycle-coroutine-scope/index.md) | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-init-.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-init-.md index 9f26c5960..a6744126e 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-init-.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-init-.md @@ -2,33 +2,70 @@ # <init> -`LifecycleCoroutineScope(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`, coroutineScope: `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md)`)` +`LifecycleCoroutineScope(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`, coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = MainImmediateContext())` -[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) instance which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). +[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). The [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) provides lifecycle-aware [launch](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html) functions which will automatically start upon reaching their associated [Lifecycle.Event](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/Event.html), -then automatically cancel upon the [lifecycle](lifecycle.md) dropping below that state. Reaching +then automatically cancel upon the lifecycle dropping below that state. Reaching that state again will start a new [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). +This `CoroutineScope`'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) will be cancelled automatically +as soon as the `lifecycle` reaches [DESTROYED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#DESTROYED). + ``` kotlin runBlocking { // This could be any LifecycleOwner -- Fragments, Activities, Services... class SomeFragment : Fragment() { - init { + val lifecycleScope = LifecycleCoroutineScope(lifecycle) - // auto-created MainImmediateCoroutineScope which is lifecycle-aware - lifecycleScope //... + init { // active only when "resumed". starts a fresh coroutine each time + lifecycleScope.launchOnResume { } + + // active only when "started". starts a fresh coroutine each time // this is a rough proxy for LiveData behavior + lifecycleScope.launchOnStart { } + + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + + // launch when created, automatically stop on destroy + lifecycleScope.launchOnCreate { } + + // it works as a normal CoroutineScope as well (because it is) + lifecycleScope.launchMain { } + } + } + } +``` + +``` kotlin +runBlocking { + + // This could be any LifecycleOwner -- Fragments, Activities, Services... + class SomeFragment : Fragment() { + + val context = Job() + DispatcherProvider() + + val lifecycleScope = LifecycleCoroutineScope(lifecycle, context) + + init { + + // active only when "resumed". starts a fresh coroutine each time lifecycleScope.launchOnResume { } // active only when "started". starts a fresh coroutine each time + // this is a rough proxy for LiveData behavior lifecycleScope.launchOnStart { } + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + // launch when created, automatically stop on destroy lifecycleScope.launchOnCreate { } @@ -42,4 +79,7 @@ runBlocking { ### Parameters -`lifecycle` - the lifecycle to which this [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) is linked. \ No newline at end of file +`lifecycle` - the lifecycle to which this [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) is linked. + +`coroutineContext` - the source CoroutineContext which will be converted to a [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md). +Its [Elements](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-element/index.html) will be re-used, except: \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-c-a-n-c-e-l.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-c-a-n-c-e-l.md index 89943bb3d..7e195482d 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-c-a-n-c-e-l.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-c-a-n-c-e-l.md @@ -2,7 +2,7 @@ # CANCEL -`CANCEL` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L116) +`CANCEL` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L147) When using `CANCEL`, a coroutine will be created the first time the [lifecycle](../lifecycle.md) meets the minimum state, and cancelled upon dropping below it. diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md index d4aa696fb..60e921437 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md @@ -2,7 +2,7 @@ # RESTART_EVERY -`RESTART_EVERY` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L129) +`RESTART_EVERY` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L160) When using `RESTART_EVERY`, a coroutine will be created every time the [lifecycle](../lifecycle.md) meets the minimum state, and will be cancelled upon dropping below it. diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.md index f6a98ece8..a3031a448 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.md @@ -2,7 +2,7 @@ # MinimumStatePolicy -`enum class MinimumStatePolicy` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L106) +`enum class MinimumStatePolicy` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L137) Describes the way a particular [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) will behave if the [lifecycle](../lifecycle.md) passes below the minimum state before said [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) has completed. diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md index a1707b1f9..040253f86 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.md @@ -2,33 +2,70 @@ # LifecycleCoroutineScope -`class LifecycleCoroutineScope : `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L34) +`open class LifecycleCoroutineScope : `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L55) -[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) instance which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). +[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). The [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) provides lifecycle-aware [launch](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html) functions which will automatically start upon reaching their associated [Lifecycle.Event](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/Event.html), -then automatically cancel upon the [lifecycle](lifecycle.md) dropping below that state. Reaching +then automatically cancel upon the lifecycle dropping below that state. Reaching that state again will start a new [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). +This `CoroutineScope`'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) will be cancelled automatically +as soon as the `lifecycle` reaches [DESTROYED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#DESTROYED). + ``` kotlin runBlocking { // This could be any LifecycleOwner -- Fragments, Activities, Services... class SomeFragment : Fragment() { - init { + val lifecycleScope = LifecycleCoroutineScope(lifecycle) - // auto-created MainImmediateCoroutineScope which is lifecycle-aware - lifecycleScope //... + init { // active only when "resumed". starts a fresh coroutine each time + lifecycleScope.launchOnResume { } + + // active only when "started". starts a fresh coroutine each time // this is a rough proxy for LiveData behavior + lifecycleScope.launchOnStart { } + + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + + // launch when created, automatically stop on destroy + lifecycleScope.launchOnCreate { } + + // it works as a normal CoroutineScope as well (because it is) + lifecycleScope.launchMain { } + } + } + } +``` + +``` kotlin +runBlocking { + + // This could be any LifecycleOwner -- Fragments, Activities, Services... + class SomeFragment : Fragment() { + + val context = Job() + DispatcherProvider() + + val lifecycleScope = LifecycleCoroutineScope(lifecycle, context) + + init { + + // active only when "resumed". starts a fresh coroutine each time lifecycleScope.launchOnResume { } // active only when "started". starts a fresh coroutine each time + // this is a rough proxy for LiveData behavior lifecycleScope.launchOnStart { } + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + // launch when created, automatically stop on destroy lifecycleScope.launchOnCreate { } @@ -44,6 +81,9 @@ runBlocking { `lifecycle` - the lifecycle to which this [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) is linked. +`coroutineContext` - the source CoroutineContext which will be converted to a [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md). +Its [Elements](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-element/index.html) will be re-used, except: + ### Types | Name | Summary | @@ -54,7 +94,7 @@ runBlocking { | Name | Summary | |---|---| -| [<init>](-init-.md) | [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) instance which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`LifecycleCoroutineScope(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`, coroutineScope: `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md)`)` | +| [<init>](-init-.md) | [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`LifecycleCoroutineScope(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`, coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = MainImmediateContext())` | ### Properties @@ -66,6 +106,18 @@ runBlocking { | Name | Summary | |---|---| -| [launchOnCreate](launch-on-create.md) | Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED).`fun launchOnCreate(minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | -| [launchOnResume](launch-on-resume.md) | Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED).`fun launchOnResume(minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | -| [launchOnStart](launch-on-start.md) | Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED).`fun launchOnStart(minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | +| [launchOnCreate](launch-on-create.md) | Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED).`fun launchOnCreate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | +| [launchOnResume](launch-on-resume.md) | Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED).`fun launchOnResume(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | +| [launchOnStart](launch-on-start.md) | Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED).`fun launchOnStart(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | + +### Companion Object Functions + +| Name | Summary | +|---|---| +| [invoke](invoke.md) | [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`operator fun invoke(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`, coroutineScope: `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`): `[`LifecycleCoroutineScope`](./index.md) | + +### Inheritors + +| Name | Summary | +|---|---| +| [ViewLifecycleCoroutineScope](../-view-lifecycle-coroutine-scope/index.md) | [LifecycleCoroutineScope](./index.md) instance which is tied to a [Fragment's](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html) View [lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`class ViewLifecycleCoroutineScope : `[`LifecycleCoroutineScope`](./index.md) | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/invoke.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/invoke.md new file mode 100644 index 000000000..234b25f37 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/invoke.md @@ -0,0 +1,55 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [LifecycleCoroutineScope](index.md) / [invoke](./invoke.md) + +# invoke + +`operator fun invoke(lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`, coroutineScope: `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`): `[`LifecycleCoroutineScope`](index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L184) + +[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). + +The [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) provides lifecycle-aware [launch](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html) functions +which will automatically start upon reaching their associated [Lifecycle.Event](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/Event.html), +then automatically cancel upon the lifecycle dropping below that state. Reaching +that state again will start a new [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). + +If this `CoroutineScope` has a [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html), it will be cancelled automatically +as soon as the `lifecycle` reaches [DESTROYED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#DESTROYED). + +``` kotlin +runBlocking { + + // This could be any LifecycleOwner -- Fragments, Activities, Services... + class SomeFragment @Inject constructor( + coroutineScope: CoroutineScope // could be any type of CoroutineScope + ) : Fragment() { + + val lifecycleScope = LifecycleCoroutineScope(lifecycle, coroutineScope) + + init { + + // active only when "resumed". starts a fresh coroutine each time + lifecycleScope.launchOnResume { } + + // active only when "started". starts a fresh coroutine each time + // this is a rough proxy for LiveData behavior + lifecycleScope.launchOnStart { } + + // active after only the first "started" event, and never re-started + lifecycleScope.launchOnStart(minimumStatePolicy = CANCEL) { } + + // launch when created, automatically stop on destroy + lifecycleScope.launchOnCreate { } + + // it works as a normal CoroutineScope as well (because it is) + lifecycleScope.launchMain { } + + } + } + } +``` + +### Parameters + +`lifecycle` - the lifecycle to which this [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) is linked. + +`coroutineScope` - the source CoroutineScope which will be converted to a [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md). +Its [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) will be re-used, except: \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.md index 80c0e22b9..84ee95f6a 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.md @@ -2,15 +2,15 @@ # launchOnCreate -`fun launchOnCreate(minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L57) +`fun launchOnCreate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L83) Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED). -[block](launch-on-create.md#dispatch.android.lifecycle.LifecycleCoroutineScope$launchOnCreate(dispatch.android.lifecycle.LifecycleCoroutineScope.MinimumStatePolicy, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))/block) is executed using the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) as a parent, +`block` is executed using the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) as a parent, but always executes using [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html) as its [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html). -Execution of [block](launch-on-create.md#dispatch.android.lifecycle.LifecycleCoroutineScope$launchOnCreate(dispatch.android.lifecycle.LifecycleCoroutineScope.MinimumStatePolicy, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))/block) is cancelled when the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) is cancelled, +Execution of `block` is cancelled when the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) is cancelled, or when [lifecycle](lifecycle.md)'s [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) drops below [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED). ``` kotlin @@ -117,6 +117,8 @@ runBlocking { ### Parameters +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + `minimumStatePolicy` - *optional* - the way this [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) will behave when passing below the minimum state or re-entering. Uses [MinimumStatePolicy.RESTART_EVERY](-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md) by default. Note that for a normal Lifecycle, there is no returning from below a [CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED) state, diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.md index 57b557aac..b815b9de9 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.md @@ -2,15 +2,15 @@ # launchOnResume -`fun launchOnResume(minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L97) +`fun launchOnResume(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L127) Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED). -[block](launch-on-resume.md#dispatch.android.lifecycle.LifecycleCoroutineScope$launchOnResume(dispatch.android.lifecycle.LifecycleCoroutineScope.MinimumStatePolicy, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))/block) is executed using the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) as a parent, +`block` is executed using the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) as a parent, but always executes using [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html) as its [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html). -Execution of [block](launch-on-resume.md#dispatch.android.lifecycle.LifecycleCoroutineScope$launchOnResume(dispatch.android.lifecycle.LifecycleCoroutineScope.MinimumStatePolicy, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))/block) is cancelled when the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) is cancelled, +Execution of `block` is cancelled when the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) is cancelled, or when [lifecycle](lifecycle.md)'s [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) drops below [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED). ``` kotlin @@ -133,5 +133,7 @@ runBlocking { ### Parameters +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + `minimumStatePolicy` - *optional* - the way this [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) will behave when passing below the minimum state or re-entering. Uses [MinimumStatePolicy.RESTART_EVERY](-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md) by default. \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.md index 220a0ec17..0f9b302ec 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.md @@ -2,15 +2,15 @@ # launchOnStart -`fun launchOnStart(minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L77) +`fun launchOnStart(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, minimumStatePolicy: MinimumStatePolicy = MinimumStatePolicy.RESTART_EVERY, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L105) Lifecycle-aware function for launching a coroutine any time the [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED). -[block](launch-on-start.md#dispatch.android.lifecycle.LifecycleCoroutineScope$launchOnStart(dispatch.android.lifecycle.LifecycleCoroutineScope.MinimumStatePolicy, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))/block) is executed using the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) as a parent, +`block` is executed using the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)'s [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) as a parent, but always executes using [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html) as its [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html). -Execution of [block](launch-on-start.md#dispatch.android.lifecycle.LifecycleCoroutineScope$launchOnStart(dispatch.android.lifecycle.LifecycleCoroutineScope.MinimumStatePolicy, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))/block) is cancelled when the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) is cancelled, +Execution of `block` is cancelled when the receiver [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) is cancelled, or when [lifecycle](lifecycle.md)'s [Lifecycle.State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) drops below [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED). ``` kotlin @@ -133,5 +133,7 @@ runBlocking { ### Parameters +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + `minimumStatePolicy` - *optional* - the way this [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) will behave when passing below the minimum state or re-entering. Uses [MinimumStatePolicy.RESTART_EVERY](-minimum-state-policy/-r-e-s-t-a-r-t_-e-v-e-r-y.md) by default. \ No newline at end of file diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/lifecycle.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/lifecycle.md index 491e848ac..1bd8993c0 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/lifecycle.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-lifecycle-coroutine-scope/lifecycle.md @@ -2,7 +2,7 @@ # lifecycle -`val lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L35) +`val lifecycle: `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L56) the lifecycle to which this [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) is linked. diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-main-immediate-context.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-main-immediate-context.md new file mode 100644 index 000000000..9f2213da5 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-main-immediate-context.md @@ -0,0 +1,12 @@ +[dispatch-android-lifecycle](../index.md) / [dispatch.android.lifecycle](index.md) / [MainImmediateContext](./-main-immediate-context.md) + +# MainImmediateContext + +`fun MainImmediateContext(): `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleCoroutineScope.kt#L29) + +Default implementation of a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) as seen in a `MainImmediateCoroutineScope`. + +**See Also** + +[MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) + diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md new file mode 100644 index 000000000..206ec6630 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/index.md @@ -0,0 +1,15 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [ViewLifecycleCoroutineScope](./index.md) + +# ViewLifecycleCoroutineScope + +`class ViewLifecycleCoroutineScope : `[`LifecycleCoroutineScope`](../-lifecycle-coroutine-scope/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt#L28) + +[LifecycleCoroutineScope](../-lifecycle-coroutine-scope/index.md) instance which is tied to a [Fragment's](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html) View [lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html). + +### Functions + +| Name | Summary | +|---|---| +| [launchOnCreate](launch-on-create.md) | Every time the View [Lifecycle State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) reaches [CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED), create a new coroutine and collect this [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html).`fun `[`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)`.launchOnCreate(): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | +| [launchOnResume](launch-on-resume.md) | Every time the View [Lifecycle State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) reaches [RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED), create a new coroutine and collect this [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html).`fun `[`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)`.launchOnResume(): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | +| [launchOnStart](launch-on-start.md) | Every time the View [Lifecycle State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) reaches [STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED), create a new coroutine and collect this [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html).`fun `[`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)`.launchOnStart(): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.md new file mode 100644 index 000000000..64cd1395a --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.md @@ -0,0 +1,12 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [ViewLifecycleCoroutineScope](index.md) / [launchOnCreate](./launch-on-create.md) + +# launchOnCreate + +`fun `[`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)`.launchOnCreate(): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt#L38) + +Every time the View [Lifecycle State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) reaches [CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED), create a new coroutine and collect this [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html). + +**See Also** + +[kotlinx.coroutines.flow.launchIn](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html) + diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.md new file mode 100644 index 000000000..0be119488 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.md @@ -0,0 +1,12 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [ViewLifecycleCoroutineScope](index.md) / [launchOnResume](./launch-on-resume.md) + +# launchOnResume + +`fun `[`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)`.launchOnResume(): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt#L56) + +Every time the View [Lifecycle State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) reaches [RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED), create a new coroutine and collect this [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html). + +**See Also** + +[kotlinx.coroutines.flow.launchIn](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html) + diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.md new file mode 100644 index 000000000..624d68068 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.md @@ -0,0 +1,12 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [ViewLifecycleCoroutineScope](index.md) / [launchOnStart](./launch-on-start.md) + +# launchOnStart + +`fun `[`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)`.launchOnStart(): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt#L47) + +Every time the View [Lifecycle State](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html) reaches [STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED), create a new coroutine and collect this [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html). + +**See Also** + +[kotlinx.coroutines.flow.launchIn](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html) + diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/index.md index 51b1109a8..ec6a9696a 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/index.md @@ -4,6 +4,6 @@ | Name | Summary | |---|---| -| [onNextCreate](on-next-create.md) | Executes [block](on-next-create.md#dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED).`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextCreate(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | -| [onNextResume](on-next-resume.md) | Executes [block](on-next-resume.md#dispatch.android.lifecycle$onNextResume(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED).`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextResume(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | -| [onNextStart](on-next-start.md) | Executes [block](on-next-start.md#dispatch.android.lifecycle$onNextStart(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED).`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextStart(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | +| [onNextCreate](on-next-create.md) | Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED).`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextCreate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | +| [onNextResume](on-next-resume.md) | Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED).`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextResume(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | +| [onNextStart](on-next-start.md) | Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED).`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextStart(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.md index e5ef9fad5..a9cded00d 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.md @@ -2,11 +2,11 @@ # onNextCreate -`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextCreate(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt#L30) +`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextCreate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt#L32) -Executes [block](on-next-create.md#dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED). +Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED). -If the lifecycle is already in this state, [block](on-next-create.md#dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))/block) will be executed immediately. +If the lifecycle is already in this state, `block` will be executed immediately. ``` kotlin runBlocking { @@ -33,6 +33,10 @@ runBlocking { } ``` +### Parameters + +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + **See Also** [LifecycleCoroutineScope.launchOnCreate](../-lifecycle-coroutine-scope/launch-on-create.md) diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.md index d9fa235e2..65e9140b0 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.md @@ -2,11 +2,11 @@ # onNextResume -`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextResume(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt#L78) +`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextResume(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt#L88) -Executes [block](on-next-resume.md#dispatch.android.lifecycle$onNextResume(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED). +Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED). -If the lifecycle is already in this state, [block](on-next-resume.md#dispatch.android.lifecycle$onNextResume(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))/block) will be executed immediately. +If the lifecycle is already in this state, `block` will be executed immediately. ``` kotlin runBlocking { @@ -38,6 +38,10 @@ runBlocking { } ``` +### Parameters + +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + **See Also** [LifecycleCoroutineScope.launchOnResume](../-lifecycle-coroutine-scope/launch-on-resume.md) diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.md index 87283dc11..5484d2c56 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.md @@ -2,11 +2,11 @@ # onNextStart -`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextStart(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt#L54) +`suspend fun `[`LifecycleOwner`](https://developer.android.com/reference/androidx/androidx/lifecycle/LifecycleOwner.html)`.onNextStart(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt#L60) -Executes [block](on-next-start.md#dispatch.android.lifecycle$onNextStart(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED). +Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED). -If the lifecycle is already in this state, [block](on-next-start.md#dispatch.android.lifecycle$onNextStart(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))/block) will be executed immediately. +If the lifecycle is already in this state, `block` will be executed immediately. ``` kotlin runBlocking { @@ -38,6 +38,10 @@ runBlocking { } ``` +### Parameters + +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + **See Also** [LifecycleCoroutineScope.launchOnStart](../-lifecycle-coroutine-scope/launch-on-start.md) diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/index.md index 8f91992dd..a1a9ea3b5 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/index.md @@ -4,6 +4,6 @@ | Name | Summary | |---|---| -| [onNextCreate](on-next-create.md) | Executes [block](on-next-create.md#dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED).`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextCreate(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | -| [onNextResume](on-next-resume.md) | Executes [block](on-next-resume.md#dispatch.android.lifecycle$onNextResume(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED).`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextResume(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | -| [onNextStart](on-next-start.md) | Executes [block](on-next-start.md#dispatch.android.lifecycle$onNextStart(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED).`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextStart(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | +| [onNextCreate](on-next-create.md) | Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED).`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextCreate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | +| [onNextResume](on-next-resume.md) | Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED).`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextResume(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | +| [onNextStart](on-next-start.md) | Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED).`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextStart(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-create.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-create.md index 1dfbd6524..e48b34899 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-create.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-create.md @@ -2,11 +2,11 @@ # onNextCreate -`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextCreate(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt#L42) +`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextCreate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt#L46) -Executes [block](on-next-create.md#dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED). +Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#CREATED). -If the lifecycle is already in this state, [block](on-next-create.md#dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))/block) will be executed immediately. +If the lifecycle is already in this state, `block` will be executed immediately. ``` kotlin runBlocking { @@ -33,6 +33,10 @@ runBlocking { } ``` +### Parameters + +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + **See Also** [LifecycleCoroutineScope.launchOnCreate](../-lifecycle-coroutine-scope/launch-on-create.md) diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-resume.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-resume.md index 6154c39be..e7466d8d8 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-resume.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-resume.md @@ -2,11 +2,11 @@ # onNextResume -`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextResume(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt#L90) +`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextResume(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt#L102) -Executes [block](on-next-resume.md#dispatch.android.lifecycle$onNextResume(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED). +Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#RESUMED). -If the lifecycle is already in this state, [block](on-next-resume.md#dispatch.android.lifecycle$onNextResume(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))/block) will be executed immediately. +If the lifecycle is already in this state, `block` will be executed immediately. ``` kotlin runBlocking { @@ -38,6 +38,10 @@ runBlocking { } ``` +### Parameters + +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + **See Also** [LifecycleCoroutineScope.launchOnResume](../-lifecycle-coroutine-scope/launch-on-resume.md) diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-start.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-start.md index 18ec75c00..5a8438ac4 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-start.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-start.md @@ -2,11 +2,11 @@ # onNextStart -`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextStart(block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/LifecycleSuspendExt.kt#L66) +`suspend fun `[`Lifecycle`](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)`.onNextStart(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T?` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/suspend.kt#L74) -Executes [block](on-next-start.md#dispatch.android.lifecycle$onNextStart(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))/block) one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED). +Executes `block` one time, the next time the [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html)'s state is at least [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle/State.html#STARTED). -If the lifecycle is already in this state, [block](on-next-start.md#dispatch.android.lifecycle$onNextStart(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))/block) will be executed immediately. +If the lifecycle is already in this state, `block` will be executed immediately. ``` kotlin runBlocking { @@ -38,6 +38,10 @@ runBlocking { } ``` +### Parameters + +`context` - *optional* - additional to [CoroutineScope.coroutineContext](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html) context of the coroutine. + **See Also** [LifecycleCoroutineScope.launchOnStart](../-lifecycle-coroutine-scope/launch-on-start.md) diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/index.md index e975e3b4b..260848e87 100644 --- a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/index.md @@ -6,7 +6,9 @@ | Name | Summary | |---|---| -| [LifecycleCoroutineScope](-lifecycle-coroutine-scope/index.md) | [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) instance which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`class LifecycleCoroutineScope : `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) | +| [LifecycleCoroutineScope](-lifecycle-coroutine-scope/index.md) | [MainImmediateCoroutineScope](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) which is tied to a [Lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`open class LifecycleCoroutineScope : `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md) | +| [LifecycleCoroutineScopeFactory](-lifecycle-coroutine-scope-factory/index.md) | Factory for [LifecycleCoroutineScope](-lifecycle-coroutine-scope/index.md)s. This may be injected into a lifecycle-aware class to provide custom [CoroutineContexts](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html).`class LifecycleCoroutineScopeFactory` | +| [ViewLifecycleCoroutineScope](-view-lifecycle-coroutine-scope/index.md) | [LifecycleCoroutineScope](-lifecycle-coroutine-scope/index.md) instance which is tied to a [Fragment's](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html) View [lifecycle](https://developer.android.com/reference/androidx/androidx/lifecycle/Lifecycle.html).`class ViewLifecycleCoroutineScope : `[`LifecycleCoroutineScope`](-lifecycle-coroutine-scope/index.md) | ### Extensions for External Classes @@ -14,3 +16,10 @@ |---|---| | [androidx.lifecycle.Lifecycle](androidx.lifecycle.-lifecycle/index.md) | | | [androidx.lifecycle.LifecycleOwner](androidx.lifecycle.-lifecycle-owner/index.md) | | +| [kotlinx.coroutines.CoroutineScope](kotlinx.coroutines.-coroutine-scope/index.md) | | + +### Functions + +| Name | Summary | +|---|---| +| [MainImmediateContext](-main-immediate-context.md) | Default implementation of a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) as seen in a `MainImmediateCoroutineScope`.`fun MainImmediateContext(): `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/index.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/index.md new file mode 100644 index 000000000..d14241317 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/index.md @@ -0,0 +1,7 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [kotlinx.coroutines.CoroutineScope](./index.md) + +### Extensions for kotlinx.coroutines.CoroutineScope + +| Name | Summary | +|---|---| +| [withViewLifecycle](with-view-lifecycle.md) | [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) helper for a [Fragment](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)'s [ViewLifecycleOwner](https://developer.android.com/reference/androidx/androidx/fragment/app/FragmentViewLifecycleOwner.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.withViewLifecycle(fragment: `[`Fragment`](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)`, block: `[`ViewLifecycleCoroutineScope`](../-view-lifecycle-coroutine-scope/index.md)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | diff --git a/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/with-view-lifecycle.md b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/with-view-lifecycle.md new file mode 100644 index 000000000..d7dd9fb93 --- /dev/null +++ b/docs/kdoc/dispatch-android-lifecycle/dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/with-view-lifecycle.md @@ -0,0 +1,27 @@ +[dispatch-android-lifecycle](../../index.md) / [dispatch.android.lifecycle](../index.md) / [kotlinx.coroutines.CoroutineScope](index.md) / [withViewLifecycle](./with-view-lifecycle.md) + +# withViewLifecycle + +`@ExperimentalCoroutinesApi fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.withViewLifecycle(fragment: `[`Fragment`](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)`, block: `[`ViewLifecycleCoroutineScope`](../-view-lifecycle-coroutine-scope/index.md)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/ViewLifecycleCoroutineScope.kt#L70) + +[CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) helper for a [Fragment](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html)'s [ViewLifecycleOwner](https://developer.android.com/reference/androidx/androidx/fragment/app/FragmentViewLifecycleOwner.html). + +This function observes a `Fragment`'s [viewLifecycleOwnerLiveData](https://developer.android.com/reference/androidx/androidx/fragment/app/Fragment.html#getViewLifecycleOwnerLiveData()), +and invokes [block](with-view-lifecycle.md#dispatch.android.lifecycle$withViewLifecycle(kotlinx.coroutines.CoroutineScope, androidx.fragment.app.Fragment, kotlin.Function1((dispatch.android.lifecycle.ViewLifecycleCoroutineScope, kotlin.Unit)))/block). + +``` kotlin +class MyFragment @Inject constructor( + scope: MainImmediateCoroutineScope +) : Fragment() { + + val myViewModel by viewModels() + + val observerJob = scope.withViewLifecycle(this) { + // this lambda is invoked every time the View lifecycle is set + myViewModel.dataFlow.onEach { data -> + // ... + }.launchOnCreate() + } +} +``` + diff --git a/docs/kdoc/dispatch-android-lifecycle/index.md b/docs/kdoc/dispatch-android-lifecycle/index.md index a680d93ab..54127f820 100644 --- a/docs/kdoc/dispatch-android-lifecycle/index.md +++ b/docs/kdoc/dispatch-android-lifecycle/index.md @@ -20,9 +20,9 @@ | **Name** | **Description** | ------------- | --------------- | -| [launchOnCreate](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.html) | Creates a coroutine tied to a [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html) which will automatically enact a [MinimumStatePolicy](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html) upon dropping below [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State.html#CREATED) -| [launchOnStart](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.html) | Creates a coroutine tied to a [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html) which will automatically enact a [MinimumStatePolicy](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html) upon dropping below [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State.html#STARTED) -| [launchOnResume](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.html) | Creates a coroutine tied to a [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html) which will automatically enact a [MinimumStatePolicy](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html) upon dropping below [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State.html#RESUMED) +| [launchOnCreate](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.html) | Creates a coroutine tied to a [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html) which will automatically enact a [MinimumStatePolicy](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html) upon dropping below [Lifecycle.State.CREATED](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State.html#CREATED) +| [launchOnStart](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.html) | Creates a coroutine tied to a [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html) which will automatically enact a [MinimumStatePolicy](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html) upon dropping below [Lifecycle.State.STARTED](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State.html#STARTED) +| [launchOnResume](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.html) | Creates a coroutine tied to a [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.html) which will automatically enact a [MinimumStatePolicy](https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html) upon dropping below [Lifecycle.State.RESUMED](https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State.html#RESUMED) ## Extension functions @@ -53,10 +53,9 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-lifecycle:1.0.0-beta04") - implementation("androidx.lifecycle:lifecycle-common:2.2.0") } ``` diff --git a/docs/kdoc/dispatch-android-lifecycle/package-list b/docs/kdoc/dispatch-android-lifecycle/package-list index e11c2d2de..e9134a50a 100644 --- a/docs/kdoc/dispatch-android-lifecycle/package-list +++ b/docs/kdoc/dispatch-android-lifecycle/package-list @@ -1,9 +1,10 @@ $dokka.format:gfm $dokka.linkExtension:md -$dokka.location:dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-create.md -$dokka.location:dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.md -$dokka.location:dispatch.android.lifecycle$onNextResume(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-resume.md -$dokka.location:dispatch.android.lifecycle$onNextResume(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.md -$dokka.location:dispatch.android.lifecycle$onNextStart(androidx.lifecycle.Lifecycle, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-start.md -$dokka.location:dispatch.android.lifecycle$onNextStart(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.md +$dokka.location:dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.Lifecycle, kotlin.coroutines.CoroutineContext, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-create.md +$dokka.location:dispatch.android.lifecycle$onNextCreate(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.CoroutineContext, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextCreate.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.md +$dokka.location:dispatch.android.lifecycle$onNextResume(androidx.lifecycle.Lifecycle, kotlin.coroutines.CoroutineContext, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-resume.md +$dokka.location:dispatch.android.lifecycle$onNextResume(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.CoroutineContext, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextResume.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.md +$dokka.location:dispatch.android.lifecycle$onNextStart(androidx.lifecycle.Lifecycle, kotlin.coroutines.CoroutineContext, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle/on-next-start.md +$dokka.location:dispatch.android.lifecycle$onNextStart(androidx.lifecycle.LifecycleOwner, kotlin.coroutines.CoroutineContext, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, dispatch.android.lifecycle.onNextStart.T)))dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.md +$dokka.location:dispatch.android.lifecycle$withViewLifecycle(kotlinx.coroutines.CoroutineScope, androidx.fragment.app.Fragment, kotlin.Function1((dispatch.android.lifecycle.ViewLifecycleCoroutineScope, kotlin.Unit)))dispatch.android.lifecycle/kotlinx.coroutines.-coroutine-scope/with-view-lifecycle.md dispatch.android.lifecycle diff --git a/docs/kdoc/dispatch-android-viewmodel/index.md b/docs/kdoc/dispatch-android-viewmodel/index.md index 631449e97..e58b15d54 100644 --- a/docs/kdoc/dispatch-android-viewmodel/index.md +++ b/docs/kdoc/dispatch-android-viewmodel/index.md @@ -175,8 +175,8 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-viewmodel:1.0.0-beta04") } ``` diff --git a/docs/kdoc/dispatch-core/alltypes/index.md b/docs/kdoc/dispatch-core/alltypes/index.md index 31e4e9fc6..5043e0955 100644 --- a/docs/kdoc/dispatch-core/alltypes/index.md +++ b/docs/kdoc/dispatch-core/alltypes/index.md @@ -27,8 +27,7 @@ Marker interface which designates a [CoroutineScope](https://kotlin.github.io/ko ##### [dispatch.core.DefaultDispatcherProvider](../dispatch.core/-default-dispatcher-provider/index.md) -Default implementation of [DispatcherProvider](../dispatch.core/-dispatcher-provider/index.md) which simply delegates to the corresponding -properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. +Holder singleton for a [DispatcherProvider](../dispatch.core/-dispatcher-provider/index.md) instance. | diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-coroutine-scope.md b/docs/kdoc/dispatch-core/dispatch.core/-default-coroutine-scope.md index 6ff368a5a..3e4e18f48 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-coroutine-scope.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-default-coroutine-scope.md @@ -6,7 +6,7 @@ Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `default`. -`fun DefaultCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`DefaultCoroutineScope`](./-default-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L57) +`fun DefaultCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`DefaultCoroutineScope`](./-default-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L57) Factory function for a [DefaultCoroutineScope](./-default-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `default` property of the `DispatcherProvider`. @@ -15,7 +15,7 @@ Dispatch defaults to the `default` property of the `DispatcherProvider`. `job` - [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html) if one is not provided. -`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) if one is not provided. +`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) if one is not provided. **See Also** @@ -30,7 +30,7 @@ Dispatch defaults to the `default` property of the `DispatcherProvider`. `coroutineContext` - [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) to be used for the resulting `CoroutineScope`. Any existing [ContinuationInterceptor](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-continuation-interceptor/index.html) will be overwritten. -If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) will be added. +If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) will be added. **See Also** diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/-init-.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/-init-.md deleted file mode 100644 index 8002b1fc7..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/-init-.md +++ /dev/null @@ -1,11 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [<init>](./-init-.md) - -# <init> - -`DefaultDispatcherProvider()` - -Default implementation of [DispatcherProvider](../-dispatcher-provider/index.md) which simply delegates to the corresponding -properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. - -This should be suitable for most production code. - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/default.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/default.md deleted file mode 100644 index 0673eb289..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/default.md +++ /dev/null @@ -1,14 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [default](./default.md) - -# default - -`val default: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L103) - -[CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for cpu-bound tasks. - -Corresponds to the [Dispatchers.Default](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html) property in a default implementation. - -**See Also** - -[Dispatchers.Default](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html) - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/get.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/get.md new file mode 100644 index 000000000..7beee6820 --- /dev/null +++ b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/get.md @@ -0,0 +1,12 @@ +[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [get](./get.md) + +# get + +`fun get(): `[`DispatcherProvider`](../-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt#L39) + +Returns the current configured default [DispatcherProvider](../-dispatcher-provider/index.md) + +**See Also** + +[set](set.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md index 839f09373..71e201a44 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md @@ -2,25 +2,27 @@ # DefaultDispatcherProvider -`class DefaultDispatcherProvider : `[`DispatcherProvider`](../-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L101) +`object DefaultDispatcherProvider` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt#L30) -Default implementation of [DispatcherProvider](../-dispatcher-provider/index.md) which simply delegates to the corresponding -properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. +Holder singleton for a [DispatcherProvider](../-dispatcher-provider/index.md) instance. -This should be suitable for most production code. +If [CoroutineScope.dispatcherProvider](../kotlinx.coroutines.-coroutine-scope/dispatcher-provider.md) or [CoroutineContext.dispatcherProvider](../kotlinx.coroutines.-coroutine-scope/dispatcher-provider.md) is referenced +in a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) which does not have one, +it will use a default defined by this object. -### Constructors +``` kotlin +val custom = CustomDispatcherProvider() +DefaultDispatcherProvider.set(custom) -| Name | Summary | -|---|---| -| [<init>](-init-.md) | Default implementation of [DispatcherProvider](../-dispatcher-provider/index.md) which simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton.`DefaultDispatcherProvider()` | +val scope = MainImmediateCoroutineScope() + +scope.mainImmediateDispatcher shouldBe custom.mainImmediate +DefaultDispatcherProvider.get().mainImmediate shouldBe custom.mainImmediate +``` -### Properties +### Functions | Name | Summary | |---|---| -| [default](default.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for cpu-bound tasks.`val default: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [io](io.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for blocking I/O tasks.`val io: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [main](main.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread.`val main: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [mainImmediate](main-immediate.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread with immediate dispatch.`val mainImmediate: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [unconfined](unconfined.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is unconfined.`val unconfined: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [get](get.md) | Returns the current configured default [DispatcherProvider](../-dispatcher-provider/index.md)`fun get(): `[`DispatcherProvider`](../-dispatcher-provider/index.md) | +| [set](set.md) | Atomically sets a default [DispatcherProvider](../-dispatcher-provider/index.md) instance.`fun set(value: `[`DispatcherProvider`](../-dispatcher-provider/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/io.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/io.md deleted file mode 100644 index 79759b9e9..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/io.md +++ /dev/null @@ -1,14 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [io](./io.md) - -# io - -`val io: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L104) - -[CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for blocking I/O tasks. - -Corresponds to the [Dispatchers.IO](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html) property in a default implementation. - -**See Also** - -[Dispatchers.IO](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html) - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main-immediate.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main-immediate.md deleted file mode 100644 index fdbf61612..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main-immediate.md +++ /dev/null @@ -1,14 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [mainImmediate](./main-immediate.md) - -# mainImmediate - -`val mainImmediate: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L106) - -[CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread with immediate dispatch. - -Corresponds to the [Dispatchers.Main.immediate](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-coroutine-dispatcher/immediate.html) property in a default implementation. - -**See Also** - -[MainCoroutineDispatcher.immediate](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-coroutine-dispatcher/immediate.html) - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main.md deleted file mode 100644 index 431da9bd8..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/main.md +++ /dev/null @@ -1,14 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [main](./main.md) - -# main - -`val main: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L105) - -[CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread. - -Corresponds to the [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html) property in a default implementation. - -**See Also** - -[Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html) - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/set.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/set.md new file mode 100644 index 000000000..66bacf23d --- /dev/null +++ b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/set.md @@ -0,0 +1,22 @@ +[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [set](./set.md) + +# set + +`fun set(value: `[`DispatcherProvider`](../-dispatcher-provider/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DefaultDispatcherProvider.kt#L47) + +Atomically sets a default [DispatcherProvider](../-dispatcher-provider/index.md) instance. + +``` kotlin +val custom = CustomDispatcherProvider() +DefaultDispatcherProvider.set(custom) + +val scope = MainImmediateCoroutineScope() + +scope.mainImmediateDispatcher shouldBe custom.mainImmediate +DefaultDispatcherProvider.get().mainImmediate shouldBe custom.mainImmediate +``` + +**See Also** + +[get](get.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/unconfined.md b/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/unconfined.md deleted file mode 100644 index d3bbaa194..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-default-dispatcher-provider/unconfined.md +++ /dev/null @@ -1,14 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DefaultDispatcherProvider](index.md) / [unconfined](./unconfined.md) - -# unconfined - -`val unconfined: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L107) - -[CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is unconfined. - -Corresponds to the [Dispatchers.Unconfined](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html) property in a default implementation. - -**See Also** - -[Dispatchers.Unconfined](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html) - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider.md deleted file mode 100644 index 196ff3d50..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider.md +++ /dev/null @@ -1,12 +0,0 @@ -[dispatch-core](../index.md) / [dispatch.core](index.md) / [DispatcherProvider](./-dispatcher-provider.md) - -# DispatcherProvider - -`fun DispatcherProvider(): `[`DispatcherProvider`](-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L93) - -Creates a default implementation of [DispatcherProvider](-dispatcher-provider/index.md). - -**See Also** - -[DefaultDispatcherProvider](-default-dispatcher-provider/index.md) - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key.md deleted file mode 100644 index 17b7b78a0..000000000 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key.md +++ /dev/null @@ -1,8 +0,0 @@ -[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DispatcherProvider](index.md) / [Key](./-key.md) - -# Key - -`companion object Key : `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<`[`DispatcherProvider`](index.md)`>` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L85) - -Unique [Key](./-key.md) definition which allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). - diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/index.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/index.md new file mode 100644 index 000000000..6ecc304af --- /dev/null +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/index.md @@ -0,0 +1,13 @@ +[dispatch-core](../../../index.md) / [dispatch.core](../../index.md) / [DispatcherProvider](../index.md) / [Key](./index.md) + +# Key + +`companion object Key : `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<`[`DispatcherProvider`](../index.md)`>` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L85) + +Unique [Key](./index.md) definition which allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). + +### Companion Object Functions + +| Name | Summary | +|---|---| +| [invoke](invoke.md) | Default implementation of [DispatcherProvider](../index.md) which simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton.`operator fun invoke(): `[`DispatcherProvider`](../index.md) | diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/invoke.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/invoke.md new file mode 100644 index 000000000..6626f79e9 --- /dev/null +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/-key/invoke.md @@ -0,0 +1,15 @@ +[dispatch-core](../../../index.md) / [dispatch.core](../../index.md) / [DispatcherProvider](../index.md) / [Key](index.md) / [invoke](./invoke.md) + +# invoke + +`operator fun invoke(): `[`DispatcherProvider`](../index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L95) + +Default implementation of [DispatcherProvider](../index.md) which simply delegates to the corresponding +properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. + +This should be suitable for most production code. + +**See Also** + +[DefaultDispatcherProvider](../../-default-dispatcher-provider/index.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/default.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/default.md index 0e25c4b22..74cf9b357 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/default.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/default.md @@ -2,7 +2,7 @@ # default -`abstract val default: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L44) +`open val default: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L44) [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for cpu-bound tasks. diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/index.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/index.md index accc5ff79..6bb460691 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/index.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/index.md @@ -15,21 +15,21 @@ thereby eliminating the need for singleton references or dependency injecting th | Name | Summary | |---|---| -| [Key](-key.md) | Unique [Key](-key.md) definition which allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html).`companion object Key : `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<`[`DispatcherProvider`](./index.md)`>` | +| [Key](-key/index.md) | Unique [Key](-key/index.md) definition which allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html).`companion object Key : `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<`[`DispatcherProvider`](./index.md)`>` | ### Properties | Name | Summary | |---|---| -| [default](default.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for cpu-bound tasks.`abstract val default: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [io](io.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for blocking I/O tasks.`abstract val io: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [key](key.md) | This unique [Key](-key.md) property is what allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html).`open val key: `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<*>` | -| [main](main.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread.`abstract val main: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [mainImmediate](main-immediate.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread with immediate dispatch.`abstract val mainImmediate: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [unconfined](unconfined.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is unconfined.`abstract val unconfined: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [default](default.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for cpu-bound tasks.`open val default: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [io](io.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for blocking I/O tasks.`open val io: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [key](key.md) | This unique [Key](-key/index.md) property is what allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html).`open val key: `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<*>` | +| [main](main.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread.`open val main: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [mainImmediate](main-immediate.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread with immediate dispatch.`open val mainImmediate: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [unconfined](unconfined.md) | [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is unconfined.`open val unconfined: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -### Inheritors +### Companion Object Functions | Name | Summary | |---|---| -| [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) | Default implementation of [DispatcherProvider](./index.md) which simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton.`class DefaultDispatcherProvider : `[`DispatcherProvider`](./index.md) | +| [invoke](invoke.md) | Default implementation of [DispatcherProvider](./index.md) which simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton.`operator fun invoke(): `[`DispatcherProvider`](./index.md) | diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/invoke.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/invoke.md new file mode 100644 index 000000000..a91433a71 --- /dev/null +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/invoke.md @@ -0,0 +1,15 @@ +[dispatch-core](../../index.md) / [dispatch.core](../index.md) / [DispatcherProvider](index.md) / [invoke](./invoke.md) + +# invoke + +`operator fun invoke(): `[`DispatcherProvider`](index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L95) + +Default implementation of [DispatcherProvider](index.md) which simply delegates to the corresponding +properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. + +This should be suitable for most production code. + +**See Also** + +[DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/io.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/io.md index 9c96fa6bd..5c1ff809b 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/io.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/io.md @@ -2,7 +2,7 @@ # io -`abstract val io: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L53) +`open val io: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L53) [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) generally intended for blocking I/O tasks. diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/key.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/key.md index 63368bd13..1ddcf6ee2 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/key.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/key.md @@ -4,5 +4,5 @@ `open val key: `[`Key`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-key/index.html)`<*>` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L35) -This unique [Key](-key.md) property is what allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). +This unique [Key](-key/index.md) property is what allows the `DispatcherProvider` to be stored in the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html). diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main-immediate.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main-immediate.md index 12c2dad72..c25b1bdc1 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main-immediate.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main-immediate.md @@ -2,7 +2,7 @@ # mainImmediate -`abstract val mainImmediate: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L71) +`open val mainImmediate: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L71) [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread with immediate dispatch. diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main.md index 14e6f1b59..91aa0f6d5 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/main.md @@ -2,7 +2,7 @@ # main -`abstract val main: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L62) +`open val main: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L62) [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is confined to the "main" thread. diff --git a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/unconfined.md b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/unconfined.md index 1e06258aa..2bf11c208 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/unconfined.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-dispatcher-provider/unconfined.md @@ -2,7 +2,7 @@ # unconfined -`abstract val unconfined: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L80) +`open val unconfined: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/DispatcherProvider.kt#L80) [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) which is unconfined. diff --git a/docs/kdoc/dispatch-core/dispatch.core/-i-o-coroutine-scope.md b/docs/kdoc/dispatch-core/dispatch.core/-i-o-coroutine-scope.md index ea2ad56ec..6912f9a21 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-i-o-coroutine-scope.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-i-o-coroutine-scope.md @@ -6,7 +6,7 @@ Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `io`. -`fun IOCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`IOCoroutineScope`](./-i-o-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L89) +`fun IOCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`IOCoroutineScope`](./-i-o-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L89) Factory function for an [IOCoroutineScope](./-i-o-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `io` property of the `DispatcherProvider`. @@ -15,7 +15,7 @@ Dispatch defaults to the `io` property of the `DispatcherProvider`. `job` - [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html) if one is not provided. -`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) if one is not provided. +`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) if one is not provided. **See Also** @@ -30,7 +30,7 @@ Dispatch defaults to the `io` property of the `DispatcherProvider`. `coroutineContext` - [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) to be used for the resulting `CoroutineScope`. Any existing [ContinuationInterceptor](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-continuation-interceptor/index.html) will be overwritten. -If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) will be added. +If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) will be added. **See Also** diff --git a/docs/kdoc/dispatch-core/dispatch.core/-main-coroutine-scope.md b/docs/kdoc/dispatch-core/dispatch.core/-main-coroutine-scope.md index 0fd66699c..101cb0ee0 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-main-coroutine-scope.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-main-coroutine-scope.md @@ -6,7 +6,7 @@ Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `main`. -`fun MainCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`MainCoroutineScope`](./-main-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L121) +`fun MainCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`MainCoroutineScope`](./-main-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L121) Factory function for a [MainCoroutineScope](./-main-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `main` property of the `DispatcherProvider`. @@ -15,7 +15,7 @@ Dispatch defaults to the `main` property of the `DispatcherProvider`. `job` - [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html) if one is not provided. -`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) if one is not provided. +`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) if one is not provided. **See Also** @@ -30,7 +30,7 @@ Dispatch defaults to the `main` property of the `DispatcherProvider`. `coroutineContext` - [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) to be used for the resulting `CoroutineScope`. Any existing [ContinuationInterceptor](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-continuation-interceptor/index.html) will be overwritten. -If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) will be added. +If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) will be added. **See Also** diff --git a/docs/kdoc/dispatch-core/dispatch.core/-main-immediate-coroutine-scope.md b/docs/kdoc/dispatch-core/dispatch.core/-main-immediate-coroutine-scope.md index 4efb2ea28..5ebbf5b88 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-main-immediate-coroutine-scope.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-main-immediate-coroutine-scope.md @@ -6,7 +6,7 @@ Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `mainImmediate`. -`fun MainImmediateCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`MainImmediateCoroutineScope`](./-main-immediate-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L153) +`fun MainImmediateCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`MainImmediateCoroutineScope`](./-main-immediate-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L153) Factory function for a [MainImmediateCoroutineScope](./-main-immediate-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `mainImmediate` property of the `DispatcherProvider`. @@ -15,7 +15,7 @@ Dispatch defaults to the `mainImmediate` property of the `DispatcherProvider`. `job` - [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html) if one is not provided. -`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) if one is not provided. +`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) if one is not provided. **See Also** @@ -30,7 +30,7 @@ Dispatch defaults to the `mainImmediate` property of the `DispatcherProvider`. `coroutineContext` - [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) to be used for the resulting `CoroutineScope`. Any existing [ContinuationInterceptor](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-continuation-interceptor/index.html) will be overwritten. -If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) will be added. +If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) will be added. **See Also** diff --git a/docs/kdoc/dispatch-core/dispatch.core/-unconfined-coroutine-scope.md b/docs/kdoc/dispatch-core/dispatch.core/-unconfined-coroutine-scope.md index 03787259a..0fc595b99 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/-unconfined-coroutine-scope.md +++ b/docs/kdoc/dispatch-core/dispatch.core/-unconfined-coroutine-scope.md @@ -6,7 +6,7 @@ Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `unconfined`. -`fun UnconfinedCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`UnconfinedCoroutineScope`](./-unconfined-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L186) +`fun UnconfinedCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`UnconfinedCoroutineScope`](./-unconfined-coroutine-scope.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopes.kt#L186) Factory function for a [UnconfinedCoroutineScope](./-unconfined-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `unconfined` property of the `DispatcherProvider`. @@ -15,7 +15,7 @@ Dispatch defaults to the `unconfined` property of the `DispatcherProvider`. `job` - [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) to be used for the resulting `CoroutineScope`. Uses a [SupervisorJob](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html) if one is not provided. -`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) if one is not provided. +`dispatcherProvider` - [DispatcherProvider](-dispatcher-provider/index.md) to be used for the resulting `CoroutineScope`. Uses [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) if one is not provided. **See Also** @@ -30,7 +30,7 @@ Dispatch defaults to the `unconfined` property of the `DispatcherProvider`. `coroutineContext` - [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) to be used for the resulting `CoroutineScope`. Any existing [ContinuationInterceptor](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-continuation-interceptor/index.html) will be overwritten. -If the `CoroutineContext` does not already contain a `DispatcherProvider`, a [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) will be added. +If the `CoroutineContext` does not already contain a `DispatcherProvider`, [DefaultDispatcherProvider.get](-default-dispatcher-provider/get.md) will be added. **See Also** diff --git a/docs/kdoc/dispatch-core/dispatch.core/index.md b/docs/kdoc/dispatch-core/dispatch.core/index.md index 5ba24c7a7..a35046a62 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/index.md +++ b/docs/kdoc/dispatch-core/dispatch.core/index.md @@ -7,7 +7,7 @@ | Name | Summary | |---|---| | [DefaultCoroutineScope](-default-coroutine-scope.md) | Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `default`.`interface DefaultCoroutineScope : `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) | -| [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) | Default implementation of [DispatcherProvider](-dispatcher-provider/index.md) which simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton.`class DefaultDispatcherProvider : `[`DispatcherProvider`](-dispatcher-provider/index.md) | +| [DefaultDispatcherProvider](-default-dispatcher-provider/index.md) | Holder singleton for a [DispatcherProvider](-dispatcher-provider/index.md) instance.`object DefaultDispatcherProvider` | | [DispatcherProvider](-dispatcher-provider/index.md) | Interface corresponding to the different [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html)'s offered by [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html).`interface DispatcherProvider : `[`Element`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/-element/index.html) | | [IOCoroutineScope](-i-o-coroutine-scope.md) | Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `io`.`interface IOCoroutineScope : `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) | | [MainCoroutineScope](-main-coroutine-scope.md) | Marker interface which designates a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) with a [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) of `main`.`interface MainCoroutineScope : `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) | @@ -26,12 +26,11 @@ | Name | Summary | |---|---| -| [DefaultCoroutineScope](-default-coroutine-scope.md) | Factory function for a [DefaultCoroutineScope](-default-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `default` property of the `DispatcherProvider`.`fun DefaultCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`DefaultCoroutineScope`](-default-coroutine-scope.md)
`fun DefaultCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`DefaultCoroutineScope`](-default-coroutine-scope.md) | -| [DispatcherProvider](-dispatcher-provider.md) | Creates a default implementation of [DispatcherProvider](-dispatcher-provider/index.md).`fun DispatcherProvider(): `[`DispatcherProvider`](-dispatcher-provider/index.md) | -| [IOCoroutineScope](-i-o-coroutine-scope.md) | Factory function for an [IOCoroutineScope](-i-o-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `io` property of the `DispatcherProvider`.`fun IOCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`IOCoroutineScope`](-i-o-coroutine-scope.md)
Factory function for a [IOCoroutineScope](-i-o-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `io` property of the `DispatcherProvider`.`fun IOCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`IOCoroutineScope`](-i-o-coroutine-scope.md) | -| [MainCoroutineScope](-main-coroutine-scope.md) | Factory function for a [MainCoroutineScope](-main-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `main` property of the `DispatcherProvider`.`fun MainCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`MainCoroutineScope`](-main-coroutine-scope.md)
`fun MainCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`MainCoroutineScope`](-main-coroutine-scope.md) | -| [MainImmediateCoroutineScope](-main-immediate-coroutine-scope.md) | Factory function for a [MainImmediateCoroutineScope](-main-immediate-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `mainImmediate` property of the `DispatcherProvider`.`fun MainImmediateCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`MainImmediateCoroutineScope`](-main-immediate-coroutine-scope.md)
`fun MainImmediateCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`MainImmediateCoroutineScope`](-main-immediate-coroutine-scope.md) | -| [UnconfinedCoroutineScope](-unconfined-coroutine-scope.md) | Factory function for a [UnconfinedCoroutineScope](-unconfined-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `unconfined` property of the `DispatcherProvider`.`fun UnconfinedCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider()): `[`UnconfinedCoroutineScope`](-unconfined-coroutine-scope.md)
`fun UnconfinedCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`UnconfinedCoroutineScope`](-unconfined-coroutine-scope.md) | +| [DefaultCoroutineScope](-default-coroutine-scope.md) | Factory function for a [DefaultCoroutineScope](-default-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `default` property of the `DispatcherProvider`.`fun DefaultCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`DefaultCoroutineScope`](-default-coroutine-scope.md)
`fun DefaultCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`DefaultCoroutineScope`](-default-coroutine-scope.md) | +| [IOCoroutineScope](-i-o-coroutine-scope.md) | Factory function for an [IOCoroutineScope](-i-o-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `io` property of the `DispatcherProvider`.`fun IOCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`IOCoroutineScope`](-i-o-coroutine-scope.md)
Factory function for a [IOCoroutineScope](-i-o-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `io` property of the `DispatcherProvider`.`fun IOCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`IOCoroutineScope`](-i-o-coroutine-scope.md) | +| [MainCoroutineScope](-main-coroutine-scope.md) | Factory function for a [MainCoroutineScope](-main-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `main` property of the `DispatcherProvider`.`fun MainCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`MainCoroutineScope`](-main-coroutine-scope.md)
`fun MainCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`MainCoroutineScope`](-main-coroutine-scope.md) | +| [MainImmediateCoroutineScope](-main-immediate-coroutine-scope.md) | Factory function for a [MainImmediateCoroutineScope](-main-immediate-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `mainImmediate` property of the `DispatcherProvider`.`fun MainImmediateCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`MainImmediateCoroutineScope`](-main-immediate-coroutine-scope.md)
`fun MainImmediateCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`MainImmediateCoroutineScope`](-main-immediate-coroutine-scope.md) | +| [UnconfinedCoroutineScope](-unconfined-coroutine-scope.md) | Factory function for a [UnconfinedCoroutineScope](-unconfined-coroutine-scope.md) with a [DispatcherProvider](-dispatcher-provider/index.md). Dispatch defaults to the `unconfined` property of the `DispatcherProvider`.`fun UnconfinedCoroutineScope(job: `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)` = SupervisorJob(), dispatcherProvider: `[`DispatcherProvider`](-dispatcher-provider/index.md)` = DefaultDispatcherProvider.get()): `[`UnconfinedCoroutineScope`](-unconfined-coroutine-scope.md)
`fun UnconfinedCoroutineScope(coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`): `[`UnconfinedCoroutineScope`](-unconfined-coroutine-scope.md) | | [withDefault](with-default.md) | Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.`suspend fun withDefault(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T` | | [withIO](with-i-o.md) | Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.`suspend fun withIO(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T` | | [withMain](with-main.md) | Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.`suspend fun withMain(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): T` | diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/dispatcher-provider.md b/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/dispatcher-provider.md index e8cb5c84f..17fa9b65d 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/dispatcher-provider.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/dispatcher-provider.md @@ -2,10 +2,10 @@ # dispatcherProvider -`val `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L90) +`val `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L102) Extracts the [DispatcherProvider](../-dispatcher-provider/index.md) out of the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html), -or returns a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) if the `CoroutineContext` +or returns a default from [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) if the `CoroutineContext` does not have one specified. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/index.md b/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/index.md index 88d4f13f7..68729d6aa 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/index.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlin.coroutines.-coroutine-context/index.md @@ -4,4 +4,4 @@ | Name | Summary | |---|---| -| [dispatcherProvider](dispatcher-provider.md) | Extracts the [DispatcherProvider](../-dispatcher-provider/index.md) out of the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html), or returns a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) if the `CoroutineContext` does not have one specified.`val `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) | +| [dispatcherProvider](dispatcher-provider.md) | Extracts the [DispatcherProvider](../-dispatcher-provider/index.md) out of the [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html), or returns a default from [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) if the `CoroutineContext` does not have one specified.`val `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) | diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-default.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-default.md index 9449cfd54..bded9d514 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-default.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-default.md @@ -2,7 +2,7 @@ # asyncDefault -`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncDefault(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L32) +`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncDefault(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L34) Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html). diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-i-o.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-i-o.md index 1bb6edbd5..9738504af 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-i-o.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-i-o.md @@ -2,7 +2,7 @@ # asyncIO -`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncIO(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L49) +`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncIO(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L51) Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html). diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main-immediate.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main-immediate.md index 3a8ccc22a..f01c3a864 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main-immediate.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main-immediate.md @@ -2,7 +2,7 @@ # asyncMainImmediate -`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncMainImmediate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L83) +`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncMainImmediate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L85) Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html). diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main.md index 321137a5e..efb3c188b 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-main.md @@ -2,7 +2,7 @@ # asyncMain -`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncMain(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L66) +`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncMain(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L68) Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html). diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-unconfined.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-unconfined.md index 5df0e979d..04b40c395 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-unconfined.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/async-unconfined.md @@ -2,7 +2,7 @@ # asyncUnconfined -`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncUnconfined(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L100) +`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncUnconfined(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/Async.kt#L102) Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html). diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/default-dispatcher.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/default-dispatcher.md index 121e709f1..cfaa4e50a 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/default-dispatcher.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/default-dispatcher.md @@ -2,11 +2,15 @@ # defaultDispatcher -`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.defaultDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L28) +`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.defaultDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L30) Extracts the **default** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), -creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary. +using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, a new instance will be created each time. +**See Also** + +[CoroutineScope.dispatcherProvider](dispatcher-provider.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/dispatcher-provider.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/dispatcher-provider.md index 1252937d7..60b6ca539 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/dispatcher-provider.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/dispatcher-provider.md @@ -2,12 +2,16 @@ # dispatcherProvider -`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L79) +`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L91) Extracts the [DispatcherProvider](../-dispatcher-provider/index.md) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), -or returns a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) if the `coroutineContext` +or returns a new instance of [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) if the `coroutineContext` does not have one specified. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, a new instance will be created each time. +**See Also** + +[CoroutineContext.dispatcherProvider](../kotlin.coroutines.-coroutine-context/dispatcher-provider.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/index.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/index.md index b00e03d5a..2216a3abb 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/index.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/index.md @@ -9,14 +9,14 @@ | [asyncMain](async-main.md) | Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncMain(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` | | [asyncMainImmediate](async-main-immediate.md) | Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncMainImmediate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` | | [asyncUnconfined](async-unconfined.md) | Creates a coroutine and returns its future result as an implementation of [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.asyncUnconfined(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> T): `[`Deferred`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html)`` | -| [defaultDispatcher](default-dispatcher.md) | Extracts the **default** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.defaultDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [dispatcherProvider](dispatcher-provider.md) | Extracts the [DispatcherProvider](../-dispatcher-provider/index.md) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), or returns a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) if the `coroutineContext` does not have one specified.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) | -| [ioDispatcher](io-dispatcher.md) | Extracts the **io** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.ioDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [defaultDispatcher](default-dispatcher.md) | Extracts the **default** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.defaultDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [dispatcherProvider](dispatcher-provider.md) | Extracts the [DispatcherProvider](../-dispatcher-provider/index.md) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), or returns a new instance of [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) if the `coroutineContext` does not have one specified.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.dispatcherProvider: `[`DispatcherProvider`](../-dispatcher-provider/index.md) | +| [ioDispatcher](io-dispatcher.md) | Extracts the **io** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.ioDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | | [launchDefault](launch-default.md) | Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). The coroutine is cancelled when the resulting job is [cancelled](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.launchDefault(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | | [launchIO](launch-i-o.md) | Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). The coroutine is cancelled when the resulting job is [cancelled](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.launchIO(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | | [launchMain](launch-main.md) | Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). The coroutine is cancelled when the resulting job is [cancelled](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.launchMain(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | | [launchMainImmediate](launch-main-immediate.md) | Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). The coroutine is cancelled when the resulting job is [cancelled](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.launchMainImmediate(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | | [launchUnconfined](launch-unconfined.md) | Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html). The coroutine is cancelled when the resulting job is [cancelled](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html).`fun `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.launchUnconfined(context: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html)` = EmptyCoroutineContext, start: `[`CoroutineStart`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)` = CoroutineStart.DEFAULT, block: suspend `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Job`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) | -| [mainDispatcher](main-dispatcher.md) | Extracts the **main** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [mainImmediateDispatcher](main-immediate-dispatcher.md) | Extracts the **mainImmediate** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainImmediateDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | -| [unconfinedDispatcher](unconfined-dispatcher.md) | Extracts the **unconfined** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.unconfinedDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [mainDispatcher](main-dispatcher.md) | Extracts the **main** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [mainImmediateDispatcher](main-immediate-dispatcher.md) | Extracts the **mainImmediate** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainImmediateDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | +| [unconfinedDispatcher](unconfined-dispatcher.md) | Extracts the **unconfined** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary.`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.unconfinedDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) | diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/io-dispatcher.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/io-dispatcher.md index 65e335402..4ecd7f051 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/io-dispatcher.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/io-dispatcher.md @@ -2,11 +2,15 @@ # ioDispatcher -`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.ioDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L38) +`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.ioDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L42) Extracts the **io** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), -creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary. +using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, a new instance will be created each time. +**See Also** + +[CoroutineScope.dispatcherProvider](dispatcher-provider.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-dispatcher.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-dispatcher.md index dd885f353..1d45f4d78 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-dispatcher.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-dispatcher.md @@ -2,11 +2,15 @@ # mainDispatcher -`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L48) +`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L54) Extracts the **main** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), -creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary. +using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, a new instance will be created each time. +**See Also** + +[CoroutineScope.dispatcherProvider](dispatcher-provider.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-immediate-dispatcher.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-immediate-dispatcher.md index 766982398..6153bbe1a 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-immediate-dispatcher.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/main-immediate-dispatcher.md @@ -2,11 +2,15 @@ # mainImmediateDispatcher -`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainImmediateDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L58) +`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.mainImmediateDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L66) Extracts the **mainImmediate** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), -creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary. +using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, a new instance will be created each time. +**See Also** + +[CoroutineScope.dispatcherProvider](dispatcher-provider.md) + diff --git a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/unconfined-dispatcher.md b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/unconfined-dispatcher.md index b9cf6ebb2..10e18e8f5 100644 --- a/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/unconfined-dispatcher.md +++ b/docs/kdoc/dispatch-core/dispatch.core/kotlinx.coroutines.-coroutine-scope/unconfined-dispatcher.md @@ -2,11 +2,15 @@ # unconfinedDispatcher -`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.unconfinedDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L68) +`val `[`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)`.unconfinedDispatcher: `[`CoroutineDispatcher`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-core/src/main/java/dispatch/core/CoroutineScopeExt.kt#L78) Extracts the **unconfined** [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) out of the [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), -creating a new instance of a [DefaultDispatcherProvider](../-default-dispatcher-provider/index.md) to provide one if necessary. +using [DefaultDispatcherProvider.get](../-default-dispatcher-provider/get.md) to provide one if necessary. Note that `CoroutineContext` is immutable, so if a new `DefaultDispatcherProvider` is needed, a new instance will be created each time. +**See Also** + +[CoroutineScope.dispatcherProvider](dispatcher-provider.md) + diff --git a/docs/kdoc/dispatch-core/index.md b/docs/kdoc/dispatch-core/index.md index 7fc92338f..f01c886b7 100644 --- a/docs/kdoc/dispatch-core/index.md +++ b/docs/kdoc/dispatch-core/index.md @@ -59,6 +59,9 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { * [Async](#async) * [WithContext](#withcontext) * [Flow](#flow) +* [DefaultDispatcherProvider](#defaultdispatcherprovider) + * [Out-of-box default functionality](#out-of-box-default-functionality) + * [Easy global dispatcher overrides](#easy-global-dispatcher-overrides) * [Minimum Gradle Config](#minimum-gradle-config) ## Types @@ -66,7 +69,7 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { | **Name** | **Description** | ------------- | --------------- | | [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-dispatcher-provider/index.html) | Interface which provides the 5 standard [CoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) properties of the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) object, but which can be embedded in a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/) -| [DefaultDispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/index.html) | Default implementation of [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-dispatcher-provider/index.html) which simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton +| [DefaultDispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/index.html) | Mutable singleton holder for an implementation of [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-dispatcher-provider/index.html). By default, it simply delegates to the corresponding properties in the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. Whenever a [CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/) does not have a [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-dispatcher-provider/index.html), this singleton's value will be used by default. ### Marker interfaces and factories @@ -139,6 +142,54 @@ val someFlow = flow { } .flowOnUnconfined() ``` +## DefaultDispatcherProvider + +The simplest way to get up and running with Dispatch. All library access to a +[CoroutineContext's](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/) [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-dispatcher-provider/index.html) filters through a single extension +property: + +``` kotlin +public val CoroutineContext.dispatcherProvider: DispatcherProvider + get() = get(DispatcherProvider) ?: DefaultDispatcherProvider.get() +``` + +If the receiver does not have a `DispatcherProvider`, the value from [DefaultDispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/index.html) +will be returned. In practice, this brings at least two benefits: + +### Out-of-box default functionality + +Calls such as `launchIO { ... }`or `withMain { ... }` are safe to use (guaranteed to have a +`DispatcherProvider`) regardless of the source of the `CoroutineContext` or [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html) and +without any additional configuration. By default, they will access the corresponding +[CoroutineDispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html) from the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton. + +### Easy global dispatcher overrides + +`DefaultDispatcherProvider` has similar +[set](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/set.html)/[reset](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/set.html) functionality to the +[Dispatchers.setMain](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html)/[Dispatchers.resetMain](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/reset-main.html) extensions in `kotlinx-coroutines-test`, except it +doesn't need to be confined to testing. + +You can use [DefaultDispatcherProvider.set](https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/set.html) to globally set a custom implementation at the beginning +of an application's lifecycle, but the most likely use-case is certainly in testing. + +``` kotlin +@Test +fun `my test`() = runBlocking { + + DefaultDispatcherProvider.set(TestDispatcherProvider()) + + withMain { + // this would normally crash without using Dispatchers.setMain + // but "main" here comes from the TestDispatcherProvider created above -- not Dispatchers.Main + } + + DefaultDispatcherProvider.reset() // from dispatch-test +} +``` + +See [dispatch-test](https://rbusarow.github.io/Dispatch/dispatch-test//index.html) and [TestDispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-test//dispatch.test/-test-dispatcher-provider/index.html) + ## Minimum Gradle Config Add to your module's `build.gradle.kts`: @@ -150,8 +201,8 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") } ``` diff --git a/docs/kdoc/dispatch-detekt/index.md b/docs/kdoc/dispatch-detekt/index.md index 7d591852e..e0d08c1ea 100644 --- a/docs/kdoc/dispatch-detekt/index.md +++ b/docs/kdoc/dispatch-detekt/index.md @@ -28,7 +28,7 @@ In root project-level `build.gradle` or `build.gradle.kts`: ``` kotlin allprojects { dependencies { - detekt("io.gitlab.arturbosch.detekt:detekt-cli:1.9.1") + detekt("io.gitlab.arturbosch.detekt:detekt-cli:1.10.0") detektPlugins("com.rickbusarow.dispatch:dispatch-detekt:1.0.0-beta04") } diff --git a/docs/kdoc/dispatch-test-junit4/index.md b/docs/kdoc/dispatch-test-junit4/index.md index 9f8ddc73b..a80c6b8e3 100644 --- a/docs/kdoc/dispatch-test-junit4/index.md +++ b/docs/kdoc/dispatch-test-junit4/index.md @@ -68,13 +68,13 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 artifact also provides the dispatch-test artifact testImplementation("com.rickbusarow.dispatch:dispatch-test-junit4:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` @@ -92,14 +92,14 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 and junit5 artifacts also provides the dispatch-test artifact testImplementation("ccom.rickbusarow.dispatch:dispatch-test-junit4:1.0.0-beta03") testImplementation("ccom.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta03") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/docs/kdoc/dispatch-test-junit5/index.md b/docs/kdoc/dispatch-test-junit5/index.md index 26cb6e14b..ac62615bf 100644 --- a/docs/kdoc/dispatch-test-junit5/index.md +++ b/docs/kdoc/dispatch-test-junit5/index.md @@ -98,13 +98,13 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit5 artifact also provides the dispatch-test artifact testImplementation("com.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") } ``` @@ -123,8 +123,8 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 and junit5 artifacts also provides the dispatch-test artifact @@ -132,7 +132,7 @@ dependencies { testImplementation("com.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta04") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") testImplementation("org.junit.vintage:junit-vintage-engine:5.6.2") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/docs/kdoc/dispatch-test/alltypes/index.md b/docs/kdoc/dispatch-test/alltypes/index.md index 455ffa13e..bb382a1d6 100644 --- a/docs/kdoc/dispatch-test/alltypes/index.md +++ b/docs/kdoc/dispatch-test/alltypes/index.md @@ -6,6 +6,11 @@ Test helpers for the [dispatch-core](https://rbusarow.github.io/Dispatch/dispatc | Name | Summary | |---|---| +| (extensions in package dispatch.test) + +##### [dispatch.core.DefaultDispatcherProvider](../dispatch.test/dispatch.core.-default-dispatcher-provider/index.md) + + | ##### [dispatch.test.TestDispatcherProvider](../dispatch.test/-test-dispatcher-provider/index.md) diff --git a/docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/index.md b/docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/index.md new file mode 100644 index 000000000..3cd5ef649 --- /dev/null +++ b/docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/index.md @@ -0,0 +1,7 @@ +[dispatch-test](../../index.md) / [dispatch.test](../index.md) / [dispatch.core.DefaultDispatcherProvider](./index.md) + +### Extensions for dispatch.core.DefaultDispatcherProvider + +| Name | Summary | +|---|---| +| [reset](reset.md) | Resets the singleton [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md) instance to the true default. This default instance delegates to the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton object properties.`fun `[`DefaultDispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md)`.reset(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | diff --git a/docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/reset.md b/docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/reset.md new file mode 100644 index 000000000..02b7fd875 --- /dev/null +++ b/docs/kdoc/dispatch-test/dispatch.test/dispatch.core.-default-dispatcher-provider/reset.md @@ -0,0 +1,32 @@ +[dispatch-test](../../index.md) / [dispatch.test](../index.md) / [dispatch.core.DefaultDispatcherProvider](index.md) / [reset](./reset.md) + +# reset + +`fun `[`DefaultDispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md)`.reset(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/RBusarow/Dispatch/tree/master/dispatch-test/src/main/java/dispatch/test/defaultDispatcherProvider.kt#L28) + +Resets the singleton [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md) instance to the true default. +This default instance delegates to the [Dispatchers](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html) singleton object properties. + +``` kotlin +val custom = CustomDispatcherProvider() +DefaultDispatcherProvider.set(custom) + +DefaultDispatcherProvider.get() shouldBe custom + +DefaultDispatcherProvider.reset() + +val default = DefaultDispatcherProvider.get() + +default shouldNotBe custom + +default.default shouldBe Dispatchers.Default +default.io shouldBe Dispatchers.IO +default.main shouldBe Dispatchers.Main +default.mainImmediate shouldBe Dispatchers.Main.immediate +default.unconfined shouldBe Dispatchers.Unconfined +``` + +**See Also** + +[DefaultDispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-default-dispatcher-provider/index.md) + diff --git a/docs/kdoc/dispatch-test/dispatch.test/index.md b/docs/kdoc/dispatch-test/dispatch.test/index.md index b20576d5d..4a195e152 100644 --- a/docs/kdoc/dispatch-test/dispatch.test/index.md +++ b/docs/kdoc/dispatch-test/dispatch.test/index.md @@ -9,6 +9,12 @@ | [TestDispatcherProvider](-test-dispatcher-provider/index.md) | [DispatcherProvider](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md) implementation for testing, where each property defaults to a [TestCoroutineDispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-dispatcher/index.html).`class TestDispatcherProvider : `[`DispatcherProvider`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-dispatcher-provider/index.md) | | [TestProvidedCoroutineScope](-test-provided-coroutine-scope/index.md) | A polymorphic testing [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html) interface.`interface TestProvidedCoroutineScope : `[`TestCoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scope/index.html)`, `[`DefaultCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-default-coroutine-scope/index.md)`, `[`IOCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-i-o-coroutine-scope/index.md)`, `[`MainCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-coroutine-scope/index.md)`, `[`MainImmediateCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.md)`, `[`UnconfinedCoroutineScope`](https://rbusarow.github.io/Dispatch/dispatch-core/dispatch.core/-unconfined-coroutine-scope/index.md) | +### Extensions for External Classes + +| Name | Summary | +|---|---| +| [dispatch.core.DefaultDispatcherProvider](dispatch.core.-default-dispatcher-provider/index.md) | | + ### Functions | Name | Summary | diff --git a/docs/kdoc/dispatch-test/index.md b/docs/kdoc/dispatch-test/index.md index 9790b5c96..ef9c0d910 100644 --- a/docs/kdoc/dispatch-test/index.md +++ b/docs/kdoc/dispatch-test/index.md @@ -117,12 +117,12 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") testImplementation("com.rickbusarow.dispatch:dispatch-test:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/docs/kdoc/dispatch-test/package-list b/docs/kdoc/dispatch-test/package-list index 9ea61f782..e9a62c512 100644 --- a/docs/kdoc/dispatch-test/package-list +++ b/docs/kdoc/dispatch-test/package-list @@ -1,4 +1,4 @@ $dokka.format:gfm $dokka.linkExtension:md - +$dokka.location:dispatch.test$reset(dispatch.core.DefaultDispatcherProvider)dispatch.test/dispatch.core.-default-dispatcher-provider/reset.md dispatch.test diff --git a/docs/modules/dispatch-android-espresso.md b/docs/modules/dispatch-android-espresso.md index 6b76c5f55..140cf6f59 100644 --- a/docs/modules/dispatch-android-espresso.md +++ b/docs/modules/dispatch-android-espresso.md @@ -88,8 +88,8 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") androidTestImplementation("com.rickbusarow.dispatch:dispatch-android-espresso:1.0.0-beta04") diff --git a/docs/modules/dispatch-android-lifecycle-extensions.md b/docs/modules/dispatch-android-lifecycle-extensions.md index 3a7ad72fd..9c1e6faee 100644 --- a/docs/modules/dispatch-android-lifecycle-extensions.md +++ b/docs/modules/dispatch-android-lifecycle-extensions.md @@ -51,7 +51,7 @@ class SomeApplication : Application() { override fun onCreate() { super.onCreate() // A custom factory can be set to add elements to the CoroutineContext - LifecycleScopeFactory.set { MainImmediateCoroutineScope() + SomeCustomElement() } + LifecycleScopeFactory.set { MainImmediateContext() + SomeCustomElement() } } } ``` @@ -62,7 +62,7 @@ class SomeEspressoTest { fun setUp() { // This custom factory can be used to use custom scopes for testing, // such as an idling dispatcher - LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope() } + LifecycleScopeFactory.set { MainImmediateIdlingCoroutineScope().coroutineContext } } @After @@ -93,7 +93,7 @@ class SomeFragmentEspressoTest { fun setUp() { // set a custom factory which is applied to all newly created lifecycleScopes LifecycleScopeFactory.set { - MainImmediateCoroutineScope() + idlingRule.dispatcherProvider + MainImmediateContext() + idlingRule.dispatcherProvider } // now SomeFragment will use an IdlingDispatcher in its CoroutineScope @@ -139,10 +139,10 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-lifecycle-extensions:1.0.0-beta04") - + implementation("androidx.lifecycle:lifecycle-common:2.2.0") } ``` diff --git a/docs/modules/dispatch-android-lifecycle.md b/docs/modules/dispatch-android-lifecycle.md index ccff73d5f..fe7857687 100644 --- a/docs/modules/dispatch-android-lifecycle.md +++ b/docs/modules/dispatch-android-lifecycle.md @@ -57,10 +57,9 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-lifecycle:1.0.0-beta04") - implementation("androidx.lifecycle:lifecycle-common:2.2.0") } ``` @@ -72,9 +71,9 @@ dependencies { [LifecycleCoroutineScope]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/index.html [MinimumStatePolicy]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/-minimum-state-policy/index.html -[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-create.html -[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-start.html -[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-lifecycle-coroutine-scope/launch-on-resume.html +[launchOnCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-create.html +[launchOnStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-start.html +[launchOnResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/-view-lifecycle-coroutine-scope/launch-on-resume.html [LifecycleOwner.onNextCreate]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-create.html [LifecycleOwner.onNextStart]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-start.html [LifecycleOwner.onNextResume]: https://rbusarow.github.io/Dispatch/dispatch-android-lifecycle//dispatch.android.lifecycle/androidx.lifecycle.-lifecycle-owner/on-next-resume.html diff --git a/docs/modules/dispatch-android-viewmodel.md b/docs/modules/dispatch-android-viewmodel.md index c94e4a7fc..7ea8e2d29 100644 --- a/docs/modules/dispatch-android-viewmodel.md +++ b/docs/modules/dispatch-android-viewmodel.md @@ -176,8 +176,8 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-android-viewmodel:1.0.0-beta04") } ``` diff --git a/docs/modules/dispatch-core.md b/docs/modules/dispatch-core.md index 40382b851..b939f7c33 100644 --- a/docs/modules/dispatch-core.md +++ b/docs/modules/dispatch-core.md @@ -60,6 +60,9 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { * [Async](#async) * [WithContext](#withcontext) * [Flow](#flow) +* [DefaultDispatcherProvider](#defaultdispatcherprovider) + * [Out-of-box default functionality](#out-of-box-default-functionality) + * [Easy global dispatcher overrides](#easy-global-dispatcher-overrides) * [Minimum Gradle Config](#minimum-gradle-config) @@ -69,8 +72,7 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { | **Name** | **Description** | ------------- | --------------- | | [DispatcherProvider] | Interface which provides the 5 standard [CoroutineDispatcher] properties of the [Dispatchers] object, but which can be embedded in a [CoroutineContext] -| [DefaultDispatcherProvider] | Default implementation of [DispatcherProvider] which simply delegates to the corresponding properties in the [Dispatchers] singleton - +| [DefaultDispatcherProvider] | Mutable singleton holder for an implementation of [DispatcherProvider]. By default, it simply delegates to the corresponding properties in the [Dispatchers] singleton. Whenever a [CoroutineContext] does not have a [DispatcherProvider], this singleton's value will be used by default. ### Marker interfaces and factories @@ -91,8 +93,6 @@ class SomeUIClass(val coroutineScope: MainCoroutineScope) { | `suspend T` | [withDefault] | [withIO] | [withMain] | [withMainImmediate] | [withUnconfined] | `Flow` | [flowOnDefault] | [flowOnIO] | [flowOnMain] | [flowOnMainImmediate] | [flowOnUnconfined] - - ### Launch ``` kotlin fun foo(scope: CoroutineScope) { @@ -131,6 +131,7 @@ suspend fun foo() { ``` ### Flow + Like [withContext], [Flow] typically doesn’t get a [CoroutineScope] of its own. They inherit the [coroutineContext][kotlin.coroutineContext] from the collector in a pattern called [context preservation][context_preservation]. These new operators maintain context preservation (*they’re forced to, actually*), and extract the [coroutineContext][kotlin.coroutineContext] from the collector. ``` kotlin @@ -142,6 +143,53 @@ val someFlow = flow { } .flowOnUnconfined() ``` +## DefaultDispatcherProvider + +The simplest way to get up and running with Dispatch. All library access to a +[CoroutineContext's][CoroutineContext] [DispatcherProvider] filters through a single extension +property: + +``` kotlin +public val CoroutineContext.dispatcherProvider: DispatcherProvider + get() = get(DispatcherProvider) ?: DefaultDispatcherProvider.get() +``` + +If the receiver does not have a `DispatcherProvider`, the value from [DefaultDispatcherProvider] +will be returned. In practice, this brings at least two benefits: + +### Out-of-box default functionality + +Calls such as `launchIO { ... }`or `withMain { ... }` are safe to use (guaranteed to have a +`DispatcherProvider`) regardless of the source of the `CoroutineContext` or [CoroutineScope] and +without any additional configuration. By default, they will access the corresponding +[CoroutineDispatchers][CoroutineDispatcher] from the [Dispatchers] singleton. + +### Easy global dispatcher overrides + +`DefaultDispatcherProvider` has similar +[set][DefaultDispatcherProvider.set]/[reset][DefaultDispatcherProvider.set] functionality to the +[Dispatchers.setMain]/[Dispatchers.resetMain] extensions in `kotlinx-coroutines-test`, except it +doesn't need to be confined to testing. + +You can use [DefaultDispatcherProvider.set] to globally set a custom implementation at the beginning +of an application's lifecycle, but the most likely use-case is certainly in testing. + +``` kotlin +@Test +fun `my test`() = runBlocking { + + DefaultDispatcherProvider.set(TestDispatcherProvider()) + + withMain { + // this would normally crash without using Dispatchers.setMain + // but "main" here comes from the TestDispatcherProvider created above -- not Dispatchers.Main + } + + DefaultDispatcherProvider.reset() // from dispatch-test +} +``` +> See [dispatch-test] and [TestDispatcherProvider] + ## Minimum Gradle Config Add to your module's `build.gradle.kts`: @@ -153,8 +201,8 @@ repositories { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") } ``` @@ -193,14 +241,20 @@ dependencies { [flowOnMain]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/kotlinx.coroutines.flow.-flow/flow-on-main.html [flowOnMainImmediate]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/kotlinx.coroutines.flow.-flow/flow-on-main-immediate.html [flowOnUnconfined]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/kotlinx.coroutines.flow.-flow/flow-on-unconfined.html +[DefaultDispatcherProvider.set]: https://rbusarow.github.io/Dispatch/dispatch-core//dispatch.core/-default-dispatcher-provider/set.html + + +[TestDispatcherProvider]: https://rbusarow.github.io/Dispatch/dispatch-test//dispatch.test/-test-dispatcher-provider/index.html - [context_preservation]: https://medium.com/@elizarov/execution-context-of-kotlin-flows-b8c151c9309b [CoroutineContext]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/ [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html [CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html [Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html +[dispatch-test]: https://rbusarow.github.io/Dispatch/dispatch-test//index.html +[Dispatchers.resetMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/reset-main.html +[Dispatchers.setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html [Dispatchers]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html [Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html [Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html diff --git a/docs/modules/dispatch-detekt.md b/docs/modules/dispatch-detekt.md index 66ee7ca9c..258eb685c 100644 --- a/docs/modules/dispatch-detekt.md +++ b/docs/modules/dispatch-detekt.md @@ -32,7 +32,7 @@ In root project-level `build.gradle` or `build.gradle.kts`: ``` kotlin allprojects { dependencies { - detekt("io.gitlab.arturbosch.detekt:detekt-cli:1.9.1") + detekt("io.gitlab.arturbosch.detekt:detekt-cli:1.10.0") detektPlugins("com.rickbusarow.dispatch:dispatch-detekt:1.0.0-beta04") } diff --git a/docs/modules/dispatch-test-junit4.md b/docs/modules/dispatch-test-junit4.md index 67458558f..9abe9d0d6 100644 --- a/docs/modules/dispatch-test-junit4.md +++ b/docs/modules/dispatch-test-junit4.md @@ -71,13 +71,13 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 artifact also provides the dispatch-test artifact testImplementation("com.rickbusarow.dispatch:dispatch-test-junit4:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` @@ -95,14 +95,14 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 and junit5 artifacts also provides the dispatch-test artifact testImplementation("ccom.rickbusarow.dispatch:dispatch-test-junit4:1.0.0-beta03") testImplementation("ccom.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta03") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/docs/modules/dispatch-test-junit5.md b/docs/modules/dispatch-test-junit5.md index 45b4f0057..e095aacc1 100644 --- a/docs/modules/dispatch-test-junit5.md +++ b/docs/modules/dispatch-test-junit5.md @@ -101,13 +101,13 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit5 artifact also provides the dispatch-test artifact testImplementation("com.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") } ``` @@ -126,8 +126,8 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") // the junit4 and junit5 artifacts also provides the dispatch-test artifact @@ -135,7 +135,7 @@ dependencies { testImplementation("com.rickbusarow.dispatch:dispatch-test-junit5:1.0.0-beta04") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") testImplementation("org.junit.vintage:junit-vintage-engine:5.6.2") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/docs/modules/dispatch-test.md b/docs/modules/dispatch-test.md index 83ff9a9fc..e344c6be6 100644 --- a/docs/modules/dispatch-test.md +++ b/docs/modules/dispatch-test.md @@ -120,12 +120,12 @@ repositories { dependencies { // core - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8") implementation("com.rickbusarow.dispatch:dispatch-core:1.0.0-beta04") testImplementation("com.rickbusarow.dispatch:dispatch-test:1.0.0-beta04") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8") } ``` diff --git a/settings.gradle.kts b/settings.gradle.kts index df110ef43..9a88ccbd4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,4 +32,5 @@ include(":dispatch-core:samples") include(":dispatch-detekt") include(":dispatch-detekt:samples") include(":dispatch-internal-test") +include(":dispatch-internal-test-android") include(":dispatch-sample") diff --git a/site/mkdocs.yml b/site/mkdocs.yml index 012d4b949..30f21c3f7 100644 --- a/site/mkdocs.yml +++ b/site/mkdocs.yml @@ -28,22 +28,26 @@ nav: - 'Modules': - 'Core': modules/dispatch-core.md - 'Detekt': modules/dispatch-detekt.md - - 'Test-Core': modules/dispatch-test.md - - 'Test-JUnit4': modules/dispatch-test-junit4.md - - 'Test-JUnit5': modules/dispatch-test-junit5.md - - 'Android-Espresso': modules/dispatch-android-espresso.md - - 'android-lifecycle': modules/dispatch-android-lifecycle.md - - 'Android-viewmodel': modules/dispatch-android-viewmodel.md + - 'Test': + - 'Test-Core': modules/dispatch-test.md + - 'Test-JUnit4': modules/dispatch-test-junit4.md + - 'Test-JUnit5': modules/dispatch-test-junit5.md + - 'Android': + - 'Android-Espresso': modules/dispatch-android-espresso.md + - 'Android-Lifecycle': modules/dispatch-android-lifecycle.md + - 'Android-Lifecycle-Extensions': modules/dispatch-android-lifecycle-extensions.md + - 'Android-Viewmodel': modules/dispatch-android-viewmodel.md # - 'Change Log': - 'Change Log': CHANGELOG.md - 'KDoc': - 'core': kdoc/dispatch-core/index.md - - 'dtekt': kdoc/dispatch-detekt/index.md + - 'detekt': kdoc/dispatch-detekt/index.md - 'test-core': kdoc/dispatch-test/index.md - 'test-junit4': kdoc/dispatch-test-junit4/index.md - 'test-junit5': kdoc/dispatch-test-junit5/index.md - 'android-espresso': kdoc/dispatch-android-espresso/index.md - 'android-lifecycle': kdoc/dispatch-android-lifecycle/index.md + - 'android-lifecycle-extensions': kdoc/dispatch-android-lifecycle-extensions/index.md - 'android-viewmodel': kdoc/dispatch-android-viewmodel/index.md theme: @@ -51,7 +55,7 @@ theme: language: en feature: - tabs: true + tabs: false palette: primary: blue accent: blue