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()
}
}
此示例从 coroutine guide 复制并由
launch(Dispatchers.Main)
协程扩展。我不明白为什么需要第 4 行中的 + Dispatchers.Main
。如果我删除这部分 launch
协程,如果 Activity 被销毁,无论如何都会取消。那么 Dispatchers.Main
的原因是什么?为什么也没有添加 Dispatchers.IO
? 最佳答案
当你写这个:
launch(Dispatchers.Main) {
try {
delay(Long.MAX_VALUE)
} catch (e: Exception) {
// e will be a JobCancellationException if the activty is destroyed
}
}
你可能没有意识到
launch
实际上是用你的 ScopedAppActivity
作为接收者调用的。所以你有效地写了this.launch(Dispatchers.Main) { ... }
launch
是 CoroutineScope
上的一个扩展函数,它将使用它的 coroutineContext
作为起点,将它与您在括号中指定的任何内容结合起来。所以,在你的情况下,有效的上下文是job + Dispatchers.Main + Dispatchers.Main
可以想象,这等于
job + Dispatchers.Main
因此,当您从
Dispatchers.Main
中删除 coroutineContext
时,没有任何变化。在
Dispatchers.Main
中提供coroutineContext
的好处是不用每次都提供,直接写launch { ... }
并且
launch
中的块将停留在 GUI 线程上,这是在 Android 和其他 GUI 应用程序上使用协程最自然的方式。由于该行不是关于声明您将使用的所有调度程序,而是默认调度程序,因此提供多个调度程序是没有意义的。
在另一个层面上,
CoroutineContext
不是一个列表(这是 +
操作符隐含的),而是一个映射。 +
语法有效,因为您添加的每个对象都声明了自己的映射键,+
使用该键将其放入上下文的内部映射中。所以实际上不可能将两个调度器放在一个 CoroutineContext
中。关于android - 为什么必须将 "Dispatchers.Main"添加到 Activity CoroutineScope 实现的根作业中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53324408/