Skip to content

Commit 0ece388

Browse files
elizarovqwwdfsad
authored andcommitted
Lazily load Dispatchers.Main and provide a stub impl on failure
Also specified explicit public visibility for Dispatchers object. Fixes #658 Fixes #665
1 parent e963ede commit 0ece388

File tree

4 files changed

+49
-15
lines changed

4 files changed

+49
-15
lines changed

common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import kotlin.coroutines.experimental.*
99
/**
1010
* Groups various implementations of [CoroutineDispatcher].
1111
*/
12-
expect object Dispatchers {
12+
public expect object Dispatchers {
1313
/**
1414
* The default [CoroutineDispatcher] that is used by all standard builders like
1515
* [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc

core/kotlinx-coroutines-core/src/Dispatchers.kt

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,7 @@ public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.paralleli
1919
/**
2020
* Groups various implementations of [CoroutineDispatcher].
2121
*/
22-
actual object Dispatchers {
23-
24-
private val mainDispatcher = loadMainDispatcher()
25-
26-
private fun loadMainDispatcher(): MainCoroutineDispatcher? {
27-
return MainDispatcherFactory::class.java.let { clz ->
28-
ServiceLoader.load(clz, clz.classLoader).toList()
29-
}.maxBy { it.loadPriority }?.createDispatcher()
30-
}
22+
public actual object Dispatchers {
3123

3224
/**
3325
* The default [CoroutineDispatcher] that is used by all standard builders like
@@ -59,8 +51,7 @@ actual object Dispatchers {
5951
* Implementation note: [MainCoroutineDispatcher.immediate] is not supported on Native and JS platforms.
6052
*/
6153
@JvmStatic
62-
public actual val Main: MainCoroutineDispatcher get() = mainDispatcher ?: error("Module with Main dispatcher is missing. " +
63-
"Add dependency with required Main dispatcher, e.g. 'kotlinx-coroutines-android'")
54+
public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
6455

6556
/**
6657
* A coroutine dispatcher that is not confined to any specific thread.
@@ -97,3 +88,47 @@ actual object Dispatchers {
9788
@JvmStatic
9889
public val IO: CoroutineDispatcher = DefaultScheduler.IO
9990
}
91+
92+
// Lazy loader for the main dispatcher
93+
private object MainDispatcherLoader {
94+
@JvmField
95+
val dispatcher: MainCoroutineDispatcher =
96+
MainDispatcherFactory::class.java.let { clz ->
97+
ServiceLoader.load(clz, clz.classLoader).toList()
98+
}.maxBy { it.loadPriority }?.tryCreateDispatcher() ?: MissingMainCoroutineDispatcher(null)
99+
100+
/**
101+
* If anything goes wrong while trying to create main dispatcher (class not found,
102+
* initialization failed, etc), then replace the main dispatcher with a special
103+
* stub that throws an error message on any attempt to actually use it.
104+
*/
105+
private fun MainDispatcherFactory.tryCreateDispatcher(): MainCoroutineDispatcher =
106+
try {
107+
createDispatcher()
108+
} catch (cause: Throwable) {
109+
MissingMainCoroutineDispatcher(cause)
110+
}
111+
}
112+
113+
private class MissingMainCoroutineDispatcher(val cause: Throwable?) : MainCoroutineDispatcher(), Delay {
114+
override val immediate: MainCoroutineDispatcher get() = this
115+
116+
override fun dispatch(context: CoroutineContext, block: Runnable) =
117+
missing()
118+
119+
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
120+
missing()
121+
122+
private fun missing() {
123+
if (cause == null) {
124+
throw IllegalStateException(
125+
"Module with the Main dispatcher is missing. " +
126+
"Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android'"
127+
)
128+
} else {
129+
throw IllegalStateException("Module with the Main dispatcher had failed to initialize", cause)
130+
}
131+
}
132+
133+
override fun toString(): String = "Main[missing${if (cause != null) ", cause=$cause" else ""}]"
134+
}

js/kotlinx-coroutines-core-js/src/Dispatchers.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package kotlinx.coroutines.experimental
66

77
import kotlin.coroutines.experimental.*
88

9-
actual object Dispatchers {
9+
public actual object Dispatchers {
1010

1111
public actual val Default: CoroutineDispatcher = createDefaultDispatcher()
1212

native/kotlinx-coroutines-core-native/src/Dispatchers.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ package kotlinx.coroutines.experimental
66

77
import kotlin.coroutines.experimental.*
88

9-
10-
actual object Dispatchers {
9+
public actual object Dispatchers {
1110

1211
public actual val Default: CoroutineDispatcher = createDefaultDispatcher()
1312

0 commit comments

Comments
 (0)