为什么必须将“Dispatchers.Main”添加到 Activitys CoroutineScope 实现的根作业中?

use*_*087 4 android kotlin kotlin-coroutines

abstract class ScopedAppActivity: AppCompatActivity(), CoroutineScope {
    protected lateinit var job: Job
    override val coroutineContext: CoroutineContext 
        get() = job + Dispatchers.Main

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        job = Job()

        launch(Dispatchers.Main) {
            try {
                delay(Long.MAX_VALUE)
            } catch (e: Exception) {
                // e will be a JobCancellationException if the activty is destroyed
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    } 
}
Run Code Online (Sandbox Code Playgroud)

这个例子是从协程指南中复制的,并由launch(Dispatchers.Main)协程扩展。我不明白为什么+ Dispatchers.Main需要第 4 行。如果我删除这部分,launch如果 Activity 被销毁,协程无论如何都会被取消。那么是什么原因Dispatchers.Main呢?为什么也Dispatchers.IO没有添加?

Mar*_*nik 6

当你写这个:

launch(Dispatchers.Main) {
    try {
        delay(Long.MAX_VALUE)
    } catch (e: Exception) {
        // e will be a JobCancellationException if the activty is destroyed
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能没有意识到launch实际上是以您的ScopedAppActivity身份调用的。所以你有效地写了

this.launch(Dispatchers.Main) { ... }
Run Code Online (Sandbox Code Playgroud)

launch是一个扩展函数CoroutineScope,它将使用它coroutineContext作为起点,将它与您在括号中指定的任何内容结合起来。所以,在你的情况下,有效的上下文是

job + Dispatchers.Main + Dispatchers.Main
Run Code Online (Sandbox Code Playgroud)

可以想象,这等于

job + Dispatchers.Main
Run Code Online (Sandbox Code Playgroud)

所以当你Dispatchers.Main从你的 中删除时coroutineContext,没有任何变化。

那么 Dispatchers.Main 的原因是什么?

提供Dispatchers.Mainin的好处coroutineContext是你不必每次都提供它,所以你可以直接写

launch { ... }
Run Code Online (Sandbox Code Playgroud)

并且里面的块launch将停留在 GUI 线程上,这是在 Android 和其他 GUI 应用程序上使用协程最自然的方式。

为什么也没有添加 Dispatchers.IO?

由于该行不是关于声明您将使用的所有调度程序,而是默认调度程序,因此提供多个调度程序是没有意义的。

在另一个层面上,CoroutineContext它不是一个列表(这是+运算符隐含的),而是一个映射。该+语法有效,因为您添加的每个对象都声明了自己的映射键,+用于将其放入上下文的内部映射中。所以实际上不可能将两个调度器合二为一CoroutineContext