调用scope.cancel后是否还会收到Flow emit?协程取消是否完全同步?
解答
1. Scope取消不是100%同步操作
CoroutineScope.cancel() 只会给对应作用域下的所有子协程打上取消标记,调用后会立刻返回,不会阻塞等待所有协程真正终止。协程只有运行到挂起点时才会检测取消状态、抛出CancellationException结束运行,存在非常小的取消响应窗口期。
2. 示例代码中的collect完全有可能收到null,使用!!操作符不安全
你在遍历执行完所有scope的cancel()后立刻执行了删除用户操作,而此时部分协程可能还没完成取消响应。如果Room的user()返回的Flow在数据库删除用户后触发了null值的下发,刚好对应collect的协程还没检测到取消标记,就会收到null值。
就算没有触发删除后的null下发,只要取消和删除的执行时序存在重叠窗口,就有空指针风险,绝对不要在这个场景下用!!。
3. Flow的取消逻辑和Rx的dispose类似,但取消时效性更弱
标准Flow的所有内置操作符都默认会检测协程的激活状态,协程取消后不会再继续下发后续事件,这一点和RxJava被dispose后不再下发事件的逻辑是一致的。
区别在于RxJava的dispose是同步检查,调用dispose后基本不会再收到后续事件;而协程取消依赖挂起点触发检测,如果你自定义Flow没有主动调用ensureActive()做状态检查,或者事件刚好在取消标记生效前完成下发,就有可能收到最后一次残留事件。
内容的提问来源于stack exchange,提问作者urSus
相关产品推荐
相关产品推荐

