您的当前位置:首页正文

kotlin协程中使用Dispatchers.Main报错的问题

2024-11-26 来源:个人技术集锦

在刚开始接触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的话就没有必要使用它了。

显示全文