在 Kotlin 流程中取消后发出

Emit after cancellation in Kotlin flow

我有以下代码的更复杂版本:

val testFlow = flow {
    try {
        // Continually emit some values
    } catch (e: CancellationException) {
        // Wrap up and emit finished state value
    }
}

当我收集这个 testFlow 时,我从未收到完成状态值。 documented 流生成器在发出值之前执行 ensureActive 检查。在此 link 中也是一个使用 IntRange.asFlow 的示例,它在发出值之前不检查取消并显示继续收集这些值。

有没有办法让自定义 kotlin 流在取消协程后发出要收集的最后一个值?

这里有一个 Kotlin Playground example(感谢 @Tenfour04)显示取消后发出的不同行为,具体取决于流程的构建方式。我只是不知道如何获得不是由 IntRange.asFlow.

构造的取消后能够发出的流

IntRange.asFlow 在内部使用 unsafeFlow 定义为:

inline fun <T> unsafeFlow(crossinline block: suspend FlowCollector<T>.() -> Unit): Flow<T> {
    return object : Flow<T> {
        override suspend fun collect(collector: FlowCollector<T>) {
            collector.block()
        }
    }
}

使用 unsafeFlow 甚至可以在已取消的协程中发出信号,尽管这个解决方案是一个 hack,我想用一个不需要访问内部 Kotlin Coroutine API 的更官方支持的版本来替换它。

注意:取消后发射仅在使用

时有效
try {
    ...
} catch (e: CancellationException) {
    ...
}

并且不使用 unsafeFlow.catch {}