https://kotlinlang.org logo
#compose
Title
# compose
k

Kevin Worth

03/08/2023, 4:51 PM
Compose + (State)Flow question. Given the following code (from this template project)
Copy code
@Composable
fun MyModelScreen(modifier: Modifier = Modifier, viewModel: MyModelViewModel = hiltViewModel()) {
    val lifecycle = LocalLifecycleOwner.current.lifecycle
    val items by produceState<MyModelUiState>(
        initialValue = MyModelUiState.Loading,
        key1 = lifecycle,
        key2 = viewModel
    ) {
        lifecycle.repeatOnLifecycle(state = STARTED) {
            viewModel.uiState.collect { value = it }
        }
    }
    if (items is MyModelUiState.Success) {
        MyModelScreen(
            items = (items as MyModelUiState.Success).data,
            onSave = viewModel::addMyModel,
            modifier = modifier
        )
    }
}
how would one “restart” the collection if/when
uiState
runs into a
catch
which cancels the subscription? In my case
uiState
is (slightly different from the template), something like
flowA.flatMapLatest {...flowB...}.map { Success(it) }.catch { emit(Error(it)) }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), Loading)
(though, for the sake of the question, I’m not really sure that detail matters…) I’ve tried things like displaying an error with an “Ok” button, and the button modifies the value of
key1
or
key2
(say, for instance, one of the keys is an
Int
which gets incremented when you press the “Ok” button), but no joy.
z

Zach Klippenstein (he/him) [MOD]

03/08/2023, 5:02 PM
k

Kevin Worth

03/08/2023, 5:10 PM
I have tried adding
retry
before the
catch
and yes, that can work. But, the problem is you (can) either loop forever (don’t limit the number of retries) or eventually end up in the
catch
and you’re back to being out of luck.
The
retry
really felt like it was good when seeing the app run as expected, but it felt gross when it came to running the tests and realizing it was just looping forever.
z

Zach Klippenstein (he/him) [MOD]

03/08/2023, 8:16 PM
I’m not sure I understand what you actually want - if you want to retry an unlimited number of times on failure, then yea if the failure continues to happen you’re going to loop forever. In general, if the flow is throwing an exception other than CancellationException, I would treat that as a bug and propagate it out of the effect right away to either crash the app (production) or fail tests. Otherwise you’re gonna run into all kinds of gross scenarios like this, missing real production bugs, thinking you’ve recovered from a deeper underlying failure state, etc.
k

Kevin Worth

03/08/2023, 8:58 PM
@Zach Klippenstein (he/him) [MOD] totally get it. I’m with you. I’d like to find the balance between that and doing something as simple as showing an error to the user and allowing them to hit a button to acknowledge the error and start over.
Ahhh, wait, you’ve led me somewhere, I think. If in the
retry
I set state which is used above it (in say the
flatMapLatest
) then it won’t keep looping. Something like,
isReady
or something. Set that to false, have that return an
Error
result (separate from the one in the
catch
), and I should be good to go, I think. Thanks!
z

Zach Klippenstein (he/him) [MOD]

03/08/2023, 9:02 PM
That sounds better, yea