【问题标题】:Cancelling parent job without using explicit Job() object在不使用显式 Job() 对象的情况下取消父作业
【发布时间】:2020-10-02 05:33:54
【问题描述】:

在下面的代码中,我创建了两个作业,然后我取消了父作业。我希望子作业会被取消,但是,子作业不会被取消,它们仍然处于活动状态。为什么?

注意:我知道这个问题很容易解决,方法是创建一个 Job() 对象,然后将 Job 对象提供给协程上下文,然后取消 Job() 对象。我的问题是为什么下面的代码不起作用?如果我想取消父作业,我必须使用显式父参数吗?

fun main() {

    // CoroutineScope
    val coroutineScope = CoroutineScope(Dispatchers.IO)

    var child1 : Job? = null
    var child2 : Job? = null

    // Use
    val currentJob = coroutineScope.launch {
        child1 = coroutineScope.launch {
            delay(500)
        }
        child2 = coroutineScope.launch {
            delay(500)
        }
    }

    Thread.sleep(300L)

    currentJob.cancel()

    println("Job 1 state: ${child1?.status()}")
    println("Job 2 state: ${child2?.status()}")
    println("Parent job is active: ${coroutineScope.isActive}")
    println("Parent job is active: ${currentJob.isActive}")


    Thread.sleep(2000L)
}

输出:

Job 1 state: Active
Job 2 state: Active
Parent job is active: true
Parent job is active: false

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    child1child2 作业不是 currentJob 的子级。他们是coroutineScope Job 的孩子。我们可以说currentJobchild1child2 是“兄弟姐妹”。如果您想全部取消它们,请取消 coroutineScope 而不是:coroutineScope.cancel() 。或者让他们成为currentJob的孩子并取消currentJob

    val currentJob = coroutineScope.launch {
        child1 = launch {
            delay(500)
        }
        child2 = launch {
            delay(500)
        }
    }
    
    Thread.sleep(300L)
    
    currentJob.cancel()
    

    【讨论】:

    • @oiyio 在内部传递的 CoroutineScope 对象上调用启动,该对象将这些任务作为子项注册到其作业中。
    • 天哪。我现在意识到了...好吧,您建议的代码会按我的预期打印孩子。但是 coroutineScope.isActive 返回仍然是 true。为什么?
    • @oiyio 因为您只取消了currentJob,这将取消child1child2。试试这个coroutineScope.cancel() 取消整个范围。
    猜你喜欢
    • 2023-03-31
    • 2020-02-10
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 2014-06-15
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多