@@ -19,15 +19,7 @@ public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.paralleli
19
19
/* *
20
20
* Groups various implementations of [CoroutineDispatcher].
21
21
*/
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 {
31
23
32
24
/* *
33
25
* The default [CoroutineDispatcher] that is used by all standard builders like
@@ -59,8 +51,7 @@ actual object Dispatchers {
59
51
* Implementation note: [MainCoroutineDispatcher.immediate] is not supported on Native and JS platforms.
60
52
*/
61
53
@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
64
55
65
56
/* *
66
57
* A coroutine dispatcher that is not confined to any specific thread.
@@ -97,3 +88,47 @@ actual object Dispatchers {
97
88
@JvmStatic
98
89
public val IO : CoroutineDispatcher = DefaultScheduler .IO
99
90
}
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
+ }
0 commit comments