CoroutineScope 取消监听

CoroutineScope cancel listener

我正在 class 中使用 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) } }
  }
}

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

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

您可以使用异常处理程序

// 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 将被调用 仅当抛出异常时

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

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

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

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

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

但我还是觉得它不太吸引人。