Skip to content

Commit cb3c105

Browse files
committed
Add workaround for androidx toolchain issues: try to load main dispatcher via Class.forName(..) if ServiceLoader failed to find dispatcher
Fixes #657
1 parent d826f5f commit cb3c105

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

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

+16-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ package kotlinx.coroutines
88

99
import kotlinx.coroutines.internal.*
1010
import kotlinx.coroutines.scheduling.*
11-
import kotlin.coroutines.*
1211
import java.util.*
12+
import kotlin.coroutines.*
1313

1414
/**
1515
* Name of the property that defines the maximal number of threads that are used by [Dispatchers.IO] coroutines dispatcher.
@@ -20,7 +20,6 @@ public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.paralleli
2020
* Groups various implementations of [CoroutineDispatcher].
2121
*/
2222
public actual object Dispatchers {
23-
2423
/**
2524
* The default [CoroutineDispatcher] that is used by all standard builders like
2625
* [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc
@@ -95,7 +94,21 @@ private object MainDispatcherLoader {
9594
val dispatcher: MainCoroutineDispatcher =
9695
MainDispatcherFactory::class.java.let { clz ->
9796
ServiceLoader.load(clz, clz.classLoader).toList()
98-
}.maxBy { it.loadPriority }?.tryCreateDispatcher() ?: MissingMainCoroutineDispatcher(null)
97+
}.maxBy { it.loadPriority }?.tryCreateDispatcher()
98+
?: (tryLoadAndroidDispatcher() ?: MissingMainCoroutineDispatcher(null))
99+
100+
private fun tryLoadAndroidDispatcher(): MainCoroutineDispatcher? {
101+
/*
102+
* Latest Android toolchain (androidx) *sometimes* mangles the name of the service loaded by ServiceLoader even if
103+
* it is present in the manifest. To workaround it (we don't want our users to suffer) we optimistically
104+
* try to load android factory manually (implementation is not mangled because it is marked with @Keep)
105+
*/
106+
val dispatcher = kotlin.runCatching {
107+
val clazz = Class.forName("kotlinx.coroutines.android.AndroidDispatcherFactory")
108+
clazz.getMethod("getDispatcher")?.invoke(null) as MainCoroutineDispatcher
109+
}
110+
return dispatcher.getOrNull()
111+
}
99112

100113
/**
101114
* If anything goes wrong while trying to create main dispatcher (class not found,

ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public sealed class HandlerDispatcher : MainCoroutineDispatcher(), Delay {
3333

3434
@Keep
3535
internal class AndroidDispatcherFactory : MainDispatcherFactory {
36+
companion object {
37+
@JvmStatic // accessed reflectively from core
38+
fun getDispatcher(): MainCoroutineDispatcher = Main
39+
}
40+
3641
override fun createDispatcher(): MainCoroutineDispatcher = Main
3742

3843
override val loadPriority: Int

0 commit comments

Comments
 (0)