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
)