Rafiul Islam
11/26/2024, 2:14 PMdata class UiState (
val isLoading: Boolean = false,
val posts: List<Post> = emptyList(),
val errorMessage: String? = null
)
Rafiul Islam
11/26/2024, 2:15 PMval pokemon = savedStateHandle.getStateFlow<Pokemon?>("pokemon", null)
val pokemonInfo: StateFlow<PokemonInfo?> =
pokemon.filterNotNull().flatMapLatest { pokemon ->
detailsRepository.fetchPokemonInfo(
..
)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = null,
)
Stylianos Gakis
11/26/2024, 2:27 PMdetailsRepository
responds with a new value, it will be emitted from this StateFlow.
What is the problem you're facing here, are you concerned that you are creating a whole new object of Pokemon
every time even one small thing may change?Rafiul Islam
11/26/2024, 2:43 PMprivate val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
Stylianos Gakis
11/26/2024, 2:50 PMval pokemon = savedStateHandle.getStateFlow<Pokemon?>("pokemon", null)
val otherState = MutableStateFlow(OtherState())
val uiState: StateFlow<LocationsUiState> = combine(
pokemon.filterNotNull().flatMapLatestToPokemonInfo(),
otherState,
) { pokemonInfo, otherState ->
LocationsUiState(
pokemonInfo = pokemonInfo,
whateverElse = otherState.whateverElse
)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = null,
)
And so on. You'd need to merge your sources of information in a combine, and then map them to your one UiState model, all before you do the stateIn
so that you still get the right behavior where if there are no listeners anymore, the flows stop being collected for no reason.Rafiul Islam
11/26/2024, 3:03 PMStylianos Gakis
11/26/2024, 3:05 PMRafiul Islam
11/27/2024, 6:44 AMinit {
savedStateHandle.getStateFlow<String?>("id", null)
.filterNotNull()
.onEach { id ->
getSomething(id)
}
.launchIn(viewModelScope)
}
Rafiul Islam
11/27/2024, 7:21 AMStylianos Gakis
11/27/2024, 8:04 AMRuben Quadros
12/10/2024, 4:15 AMcombine
should work or even merge
will work when the operations are independent.
So on user events, you will end up updating the _uiState
. Basically, instead of multiple states, you now have only 2 things - loadInitialData
for the initial data and then _uiState
for every other update.
val loadInitialData: () -> Flow<STATE> = someFlow()
val _uiState: MutableStateFlow<STATE> = MutableStateFlow(initialState)
val uiState: StateFlow<STATE> = merge(loadInitialData(), _uiState).stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = someInitialState
)