【问题标题】:CoroutineScope cancel listenerCoroutineScope 取消监听器
【发布时间】:2021-08-24 09:20:50
【问题描述】:

我正在使用 Scope 的类中执行一些工作:

class MyClass(val scope: CoroutineScope) {

  private val state: StateFlow<Int> = someFlow()
    .shareIn(scope, started = SharingStared.Eagerly, initialValue = 0)

  fun save() {
    scope.launch {
      save(state.value)
    }
  }
}

现在我想在取消范围时进行清理。做这个的最好方式是什么?我可以想出这个,但这听起来不太稳定。

init {
  scope.launch {
    try { delay(10000000000000) }
    finally { withContext(Noncancellable) { save(state.value) } }
  }
}

编辑:我已经修改了我的 sn-p 以更多地反映我正在做的事情。 state Flow 每秒更新几次,当我调用 save() 方法时,我想将状态保存到磁盘(所以我不想在每次状态更改时都这样做)。

接下来,我想在取消范围时保存状态(即在最后)。这就是我遇到麻烦的地方。

【问题讨论】:

  • 您要清理什么?所有启动的协程都将在范围取消时被取消,因此在其中运行的所有代码都会抛出CancellationException。在这些协程的代码中使用finallyuse { ... } 块将自动清理。
  • @Joffrey 我已经进行了编辑!
  • 感谢编辑,我现在知道了。我猜在这种情况下,范围很可能绑定到某种生命周期(您实际上取消它的地方)。我认为直接挂钩该生命周期而不是通过范围间接挂钩可能更合适。
  • 是的,这是正确的,虽然我希望这样的事情是可能的。
  • 我在我的回答中添加了一个“更清洁”的替代方法来替代您当前的解决方法

标签: kotlin kotlin-coroutines


【解决方案1】:

据我所知,CoroutineScope 上没有这样的“onCancellation”机制。

一般来说,在执行需要清理的代码时,清理可以在现场“准备好”。例如,使用use { ... } 的输入流或使用finally 块关闭资源。 这将在取消(或任何其他失败,顺便说一句)时自动兑现,因为取消范围只会在正在运行的协程中生成 CancellationExceptions。

现在,有时(如您的情况)您有更复杂的需求,在这种情况下,我会说取消范围只是在某种生命周期结束时发生的一件事,您可以这样做您需要在取消范围的同一位置进行清理。

如果你真的想使用像当前并行协程这样的解决方法,你可以使用awaitCancellation 而不是巨大的延迟:

init {
  scope.launch {
    try { awaitCancellation() }
    finally { withContext(Noncancellable) { save(state.value) } }
  }
}

但我仍然觉得它不是很吸引人。

【讨论】:

  • 感谢awaitCancellation 的来电!我会看看我的想法。
【解决方案2】:

您可以使用异常处理程序

// Destroy service when completed or in case of an error.
val handler = CoroutineExceptionHandler { _, exception ->
    Log.e("CoroutineExceptionHandler Error", exception.message!!)
    stopSelf(startId)
}

那么你就可以把这个Handler当作

scope.launch(handler){
// do stuff
}

handler只有在抛出异常时才会被调用

【讨论】:

  • 我认为这不是我想要的。在我的情况下我将如何使用它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 2020-11-20
  • 2021-06-13
  • 2023-03-25
相关资源
最近更新 更多