Skip to content

Commit

Permalink
Lazily load Dispatchers.Main and provide a stub impl on failure
Browse files Browse the repository at this point in the history
Also specified explicit public visibility for Dispatchers object.

Fixes #658
Fixes #665
  • Loading branch information
elizarov authored and qwwdfsad committed Oct 8, 2018
1 parent e963ede commit 0ece388
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 15 deletions.
Expand Up @@ -9,7 +9,7 @@ import kotlin.coroutines.experimental.*
/**
* Groups various implementations of [CoroutineDispatcher].
*/
expect object Dispatchers {
public expect object Dispatchers {
/**
* The default [CoroutineDispatcher] that is used by all standard builders like
* [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc
Expand Down
57 changes: 46 additions & 11 deletions core/kotlinx-coroutines-core/src/Dispatchers.kt
Expand Up @@ -19,15 +19,7 @@ public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.paralleli
/**
* Groups various implementations of [CoroutineDispatcher].
*/
actual object Dispatchers {

private val mainDispatcher = loadMainDispatcher()

private fun loadMainDispatcher(): MainCoroutineDispatcher? {
return MainDispatcherFactory::class.java.let { clz ->
ServiceLoader.load(clz, clz.classLoader).toList()
}.maxBy { it.loadPriority }?.createDispatcher()
}
public actual object Dispatchers {

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

/**
* A coroutine dispatcher that is not confined to any specific thread.
Expand Down Expand Up @@ -97,3 +88,47 @@ actual object Dispatchers {
@JvmStatic
public val IO: CoroutineDispatcher = DefaultScheduler.IO
}

// Lazy loader for the main dispatcher
private object MainDispatcherLoader {
@JvmField
val dispatcher: MainCoroutineDispatcher =
MainDispatcherFactory::class.java.let { clz ->
ServiceLoader.load(clz, clz.classLoader).toList()
}.maxBy { it.loadPriority }?.tryCreateDispatcher() ?: MissingMainCoroutineDispatcher(null)

/**
* If anything goes wrong while trying to create main dispatcher (class not found,
* initialization failed, etc), then replace the main dispatcher with a special
* stub that throws an error message on any attempt to actually use it.
*/
private fun MainDispatcherFactory.tryCreateDispatcher(): MainCoroutineDispatcher =
try {
createDispatcher()
} catch (cause: Throwable) {
MissingMainCoroutineDispatcher(cause)
}
}

private class MissingMainCoroutineDispatcher(val cause: Throwable?) : MainCoroutineDispatcher(), Delay {
override val immediate: MainCoroutineDispatcher get() = this

override fun dispatch(context: CoroutineContext, block: Runnable) =
missing()

override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
missing()

private fun missing() {
if (cause == null) {
throw IllegalStateException(
"Module with the Main dispatcher is missing. " +
"Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android'"
)
} else {
throw IllegalStateException("Module with the Main dispatcher had failed to initialize", cause)
}
}

override fun toString(): String = "Main[missing${if (cause != null) ", cause=$cause" else ""}]"
}
2 changes: 1 addition & 1 deletion js/kotlinx-coroutines-core-js/src/Dispatchers.kt
Expand Up @@ -6,7 +6,7 @@ package kotlinx.coroutines.experimental

import kotlin.coroutines.experimental.*

actual object Dispatchers {
public actual object Dispatchers {

public actual val Default: CoroutineDispatcher = createDefaultDispatcher()

Expand Down
3 changes: 1 addition & 2 deletions native/kotlinx-coroutines-core-native/src/Dispatchers.kt
Expand Up @@ -6,8 +6,7 @@ package kotlinx.coroutines.experimental

import kotlin.coroutines.experimental.*


actual object Dispatchers {
public actual object Dispatchers {

public actual val Default: CoroutineDispatcher = createDefaultDispatcher()

Expand Down

0 comments on commit 0ece388

Please sign in to comment.