在刚开始接触kotlin协程的时候,使用Dispatchers.Main操作主线程可能会遇到错误Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used
。这可能是在普通的kotlin项目中使用Dispatcher.Main造成的。
fun main() {
GlobalScope.launch(Dispatchers.Main) {
print("success")
}
}
例如上面这段代码就会出现错误,因为kotlin协程中如果要操作主线程是有条件的,个人理解为需要在一些在主线程中操作UI的项目中才可以使用Dispatcers.Main。
/** In order to work with `Main` dispatcher, the following artifacts should be added to project runtime dependencies:
* - `kotlinx-coroutines-android` for Android Main thread dispatcher
* - `kotlinx-coroutines-javafx` for JavaFx Application thread dispatcher
* - `kotlinx-coroutines-swing` for Swing EDT dispatcher
*
* In order to set a custom `Main` dispatcher for testing purposes, add the `kotlinx-coroutines-test` artifact to
* project test dependencies.
*/
@JvmStatic
public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
从以上的部分注释可以看出如果需要操作主线程的话可以使用 android项目、swing项目、javafx项目,并且引入相对应的运行时依赖。
可以看出操作主线程是与平台相关的。在MainDispatcherLoader中能够发现一些端倪。
// Lazy loader for the main dispatcher
internal object MainDispatcherLoader {
private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)
@JvmField
val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()
private fun loadMainDispatcher(): MainCoroutineDispatcher {
return try {
val factories = if (FAST_SERVICE_LOADER_ENABLED) {
MainDispatcherFactory::class.java.let { clz ->
FastServiceLoader.load(clz, clz.classLoader)
}
} else {
//We are explicitly using the
//`ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
//form of the ServiceLoader call to enable R8 optimization when compiled on Android.
ServiceLoader.load(
MainDispatcherFactory::class.java,
MainDispatcherFactory::class.java.classLoader
).iterator().asSequence().toList()
}
factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
?: MissingMainCoroutineDispatcher(null)
} catch (e: Throwable) {
// Service loader can throw an exception as well
MissingMainCoroutineDispatcher(e)
}
}
}
我们可以看到在loadMainDispatcher函数中使用了MainDispatcherFactory::class.java
,获取到了该类的Javaclass 对象,而该对象在不同平台上是不同的。在android项目中该对象就是kotlinx.coroutines.android.AndroidDispatcherFactory
类的Javaclass对象。在普通项目中Dispatchers.Main是不能被成功的初始化的,所以会出现这个问题。然而其他的几个适配器是可以被使用的,这种设计应该主要是因为Dispatchers.Main的作用就是要在主线程中操作UI,防止UI阻塞,如果没有UI的话就没有必要使用它了。