In my Android ViewModel I have code like this:
try {
myRepository
.getAllData()
.catch {
Timber.e("catch exception case 1")
Timber.e(it)
}
.collect { data ->
// use data to set UI state
uiState = uiState.copy(data = data)
}
} catch(e: Exception) {
Timber.e("catch exception case 2")
Timber.e(e)
// how to keep the flow alive or restart it?
}
During testing I reached catch exception case 2
. In this case I want to display an error to the user, but keep the Flow
alive (e.g. if users presses a retry button which could then send successful data over the Flow
). However in my understanding the Flow
is automatically cancelled due to the exception? How to restart the Flow
or prevent it from being cancelled at all?
In which case would one reach catch exception case 1
?
You should use retryWhen
instead of catch
, it's the most powerful operator for working with exceptions in Flow
.
It allows you to:
Throwable
Flow
.Conceptually you could do something like this:
myRepository
.getAllData()
.retryWhen { cause, attempt ->
Timber.e("catch exception case 1")
Timber.e(it)
// Emit UiState downstream to show error
emit(UiState.Error(cause))
// Or predicate based on cause
true
}
.collect { data ->
// use data to set UI state
uiState = uiState.copy(data = data)
}
Unless uiState = uiState.copy(data = data)
can throw an exception, which I assume it won't. This code will never fail.
To make it fail, you should either return false
to retryWhen
or re throw a different exception from within retryWhen
.