androidandroid-viewmodelkotlin-flowandroid-architecture

How to keep a flow alive on errors / restart it?


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?
}
  1. 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?

  2. In which case would one reach catch exception case 1?


Solution

  • You should use retryWhen instead of catch, it's the most powerful operator for working with exceptions in Flow.

    It allows you to:

    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.