从 CoroutineScope 启动的 Job 和 SupervisorJob 也是一个 SupervisorJob 吗?
Is Job launched from CoroutineScope with SupervisorJob also a SupervisorJob?
在下面的例子中。 childJob 是 SupervisorJob 吗?
val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val childJob = viewModelScope.launch {/* do something */}
或类似的东西是必要的:
val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val childJob = viewModelScope.launch(SupervisorJob()) {/* do something */}
据我了解 SupervisorJob 它不会影响 children 也将其修改为表现得像 SupervisorJob,也就是说 children SupervisorJob 不会失败parent 作业,但是如果 children 的 child 作业失败,那么那些 children 也会失败。该行为不会通过作业的 children 传递。
在我看来,这也是有道理的,因为您的取消等默认行为应该是相同的,直到您为一个特定的协程更改它。
要回答您的问题,您需要明确声明您想要启动具有 SupervisorJob 行为的协程。
我会让代码来说话:
fun main() = runBlocking {
val scopeSupervisor = SupervisorJob()
val explicitSupervisor = SupervisorJob()
val explicitPlainJob = Job()
val scope = CoroutineScope(Dispatchers.Main + scopeSupervisor)
scopeSupervisor.printJobClass("scopeSupervisor")
explicitPlainJob.printJobClass("explicitPlainJob")
println()
scope.launch {
coroutineContext.printJobClass("context 1")
scopeSupervisor.printChildren("scopeSupervisor")
}.join()
scope.launch(explicitSupervisor) {
coroutineContext.printJobClass("context 2")
explicitSupervisor.printChildren("explicitSupervisor")
}.join()
scope.launch(explicitPlainJob) {
coroutineContext.printJobClass("context 3")
explicitPlainJob.printChildren("explicitPlainJob")
}.join()
}
fun CoroutineContext.printJobClass(msg: String) {
println("$msg class: ${this[Job]!!.className}")
}
fun Job.printChildren(msg: String) {
println("$msg children: ${children.map { it.className }.joinToString()}")
}
val Any.className get() = this::class.java.simpleName
这会打印
scopeSupervisor class: SupervisorJobImpl
explicitPlainJob class: JobImpl
context 1 class: StandaloneCoroutine
scopeSupervisor children: StandaloneCoroutine
context 2 class: StandaloneCoroutine
explicitSupervisor children: StandaloneCoroutine
context 3 class: StandaloneCoroutine
explicitPlainJob children: StandaloneCoroutine
解读:
范围内的作业和显式传入的作业都没有成为与协程关联的作业。协程作业始终是 StandaloneCoroutine
类型,它是传入作业的子作业。
另请注意,传入一个不是作用域作业子项的显式 SupervisorJob
是错误的。如果您取消范围内的顶级作业,这将不会传播到您创建的显式 SupervisorJob
。
在下面的例子中。 childJob 是 SupervisorJob 吗?
val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val childJob = viewModelScope.launch {/* do something */}
或类似的东西是必要的:
val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val childJob = viewModelScope.launch(SupervisorJob()) {/* do something */}
据我了解 SupervisorJob 它不会影响 children 也将其修改为表现得像 SupervisorJob,也就是说 children SupervisorJob 不会失败parent 作业,但是如果 children 的 child 作业失败,那么那些 children 也会失败。该行为不会通过作业的 children 传递。
在我看来,这也是有道理的,因为您的取消等默认行为应该是相同的,直到您为一个特定的协程更改它。
要回答您的问题,您需要明确声明您想要启动具有 SupervisorJob 行为的协程。
我会让代码来说话:
fun main() = runBlocking {
val scopeSupervisor = SupervisorJob()
val explicitSupervisor = SupervisorJob()
val explicitPlainJob = Job()
val scope = CoroutineScope(Dispatchers.Main + scopeSupervisor)
scopeSupervisor.printJobClass("scopeSupervisor")
explicitPlainJob.printJobClass("explicitPlainJob")
println()
scope.launch {
coroutineContext.printJobClass("context 1")
scopeSupervisor.printChildren("scopeSupervisor")
}.join()
scope.launch(explicitSupervisor) {
coroutineContext.printJobClass("context 2")
explicitSupervisor.printChildren("explicitSupervisor")
}.join()
scope.launch(explicitPlainJob) {
coroutineContext.printJobClass("context 3")
explicitPlainJob.printChildren("explicitPlainJob")
}.join()
}
fun CoroutineContext.printJobClass(msg: String) {
println("$msg class: ${this[Job]!!.className}")
}
fun Job.printChildren(msg: String) {
println("$msg children: ${children.map { it.className }.joinToString()}")
}
val Any.className get() = this::class.java.simpleName
这会打印
scopeSupervisor class: SupervisorJobImpl
explicitPlainJob class: JobImpl
context 1 class: StandaloneCoroutine
scopeSupervisor children: StandaloneCoroutine
context 2 class: StandaloneCoroutine
explicitSupervisor children: StandaloneCoroutine
context 3 class: StandaloneCoroutine
explicitPlainJob children: StandaloneCoroutine
解读:
范围内的作业和显式传入的作业都没有成为与协程关联的作业。协程作业始终是 StandaloneCoroutine
类型,它是传入作业的子作业。
另请注意,传入一个不是作用域作业子项的显式 SupervisorJob
是错误的。如果您取消范围内的顶级作业,这将不会传播到您创建的显式 SupervisorJob
。