Ignoring an exception from a single run with Flow
See original GitHub issueIgnoring an exception from a single run with Flow
I’m currently in a project where the local Room database exposes Flow
to observe database changes.
Say I’m building a chain of operators before collecting the results from the database to shape my data for the user interface.
If any of the statements throw an exception before collecting, is there any way to skip/ignore that single run and continue the flow?
I understand that using the catch()
operator allows me to have a fallback (using emit or emitAll) for the entire Flow, not a single run within the Flow. If I use emit
, I will collect the value I emitted and the flow completes because it is a single value, definitely not ideal for Room as I would lose notifications. Using emitAll
is not suitable for this case as I would need to repeat my entire chain, it would be preferable to use retryWhen
. In my case, using the retryWhen
operator might be enough, but not ideal. Whenever an exception comes up, a new query is made to the database and the Flow always emits the initial state of the database.
Ideally, I could start the Flow
once and if an exception was thrown during the run of a specific value I could simply log it or have a dedicated state for it and keep listening for future emissions. Retry should be optional.
In a shorter example
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.*
fun main() {
runBlocking {
(0..5).asFlow()
.onEach { check(it != 3) }
.collect { println(it) }
}
}
In this case, how could I ignore the run that throws the exception and move on until number 5? Try catching inside a Flow feels wrong 😢
A less predictable example
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.*
fun main() {
runBlocking {
userRepo.fetchCachedUserIds()
.map {
fetchUserDetails(it) // An exception-prone network call
}
.collect { println(it) }
}
}
In this case, we subscribe to a list of users that is stored locally and wish to enrich the user interface by fetching some details remotely. How can I start this flow only once and handle a possible exception from the network without stop listening for future values?
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:16 (7 by maintainers)
Top GitHub Comments
I’m using bidirectional streams in grpc. How can I deal with exceptions from server? I’m not sure that creating new flow each time I got connection exception is a good idea. I’m using coroutine stub and I have no places to catch exception from server (proto files generates method that returns flow)
@fvasco I am not sure I understood your point. I am not assuming a Flow can emit
(item|exception)*
, I assume a you can emititems
and throwexceptions
.The behaviour of the example with your implementation of the use case would be printing that AuthorizationException in case the check failed. I believe that is how
catch
would behave as well. The only difference is that withcatch
the Flow would complete and withcatchOnEach
it would not, unless you re-throw that exception and there is no othercatch
/catchOnEach
downstream to catch it. I believe the operator would be very similar tocatch
, that’s why I am not getting how it disrupts the spec.