【问题标题】:Cancelling custom CoroutineScope取消自定义 CoroutineScope
【发布时间】:2021-06-13 12:21:35
【问题描述】:
val scope = CoroutineScope(
        Job() + Dispatchers.Main
)
scope.launch {
    beforeExecute()
    val result = withContext(dispatcher) { doInBackground(*params) }
    if (!isCancelled) {
        postExecute(result)
    } else {
        cancelled(result)
    }
    status = Status.FINISHED
}
scope.cancel()

如果我将scope.cancel() 放在启动之外,它会立即取消协同程序而不调用启动块代码。这是预期的吗?为什么会发生?如果我希望协同程序在完成后结束,应该将取消放在启动块末尾的启动内在启动内执行代码?

更新

根据 Hau Luu 的回答和 Marko Topolnik 的评论,

”在启动结束时,我认为任务已经完成,你不需要 手动取消协程。”

“一旦你的任务完成,协程就会从内存中消失。”

但是在案例 2 中,如果我启动另一个启动,除非我们像案例 1 一样取消第一次启动中的协程,否则它会被执行。 那么是否可以确定在任务完成后协程会在我们手动调用 cancel() 的情况下从内存中消失?Bcoz 编译器永远不会知道要执行的最后一次启动是什么,之后它需要结束协程

案例 1

scope.launch {
    Log.e("Task","1");
    scope.cancel()
}
scope.launch {
    Log.e("Task","2");
}

仅打印任务 1

案例 2

scope.launch {
    Log.e("Task","1");
}
scope.launch {
    Log.e("Task","2");
}

打印任务 1 和 2

【问题讨论】:

  • 除非执行此协程的对象已被处置且其结果不再相关,否则不应取消范围。如果您在发布启动块后立即取消范围,您期望会发生什么?
  • @Pawel 我希望一旦我的任务完成,协程应该停止运行。协程的 AFAIK 生命周期取决于我们使用的范围,如果我使用像 viewmodelscope 这样的内置范围,那么 lifecyale 与生命周期相关联viewmodel 的。但是我在这里使用自定义 CoroutineScope。如何确保协程在我的任务完成后不会保留在内存中?我在抽象类 final 方法中使用此代码,我的任务在 status = Status.FINISHED 行之后完成。
  • 正如您所说,viewmodelscope 与 viewmodel 的生命周期相关联,因此您应该将范围与类的生命周期联系起来。声明一个协程执行的范围是没有意义的。如果它是静态方法,那么您不妨将其发布在 GlobalScope 上,因为协程一旦执行完毕就不会留在内存中。
  • @Pawel 我相信 GlobalScope 与应用程序的生命周期有关,不应使用!
  • @AndroidDeveloper 是的!理论上,它应该是。但由于我无法检查 CS (CoroutineScope) 的存在,所以我无法确认。因为作用域内协程的生命周期可能比启动它的方法的生命周期长。

标签: android kotlin kotlin-coroutines


【解决方案1】:

您的代码可以翻译成自然语言“在 scope.launch 执行后立即取消给定的协程”,所以我认为这是预期的行为。

对于另一个问题,我们只想在执行过程中出现问题时取消协程 - 嘿协程,在执行我给你的任务期间。如果有错误发生。杀死自己。所以在启动结束时,我认为任务已经完成,您不需要手动取消协程。

更新:我写这个作为答案,因为我不能在评论中写代码。

CoroutineScope 旨在对创建/启动/容纳协程的对象的生命周期做出反应。因此,当您在 CoroutineScope 上调用取消方法时,您将停止一切。停止不取消。作用域创建的所有子协程,它们正在执行的所有作业,都取消它们,仅此而已。工作完成了。这就是为什么你不能在 scope.cancel 之后开始另一个启动

CoroutineScope 将通过启动和异步等构建器方法创建并保存一组 Corrountine 的引用。当你想取消一个特定的协程时。您需要取消构建器返回的作业。不要取消容纳它们的范围。

https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html

val job1 = scope.launch{ print('Task 1') }
job1.cancel()
val job2 = scope.launch{ print('Task 2') }

任务 2 将正常打印。

【讨论】:

  • 协程的 AFAIK 生命周期取决于我们使用的范围,如果我使用像 viewmodelscope 这样的内置范围,那么生命周期与 viewmodel 的生命周期相关联。但这里我使用的是自定义 CoroutineScope。我怎样才能确保一旦我的任务完成,协程就不会保留在内存中?我相信我需要为此使用取消!
  • 一旦你的任务完成,协程就会从内存中消失。在这方面它与Thread 几乎相同。 thread.start(); thread.interrupt(); 你不会这样做,协程也是如此。
  • @MarkoTopolnik 编译器可以知道哪个是要执行的最后一次启动,之后它需要结束协程吗?请根据您的评论和 Hau Luu 的回答检查我的问题中的“更新”部分跨度>
  • 你认为scope是协程吗? CoroutineScope 只是一个简单的数据对象,它不包含任何资源。 launch 创建协程,完成后消失。仅当您想突然取消所有恰巧仍在范围内运行的协程时才使用scope.cancel(),因为您的应用程序中某些组件的生命周期即将结束。
  • 我已经更新了我的答案,因为评论编辑器很难使用。对不起!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 1970-01-01
  • 2019-06-13
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多