{"id":16559909,"url":"https://github.com/rbusarow/dispatch","last_synced_at":"2026-01-11T17:44:01.576Z","repository":{"id":38509020,"uuid":"206223913","full_name":"RBusarow/Dispatch","owner":"RBusarow","description":"Automatic CoroutineDispatcher injection and extensions for kotlinx.coroutines","archived":false,"fork":false,"pushed_at":"2024-10-22T18:38:51.000Z","size":9053,"stargazers_count":136,"open_issues_count":24,"forks_count":6,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-28T12:08:21.036Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://rbusarow.github.io/Dispatch/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RBusarow.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-04T03:33:06.000Z","updated_at":"2025-01-09T14:12:54.000Z","dependencies_parsed_at":"2024-10-26T20:28:54.570Z","dependency_job_id":"b7f138f7-a9e0-46cb-8a73-c33d7264de4f","html_url":"https://github.com/RBusarow/Dispatch","commit_stats":null,"previous_names":["rbusarow/dispatcherprovider"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RBusarow%2FDispatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RBusarow%2FDispatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RBusarow%2FDispatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RBusarow%2FDispatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RBusarow","download_url":"https://codeload.github.com/RBusarow/Dispatch/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182401,"owners_count":20897381,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T20:27:30.837Z","updated_at":"2026-01-11T17:44:01.546Z","avatar_url":"https://github.com/RBusarow.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[\u003cimg src=\"https://img.shields.io/maven-central/v/com.rickbusarow.dispatch/dispatch-core.svg?label=Maven%20Central\"/\u003e](https://search.maven.org/search?q=com.rickbusarow.dispatch)\n![CI](https://github.com/RBusarow/Dispatch/workflows/CI/badge.svg)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\n# Dispatch\n\nUtilities for [kotlinx.coroutines] which make them type-safe, easier to test, and more expressive.\nUse the predefined [types and factories](#types-and-factories) or define your own, and never inject\na `Dispatchers` object again.\n\n```kotlin\nval presenter = MyPresenter(MainCoroutineScope())\n\nclass MyPresenter @Inject constructor(\n  /**\n  * Defaults to the Main dispatcher\n  */\n  val coroutineScope: MainCoroutineScope\n) {\n\n  fun loopSomething() = coroutineScope.launchDefault {  }\n\n  suspend fun updateSomething() = withMainImmediate {  }\n}\n```\n\n```kotlin\nclass MyTest {\n\n  @Test\n  fun `no setting the main dispatcher`() = runBlockingProvidedTest {\n\n    // automatically use TestCoroutineDispatcher for every dispatcher type\n    val presenter = MyPresenter(coroutineScope = this)\n\n    // this call would normally crash due to the main looper\n    presenter.updateSomething()\n  }\n\n}\n```\n\n## Contents\n\n\u003c!--- TOC --\u003e\n\n* [Injecting dispatchers](#injecting-dispatchers)\n* [Types and Factories](#types-and-factories)\n* [Referencing dispatchers](#referencing-dispatchers)\n  * [Builder Extensions](#builder-extensions)\n* [Android Lifecycle](#android-lifecycle)\n* [Android Espresso](#android-espresso)\n* [Android ViewModel](#android-viewmodel)\n* [Testing](#testing)\n* [Modules](#modules)\n* [Full Gradle Config](#full-gradle-config)\n* [License](#license)\n\n\u003c!--- END --\u003e\n\n## Injecting dispatchers\n\nEverywhere you use coroutines, you use a [CoroutineContext]. If we embed the\n[CoroutineDispatchers][CoroutineDispatcher] settings we want into the context, then we don't need to\npass them around manually.\n\nThe core of this library is [DispatcherProvider] - an interface with properties corresponding to the\n5 different [CoroutineDispatchers][CoroutineDispatcher] we can get from the [Dispatchers] singleton.\nIt lives inside the [CoroutineContext], and gets passed from parent to child coroutines\ntransparently without any additional code.\n\n```kotlin\ninterface DispatcherProvider : CoroutineContext.Element {\n\n  override val key: CoroutineContext.Key\u003c*\u003e get() = Key\n\n  val default: CoroutineDispatcher\n  val io: CoroutineDispatcher\n  val main: CoroutineDispatcher\n  val mainImmediate: CoroutineDispatcher\n  val unconfined: CoroutineDispatcher\n\n  companion object Key : CoroutineContext.Key\u003cDispatcherProvider\u003e\n}\n\nval someCoroutineScope = CoroutineScope(\n  Job() + Dispatchers.Main + DispatcherProvider()\n)\n```\n\nThe default implementation of this interface simply delegates to that [Dispatchers] singleton, as\nthat is what we typically want for production usage.\n\n## Types and Factories\n\nA [CoroutineScope] may have any type of [CoroutineDispatcher]. What if we have a View class which\nwill always use the [Main][Dispatchers.Main] thread, or one which will always do I/O?\n\nThere are marker interfaces and factories to ensure that the correct type of [CoroutineScope] is\nalways used.\n\n| **Type**                         | **Dispatcher**       |\n| -------------------------------- | -------------------- |\n| [DefaultCoroutineScope]          | [Dispatchers.Default]\n| [IOCoroutineScope]               | [Dispatchers.IO]\n| [MainCoroutineScope]             | [Dispatchers.Main]\n| [MainImmediateCoroutineScope]    | [Dispatchers.Main.immediate]\n| [UnconfinedCoroutineScope]       | [Dispatchers.Unconfined]\n\n```kotlin\nval mainScope = MainCoroutineScope()\n\nval someUIClass = SomeUIClass(mainScope)\n\nclass SomeUIClass(val coroutineScope: MainCoroutineScope) {\n\n  fun foo() = coroutineScope.launch {\n    // because of the dependency type,\n    // we're guaranteed to be on the main dispatcher even though we didn't specify it\n  }\n\n}\n```\n\n## Referencing dispatchers\n\nThese [dispatcher][CoroutineDispatcher] settings can then be accessed via extension functions upon\n[CoroutineScope], or the [coroutineContext][kotlin.coroutineContext], or directly from extension\nfunctions:\n\n### Builder Extensions\n\n| | **Default**     | **IO**     | **Main**     | **Main.immediate**    | **\nUnconfined**     | | ------------ | --------------- | ---------- | ------------ |\n--------------------- | ------------------ | | [Job]        | [launchDefault] | [launchIO]\n| [launchMain] | [launchMainImmediate] | [launchUnconfined]\n| [Deferred]   | [asyncDefault]  | [asyncIO]  | [asyncMain]  | [asyncMainImmediate]\n| [asyncUnconfined]\n| `suspend T`  | [withDefault]   | [withIO]   | [withMain]   | [withMainImmediate]\n| [withUnconfined]\n| `Flow\u003cT\u003e`    | [flowOnDefault] | [flowOnIO] | [flowOnMain] | [flowOnMainImmediate]\n| [flowOnUnconfined]\n\n```kotlin\nclass MyClass(val coroutineScope: IOCoroutineScope) {\n\n  fun accessMainThread() = coroutineScope.launchMain {\n    // we're now on the \"main\" thread as defined by the interface\n  }\n\n}\n```\n\n## Android Lifecycle\n\nThe [AndroidX.lifecycle][androidx-lifecycle-runtime-ktx] library offers a\n[lifecycleScope][androidx-lifecycleScope] extension function to provide a lifecycle-aware\n[CoroutineScope], but there are two shortcomings:\n1. It delegates to a hard-coded `Dispatchers.Main` [CoroutineDispatcher], which complicates unit and\n   [Espresso] testing by requiring the use of [Dispatchers.setMain].\n2. It *pauses* the dispatcher when the lifecycle state passes below its threshold,\n   which [leaks backpressure to the producing coroutine and can create deadlocks][b/146370660].\n\n[Dispatch-android-lifecycle] and [dispatch-android-lifecycle-extensions] completely replace the\nAndroidX version.\n\n```kotlin\nimport dispatch.android.lifecycle.*\nimport dispatch.core.*\nimport kotlinx.coroutines.flow.*\n\nclass MyActivity : Activity() {\n\n  init {\n    dispatchLifecycleScope.launchOnCreate {\n          viewModel.someFlow.collect {\n            channel.send(\"$it\")\n          }\n        }\n  }\n}\n```\n\nThe [DispatchLifecycleScope][DispatchLifecycleScope-class] may be configured with any dispatcher,\nsince\n[MainImmediateCoroutineScope] is just a marker interface. Its lifecycle-aware functions *cancel*\nwhen dropping below a threshold, then automatically restart when entering into the desired lifecycle\nstate again. This is key to preventing the backpressure leak of the AndroidX version, and it's also\nmore analogous to the behavior of [LiveData] to which many developers are accustomed.\n\nThere are two built-in ways to define a custom LifecycleCoroutineScope - by simply constructing one\ndirectly inside a Lifecycle class, or by statically setting a custom [LifecycleScopeFactory]. This\nsecond option can be very useful when utilizing an [IdlingCoroutineScope].\n\n## Android Espresso\n\n[Espresso] is able to use [IdlingResource] to infer when it should perform its actions, which helps\nto reduce the flakiness of tests. Conventional thread-based `IdlingResource` implementations don't\nwork with coroutines, however.\n\n[IdlingCoroutineScope] utilizes [IdlingDispatchers][IdlingDispatcher], which count a coroutine as\nbeing \"idle\" when it is suspended. Using statically defined factories, service locators, or\ndependency injection, it is possible to utilize idling-aware dispatchers throughout a codebase\nduring Espresso testing.\n\n```kotlin\nclass IdlingCoroutineScopeRuleWithLifecycleSample {\n\n\n  val customDispatcherProvider = IdlingDispatcherProvider()\n\n  @JvmField\n  @Rule\n  val idlingRule = IdlingDispatcherProviderRule {\n    IdlingDispatcherProvider(customDispatcherProvider)\n  }\n\n  /**\n  * If you don't provide CoroutineScopes to your lifecycle components via a dependency injection framework,\n  * you need to use the `dispatch-android-lifecycle-extensions` and `dispatch-android-viewmodel` artifacts\n  * to ensure that the same `IdlingDispatcherProvider` is used.\n  */\n  @Before\n  fun setUp() {\n    LifecycleScopeFactory.set {\n      MainImmediateCoroutineScope(customDispatcherProvider)\n    }\n    ViewModelScopeFactory.set {\n      MainImmediateCoroutineScope(customDispatcherProvider)\n    }\n  }\n\n  @Test\n  fun testThings() = runBlocking {\n\n    // Now any CoroutineScope which uses the DispatcherProvider\n    // in TestAppComponent will sync its \"idle\" state with Espresso\n\n  }\n\n}\n```\n\n## Android ViewModel\n\nThe [AndroidX ViewModel][androidx-lifecycle-viewmodel-ktx] library offers a\n[viewModelScope][androidx-viewModelScope] extension function to provide an auto-cancelled\n[CoroutineScope], but again, this `CoroutineScope` is hard-coded and uses `Dispatchers.Main`. This\nlimitation needn't exist.\n\n[Dispatch-android-viewmodel] doesn't have as many options as its lifecycle counterpart, because the\n[ViewModel.onCleared] function is `protected` and [ViewModel] does not expose anything about its\nlifecycle. The only way for a third party library to achieve a lifecycle-aware `CoroutineScope` is\nthrough inheritance.\n\n[CoroutineViewModel] is a simple abstract class which exposes a lazy [viewModelScope] property which\nis automatically cancelled when the `ViewModel` is destroyed. The exact type of the `viewModelScope`\ncan be configured statically via [ViewModelScopeFactory]. In this way, you can use\n[IdlingCoroutineScopes][IdlingCoroutineScope] for Espresso testing,\n[TestProvidedCoroutineScopes][TestProvidedCoroutineScope] for unit testing, or any other custom\nscope you'd like.\n\nIf you're using the AAC `ViewModel` but not dependency injection, this artifact should be very\nhelpful with testing.\n\n```kotlin\nimport dispatch.android.viewmodel.*\nimport kotlinx.coroutines.flow.*\nimport timber.log.*\n\nclass MyViewModel : CoroutineViewModel() {\n\n  init {\n    MyRepository.someFlow.onEach {\n      Timber.d(\"$it\")\n    }.launchIn(viewModelScope)\n  }\n}\n```\n\nThe [DispatchLifecycleScope][DispatchLifecycleScope-class] may be configured with any dispatcher,\nsince\n[MainImmediateCoroutineScope] is just a marker interface. Its lifecycle-aware functions *cancel*\nwhen dropping below a threshold, then automatically restart when entering into the desired lifecycle\nstate again. This is key to preventing the backpressure leak of the AndroidX version, and it's also\nmore analogous to the behavior of [LiveData] to which many developers are accustomed.\n\nThere are two built-in ways to define a custom LifecycleCoroutineScope - by simply constructing one\ndirectly inside a Lifecycle class, or by statically setting a custom [LifecycleScopeFactory]. This\nsecond option can be very useful when utilizing an [IdlingCoroutineScope].\n\n## Testing\n\nTesting is why this library exists. [TestCoroutineScope] and [TestCoroutineDispatcher] are very\npowerful when they can be used, but any reference to a statically defined dispatcher (like a\n[Dispatchers] property) removes that control.\n\nTo that end, there's a configurable [TestDispatcherProvider]:\n\n```kotlin\nclass TestDispatcherProvider(\n  override val default: CoroutineDispatcher = TestCoroutineDispatcher(),\n  override val io: CoroutineDispatcher = TestCoroutineDispatcher(),\n  override val main: CoroutineDispatcher = TestCoroutineDispatcher(),\n  override val mainImmediate: CoroutineDispatcher = TestCoroutineDispatcher(),\n  override val unconfined: CoroutineDispatcher = TestCoroutineDispatcher()\n) : DispatcherProvider\n```\n\nAs well as a polymorphic [TestProvidedCoroutineScope] which may be used in place of any\ntype-specific [CoroutineScope]:\n\n```kotlin\nval testScope = TestProvidedCoroutineScope()\n\nval someUIClass = SomeUIClass(testScope)\n\nclass SomeUIClass(val coroutineScope: MainCoroutineScope) {\n\n  fun foo() = coroutineScope.launch {\n    // ...\n  }\n\n}\n```\n\nThere's also [testProvided], which delegates to [runBlockingTest][kotlinx.runBlockingTest] but which\nincludes a [TestDispatcherProvider] inside the [TestCoroutineScope].\n\n```kotlin\nclass Subject {\n  // this would normally be a hard-coded reference to Dispatchers.Main\n  suspend fun sayHello() = withMain {  }\n}\n\n@Test\nfun `sayHello should say hello`() = runBlockingProvided {\n\n  val subject = SomeClass(this)\n  // uses \"main\" TestCoroutineDispatcher safely with no additional setup\n  subject.getSomeData() shouldPrint \"hello\"\n}\n```\n\n## Modules\n\n| **artifact**                            | **features**                                   |\n| --------------------------------------  | ---------------------------------------------- |\n| [dispatch-android-espresso]             | [IdlingDispatcher] \u003cp/\u003e [IdlingDispatcherProvider]\n| [dispatch-android-lifecycle-extensions] | [dispatchLifecycleScope][dispatchLifecycleScope-extension]\n| [dispatch-android-lifecycle]            | [DispatchLifecycleScope][DispatchLifecycleScope-class] \u003cp/\u003e [launchOnCreate] \u003cp/\u003e [launchOnStart] \u003cp/\u003e [launchOnResume] \u003cp/\u003e [onNextCreate] \u003cp/\u003e [onNextStart] \u003cp/\u003e [onNextResume]\n| [dispatch-android-viewmodel]            | [CoroutineViewModel] \u003cp/\u003e [viewModelScope]\n| [dispatch-core]                         | Dispatcher-specific types and factories \u003cp/\u003e Dispatcher-specific coroutine builders\n| [dispatch-detekt]                       | [Detekt] rules for common auto-imported-the-wrong-thing problems\n| [dispatch-test-junit4]                  | [TestCoroutineRule]\n| [dispatch-test-junit5]                  | [CoroutineTest] \u003cp/\u003e [CoroutineTestExtension]\n| [dispatch-test]                         | [TestProvidedCoroutineScope] \u003cp/\u003e [TestDispatcherProvider] \u003cp/\u003e [runBlockingProvided] and [testProvided]\n\n## Full Gradle Config\n\n```kotlin\nrepositories {\n  mavenCentral()\n}\n\ndependencies {\n\n  /*\n  production code\n  */\n\n  // core coroutines\n  implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0\")\n  implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0\")\n\n  // a BOM ensures that all artifacts used from the library are of the same version\n  implementation(platform(\"com.rickbusarow.dispatch:dispatch-bom:1.0.0-beta10\"))\n\n  // everything provides :core via \"api\", so you only need this if you have no other \"implementation\" dispatch artifacts\n  implementation(\"com.rickbusarow.dispatch:dispatch-core\")\n  // LifecycleCoroutineScope for Android Fragments, Activities, etc.\n  implementation(\"com.rickbusarow.dispatch:dispatch-android-lifecycle\")\n  // lifecycleScope extension function with a settable factory.  Use this if you don't DI your CoroutineScopes\n  // This provides :dispatch-android-lifecycle via \"api\", so you don't need to declare both\n  implementation(\"com.rickbusarow.dispatch:dispatch-android-lifecycle-extensions\")\n  // ViewModelScope for Android ViewModels\n  implementation(\"com.rickbusarow.dispatch:dispatch-android-viewmodel\")\n\n  /*\n  jvm testing\n  */\n\n  // core coroutines-test\n  testImplementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.0\")\n  // you only need this if you don't have the -junit4 or -junit5 artifacts\n  testImplementation(\"com.rickbusarow.dispatch:dispatch-test\")\n  // CoroutineTestRule and :dispatch-test\n  // This provides :dispatch-test via \"api\", so you don't need to declare both\n  // This can be used at the same time as :dispatch-test-junit5\n  testImplementation(\"com.rickbusarow.dispatch:dispatch-test-junit4\")\n  // CoroutineTest, CoroutineTestExtension, and :dispatch-test\n  // This provides :dispatch-test via \"api\", so you don't need to declare both\n  // This can be used at the same time as :dispatch-test-junit4\n  testImplementation(\"com.rickbusarow.dispatch:dispatch-test-junit5\")\n  /*\n  Android testing\n  */\n\n  // core android\n  androidTestImplementation(\"androidx.test:runner:1.3.0\")\n  androidTestImplementation(\"androidx.test.espresso:espresso-core:3.3.0\")\n  // IdlingDispatcher, IdlingDispatcherProvider, and IdlingCoroutineScope\n  androidTestImplementation(\"com.rickbusarow.dispatch:dispatch-android-espresso\")\n}\n```\n\n## License\n\n``` text\nCopyright (C) 2021 Rick Busarow\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n     http://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[DispatcherProvider]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/-dispatcher-provider/index.html\n\n[DefaultCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/-default-coroutine-scope/index.html\n\n[IOCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/-i-o-coroutine-scope/index.html\n\n[MainCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/-main-coroutine-scope/index.html\n\n[MainImmediateCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/-main-immediate-coroutine-scope/index.html\n\n[UnconfinedCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/-unconfined-coroutine-scope/index.html\n\n[launchDefault]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/launch-default.html\n\n[launchIO]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/launch-i-o.html\n\n[launchMain]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/launch-main.html\n\n[launchMainImmediate]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/launch-main-immediate.html\n\n[launchUnconfined]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/launch-unconfined.html\n\n[asyncDefault]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/async-default.html\n\n[asyncIO]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/async-i-o.html\n\n[asyncMain]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/async-main.html\n\n[asyncMainImmediate]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/async-main-immediate.html\n\n[asyncUnconfined]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/async-unconfined.html\n\n[withDefault]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/with-default.html\n\n[withIO]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/with-i-o.html\n\n[withMain]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/with-main.html\n\n[withMainImmediate]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/with-main-immediate.html\n\n[withUnconfined]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/with-unconfined.html\n\n[flowOnDefault]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/flow-on-default.html\n\n[flowOnIO]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/flow-on-i-o.html\n\n[flowOnMain]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/flow-on-main.html\n\n[flowOnMainImmediate]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/flow-on-main-immediate.html\n\n[flowOnUnconfined]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/flow-on-unconfined.html\n\n\n[TestProvidedCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-test/dispatch.test/-test-provided-coroutine-scope/index.html\n\n[TestDispatcherProvider]: https://rbusarow.github.io/Dispatch/api/dispatch-test/dispatch.test/-test-dispatcher-provider/index.html\n\n[testProvided]: https://rbusarow.github.io/Dispatch/api/dispatch-test/dispatch.test/test-provided.html\n\n[runBlockingProvided]: https://rbusarow.github.io/Dispatch/api/dispatch-test/dispatch.test/run-blocking-provided.html\n\n\n[TestCoroutineRule]: https://rbusarow.github.io/Dispatch/api/dispatch-test-junit4/dispatch.test/-test-coroutine-rule/index.html\n\n\n[CoroutineTest]: https://rbusarow.github.io/Dispatch/api/dispatch-test-junit5/dispatch.test/-coroutine-test/index.html\n\n[CoroutineTestExtension]: https://rbusarow.github.io/Dispatch/api/dispatch-test-junit5/dispatch.test/-coroutine-test-extension/index.html\n\n\n[IdlingCoroutineScope]: https://rbusarow.github.io/Dispatch/api/dispatch-android-espresso/dispatch.android.espresso/-idling-coroutine-scope/index.html\n\n[IdlingDispatcher]: https://rbusarow.github.io/Dispatch/api/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher/index.html\n\n[IdlingDispatcherProvider]: https://rbusarow.github.io/Dispatch/api/dispatch-android-espresso/dispatch.android.espresso/-idling-dispatcher-provider/index.html\n\n\n[launchOnCreate]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/-dispatch-lifecycle-scope/launch-on-create.html\n\n[launchOnStart]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/-dispatch-lifecycle-scope/launch-on-start.html\n\n[launchOnResume]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/-dispatch-lifecycle-scope/launch-on-resume.html\n\n[onNextCreate]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/on-next-create.html\n\n[onNextStart]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/on-next-start.html\n\n[onNextResume]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/on-next-resume.html\n\n\n[LifecycleScopeFactory]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/-lifecycle-scope-factory/index.html\n\n\n[CoroutineViewModel]: https://rbusarow.github.io/Dispatch/api/dispatch-android-viewmodel/dispatch.android.viewmodel/index.html#dispatch.android.viewmodel/CoroutineViewModel//PointingToDeclaration/\n\n[viewModelScope]: https://rbusarow.github.io/Dispatch/api/dispatch-android-viewmodel/dispatch.android.viewmodel/-dispatch-view-model/index.html#dispatch.android.viewmodel/DispatchViewModel/viewModelScope/#/PointingToDeclaration/\n\n[ViewModelScopeFactory]: https://rbusarow.github.io/Dispatch/api/dispatch-android-viewmodel/dispatch.android.viewmodel/-view-model-scope-factory/index.html\n\n\n[androidx-lifecycle-runtime-ktx]: https://developer.android.com/jetpack/androidx/releases/lifecycle\n\n[androidx-lifecycle-viewmodel-ktx]: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-viewmodel-ktx/src/main/java/androidx/lifecycle/ViewModel.kt;l=42\n\n[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\n\n[androidx-viewModelScope]: https://developer.android.com/topic/libraries/architecture/coroutines#viewmodelscope\n\n[b/146370660]: https://issuetracker.google.com/issues/146370660\n\n[CoroutineContext]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/\n\n[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html\n\n[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html\n\n[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html\n\n[Detekt]: https://github.com/detekt/detekt\n\n[dispatch-android-espresso]: https://rbusarow.github.io/Dispatch/api/dispatch-android-espresso/dispatch.android.espresso/index.html\n\n[dispatch-android-lifecycle-extensions]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/index.html\n\n[dispatch-android-lifecycle]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/index.html\n\n[dispatch-android-viewmodel]: https://rbusarow.github.io/Dispatch/api/dispatch-android-viewmodel/dispatch.android.viewmodel/index.html\n\n[dispatch-core]: https://rbusarow.github.io/Dispatch/api/dispatch-core/dispatch.core/index.html\n\n[dispatch-detekt]: https://rbusarow.github.io/Dispatch/api/dispatch-detekt/dispatch.detekt/index.html\n\n[dispatch-test-junit4]: https://rbusarow.github.io/Dispatch/api/dispatch-test-junit4/dispatch.test/index.html\n\n[dispatch-test-junit5]: https://rbusarow.github.io/Dispatch/api/dispatch-test-junit5/dispatch.test/index.html\n\n[dispatch-test]: https://rbusarow.github.io/Dispatch/api/dispatch-test/dispatch.test/index.html\n\n[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html\n\n[Dispatchers.IO]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-io.html\n\n[Dispatchers.Main.immediate]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-coroutine-dispatcher/immediate.html\n\n[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html\n\n[Dispatchers.setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html\n\n[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html\n\n[Dispatchers]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html\n\n[Espresso]: https://developer.android.com/training/testing/espresso\n\n[IdlingResource]: https://developer.android.com/training/testing/espresso/idling-resource\n\n[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html\n\n[kotlin.coroutineContext]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/coroutine-context.html\n\n[kotlinx.coroutines]: https://kotlin.github.io/kotlinx.coroutines/\n\n[kotlinx.runBlockingTest]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/run-blocking-test.html\n\n[LiveData]: https://developer.android.com/reference/androidx/lifecycle/LiveData\n\n[TestCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-dispatcher/index.html\n\n[TestCoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scope/index.html\n\n[ViewModel.onCleared]: https://developer.android.com/reference/androidx/lifecycle/ViewModel#onCleared()\n\n[ViewModel]: https://developer.android.com/reference/androidx/lifecycle/ViewModel\n\n\n[DispatchLifecycleScope-class]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle/dispatch.android.lifecycle/-dispatch-lifecycle-scope/index.html\n\n[dispatchLifecycleScope-extension]: https://rbusarow.github.io/Dispatch/api/dispatch-android-lifecycle-extensions/dispatch.android.lifecycle/index.html#dispatch.android.lifecycle/dispatchLifecycleScope/androidx.lifecycle.LifecycleOwner#/PointingToDeclaration/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frbusarow%2Fdispatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frbusarow%2Fdispatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frbusarow%2Fdispatch/lists"}