svenjacobs
08/18/2022, 9:51 AMval uiState: StateFlow<UiState> =
combine(
firstFlow,
secondFlow,
thirdFlow,
) { first, second, third ->
UiState(
first = first,
second = second,
third = third,
)
}.stateIn(...)
Flow
arguments. Starting with six or more arguments combine
takes a vararg Flow<T>
or Iterable<Flow<T>>
. This means all Flows must be of the same type or - if not - the type becomes Any
. Then we lose type safety and must cast to the right types, which is subpar.
When I encounter this, I combine logical units of Flows into their own data classes (or Pair
or Triple
), something like
val combinedFlow = combine(
firstFlow,
secondFlow,
) { first, second ->
CombinedState(
first = first,
second = second,
)
}
val uiState: StateFlow<UiState> =
combine(
combinedFlow,
thirdFlow,
) { (first, second), third ->
UiState(
first = first,
second = second,
third = third,
)
}.stateIn(...)
But even this solution has its limitations when there are no more logical units of Flows to build and there are still more than five distinct Flows.
How do you approach this problem? What are your solutions?Zoltan Demant
08/18/2022, 10:22 AMsvenjacobs
08/18/2022, 10:36 AMMutableStateFlow
and setting attributes of UiState
individually. Because this usually also means launching multiple coroutines, possibly in init
of ViewModel? I think having one public StateFlow
is safer (resource wise) and less verbose.combine
variants to my project myself, like you suggested. I’m wondering if someone already wrote a library for that?Tgo1014
08/18/2022, 10:59 AMsvenjacobs
08/18/2022, 11:05 AMCsaba Szugyiczki
08/18/2022, 11:14 AMMyViewModel(repo: Repo) {
val name: StateFlow<String> = repo.name
val description: StateFlow<String> = repo.description
val cout: StateFlow<Int> = repo.count
}
Instead of this:
MyViewModel(repo: Repo) {
val state: StateFlow<MyState> = combine(repo.name, repo.description, repo.count) {name, description, count
MyState(name, description, count)
}
class MyState(
val name: String
val description: String
val count: Int
)
}
svenjacobs
08/18/2022, 11:39 AMval name = viewModel.name.collectAsState()
val description = viewModel.description.collectAsState()
...
instead of one single
val uiState = viewModel.uiState.collectAsState()
In the end it’s a matter of personal taste but Compose is able to efficiently only recompose those parts of a UI that are affected by changed UI state properties, even if they are combined in a single data class (assuming the data class itself is stable).UiState
is just what I saw in a lot of official Compose examples and blog posts lately.Csaba Szugyiczki
08/18/2022, 11:42 AMsvenjacobs
08/18/2022, 11:43 AMAmrJyniat
08/19/2022, 5:00 AM