I have a view and its ViewModel consists of UI state for a search query and results for the query.
The search query is a string and I can hold its state in the ViewModel like this:
data class SearchUiState(
val query: String = ""
)
class SearchViewModel(
private val resultsRepository: ResultsRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(SearchUiState())
val uiState = _uiState.asStateFlow()
}
Now, the search results come as a Flow like this: Flow<List<Result>>
.
I read you should collect a flow in the UI (source: What is the proper way to wait for a Flow to collect?)
So, I can do that by converting the Flow
into a StateFlow
in the ViewModel
.
class SearchViewModel(
private val resultsRepository: ResultsRepository
) : ViewModel() {
// ...
val resultsUiState: StateFlow<resultsUiState> =
resultsRepository.getResultsStream(_queryUiState.value.query).map { ResultsUiState(it) }
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
initialValue = ResultsUiState()
)
}
Then, in the UI, I can collect the StateFlow
.
@Composable
fun SearchScreen(
viewModel: SearchViewModel
) {
val resultsUiState = viewModel.resultsUiState.collectAsState()
// ...
}
But then now, I need to also collect the UI state of the search query separately from the same ViewModel
.
@Composable
fun SearchScreen(
viewModel: SearchViewModel
) {
val resultsUiState = viewModel.resultsUiState.collectAsState()
val queryUiState = viewModel.queryUiState.collectAsState()
// ...
}
Is this a good practice to have different UI states held separately in a single ViewModel
?
This post, Android - Best Practices for ViewModel State in MVVM?, suggests to put all UI state into a single state.
How can I achieve this with the queryUiState
and resultsUiState
when collecting a Flow
from the UI?
Thanks in advance.