Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin SharedFlow and catching Exceptions

I am on an Android project using Kotlin and Flows. My team wants to handle non-nominal cases by throwing exceptions. If a class uses a MutableStateFlow, using it to expose a Flow, how can an exception be emitted to that MutableStateFlow so that the consumer can 'catch' and act on the exception? (Is this approach even possible?)

For a code example.

method2().catch{
    // How can I catch an exception thrown from evaluateEnvStatus?
}.collect {
    // ....
}


val mutableSharedFlow = MutableSharedFlow<String>()
suspend fun evaluateEnvStatus(){
    if(isEnvAcceptable){
        mutableSharedFlow.emit("Acceptable")
    else {
        // How can I throw an exception here that can be caught by someone consuming the SharedFlow?
    }
}

fun updateEnvStatus : Flow<String> {
    scope.launch(){
       method1()
    }
    return mutableSharedFlow
}
like image 892
eimmer Avatar asked Feb 02 '26 06:02

eimmer


1 Answers

You can't "throw" an exception from SharedFlow because that would mean it completed and SharedFlows never end.

If you want to emit failure to collectors you have to instead expose a cold flow that transforms value of your shared flow and throws then.

For example:

private val _messageFlow = MutableSharedFlow<Result<String>>()
val messageFlow = _messageFlow.map { it.getOrThrow() }

// where you produce values:
private suspend fun evaluateEnvStatus(){
    if(isEnvAcceptable){
        _messageFlow.emit(Result.success("Acceptable"))
    } else {
        _messageFlow.emit(Result.failure(IllegalArgumentException("Unacceptable")))
    }
}

// collecting:
// to stop collecting on exception catch it
messageFlow
    .catch { exception ->  } // handle exception
    .collect { message -> } // String

// to keep collecting after exception, retry the cold flow *
messageFlow
    .retry { exception -> true } // handle exception and return true
    .collect { message -> } // String

Do note that retrying has a big caveat: even though you will restart the flow collection, any values emitted between exception and restart won't be handled and so will be values in buffer (if you enable it). So I would not actually recommend it for this case.

If you really need to collect all values I don't think there's a better solution to just emitting a wrapped error and parsing it on collector side without using any exception handling.

like image 196
Pawel Avatar answered Feb 03 '26 23:02

Pawel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!