如何监听CoroutineScope取消事件,实现Scope销毁时自动保存StateFlow状态
最优实现方案
推荐方案:使用协程原生invokeOnCompletion监听
你原来的方案靠超长delay等待Scope取消的写法存在冗余,且极端场景下如果协程被异常终止可能漏触发,直接使用协程上下文提供的生命周期监听API即可稳定实现需求:
class MyClass(val scope: CoroutineScope) { private val state: StateFlow<Int> = someFlow() .shareIn(scope, started = SharingStarted.Eagerly, initialValue = 0) init { // 监听Scope根Job的终止事件,正常取消、异常崩溃都会触发 scope.coroutineContext.job.invokeOnCompletion { // 用Noncancellable上下文保证保存逻辑不会被中断 CoroutineScope(Noncancellable).launch { runCatching { save(state.value) }.onFailure { // 可自行添加保存失败的日志处理逻辑 it.printStackTrace() } } } } fun save() { scope.launch { save(state.value) } } private suspend fun save(value: Int) { // 原有保存到磁盘的逻辑 } }
方案优势
- 无冗余的无效delay逻辑,不占用额外协程资源
- 覆盖所有Scope终止场景:主动调用cancel、Scope内部未捕获异常导致销毁、父协程取消传导
- 触发时机准确,正好是Scope生命周期结束的最后节点,符合你的需求
可选替代方案:awaitCancellation写法
如果你更偏好结构化的协程写法,可以用标准库提供的awaitCancellation()替代原来的超长delay,可读性和稳定性更高:
init { scope.launch { // 直接挂起直到当前协程被取消,不需要写死超时时间 awaitCancellation() }.invokeOnCompletion { CoroutineScope(Noncancellable).launch { runCatching { save(state.value) } } } }
注意事项
- 保存逻辑必须包裹在
Noncancellable上下文中执行,否则Scope取消后协程会被立即中断,导致保存逻辑执行不完整 - 建议给保存逻辑加异常捕获,避免IO等异常导致额外崩溃
- StateFlow的
value属性是线程安全的,高频率更新下直接读取即可,不需要额外加锁
内容的提问来源于stack exchange,提问作者nhaarman
相关产品推荐
相关产品推荐

