Issue
I have a more complex version of the following code:
val testFlow = flow {
try {
// Continually emit some values
} catch (e: CancellationException) {
// Wrap up and emit finished state value
}
}
When I collect this testFlow, I never receive the finished state value. It is documented that the flow builder performs ensureActive checks before emitting values. In this link is also an example using IntRange.asFlow
that does not check for cancellation before emitting values and showing that those values are continued to be collected.
Is there a way to make a custom kotlin flow emit a last value to be collected after the cancellation of the coroutine?
Here's a Kotlin Playground example (thanks @Tenfour04) showing differing behaviour of emit after cancel depending on how the flow is constructed. I just don't know how to get a flow that's able to emit after cancel that is not constructed by IntRange.asFlow
.
Solution
IntRange.asFlow
uses unsafeFlow internally which is defined as:
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()
}
}
}
Using unsafeFlow one can emit even in cancelled coroutines, even though this solution is quite a hack and I would like to replace it with a more officially supported version that does not require to access internal Kotlin Coroutine APIs.
Note: Emitting after cancellation only works when using
try {
...
} catch (e: CancellationException) {
...
}
and not using unsafeFlow.catch {}
.
Answered By - 1387
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.