If you have this question, perhaps you are a long time server-side developer and are wondering what the Main Dispatcher is doing in the Kotlinx coroutines library? Well, the Main Dispatcher exists as kind of an interface, but its implementation isn't really there.
The Main dispatcher is used in Kotlin when programming something that will interact with some sort of UI. For the Dispatchers.Main scope to be available, one of these needs to be available: Android main thread dispatcher, JavaFx, or Swing EDT dispatcher. The Main dispatcher has one distinct characteristic that tells it apart from the others. This dispatcher is singe-threaded and it is not shipped with the kotlinx coroutines library.
Let’s look at one example:
class MainDispatcherLauncher {
companion object {
val logger: Logger = LoggerFactory.getLogger(MainDispatcherLauncher::class.java)
@JvmStatic
fun main(args: Array<String> = emptyArray()) = runBlocking {
runMainCoroutinesTest()
}
private suspend fun runMainCoroutinesTest() {
try {
val job = CoroutineScope(Dispatchers.Main).launch {
launch {
delay(100)
logger.info("This is cat @ ${LocalDateTime.now()}")
}
launch {
logger.info("This is mouse @ ${LocalDateTime.now()}")
}
logger.info("This is master @ ${LocalDateTime.now()}")
}
job.join()
} catch (ex: IllegalStateException) {
logger.info("Error!", ex)
}
}
}
}
In this case, both launches would kickstart two coroutines and we would expect at least 3 log outputs in a normal situation. However, this will not work if simply running a standalone application or in a server-side setting. Since the Main disptacher isn’t available, running this code will result in:
Exception in thread "main" java.lang.IllegalStateException: Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android' and ensure it has the same version as 'kotlinx-coroutines-core'
at kotlinx.coroutines.internal.MainDispatchersKt.throwMissingMainDispatcherException(MainDispatchers.kt:77)
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.missing(MainDispatchers.kt:108)
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.isDispatchNeeded(MainDispatchers.kt:92)
at kotlinx.coroutines.test.internal.TestMainDispatcher.isDispatchNeeded(TestMainDispatcher.kt:31)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:315)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:21)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:88)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:123)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:52)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:43)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
at org.jesperancinha.ktd.MainScopeLauncher$Companion.runMainCoroutinesTest(MainScopeLauncher.kt:20)
at org.jesperancinha.ktd.MainScopeLauncher$Companion.access$runMainCoroutinesTest(MainScopeLauncher.kt:10)
at org.jesperancinha.ktd.MainScopeLauncher$Companion$main$1.invokeSuspend(MainScopeLauncher.kt:15)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:48)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at org.jesperancinha.ktd.MainScopeLauncher$Companion.main(MainScopeLauncher.kt:14)
at org.jesperancinha.ktd.MainScopeLauncher.main(MainScopeLauncher.kt)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@2c039ac6, Dispatchers.Main]
06:44:49.864 [main] INFO org.jesperancinha.ktd.MainScopeLauncher -- Error!
java.lang.IllegalStateException: Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android' and ensure it has the same version as 'kotlinx-coroutines-core'
at kotlinx.coroutines.internal.MainDispatchersKt.throwMissingMainDispatcherException(MainDispatchers.kt:77)
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.missing(MainDispatchers.kt:108)
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.isDispatchNeeded(MainDispatchers.kt:92)
at kotlinx.coroutines.test.internal.TestMainDispatcher.isDispatchNeeded(TestMainDispatcher.kt:31)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:315)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:21)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:88)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:123)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:52)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:43)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
at org.jesperancinha.ktd.MainScopeLauncher$Companion.runMainCoroutinesTest(MainScopeLauncher.kt:20)
at org.jesperancinha.ktd.MainScopeLauncher$Companion.access$runMainCoroutinesTest(MainScopeLauncher.kt:10)
at org.jesperancinha.ktd.MainScopeLauncher$Companion$main$1.invokeSuspend(MainScopeLauncher.kt:15)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:48)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at org.jesperancinha.ktd.MainScopeLauncher$Companion.main(MainScopeLauncher.kt:14)
at org.jesperancinha.ktd.MainScopeLauncher.main(MainScopeLauncher.kt)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: null
Process finished with exit code 0
Remember to check the source for more details:
And if you have read this and have learned something new, you probably are ready to answer the following quiz:
And you can check your answer in the response video I created:
Have a good one everyone!
Top comments (0)