Reputation: 2335
The Code A is based a Android offical sample project here.
The Code A can display correct data in UI.
If I use Code B, I find that nothing is displayed.
It seems that _uiState=_uiState.copy(...)
doesn't make uiState
to notice UI that the data has changed in Code B.
What is wrong with Code B?
Code A
class InterestsViewModel(
private val interestsRepository: InterestsRepository
) : ViewModel() {
// UI state exposed to the UI
private var _uiState by mutableStateOf (InterestsUiState(loading = true)) //My
val uiState: InterestsUiState = _uiState //My
private fun refreshAll() {
_uiState .loading = true //My
viewModelScope.launch {
// Trigger repository requests in parallel
val topicsDeferred = async { interestsRepository.getTopics() }
val peopleDeferred = async { interestsRepository.getPeople() }
val publicationsDeferred = async { interestsRepository.getPublications() }
// Wait for all requests to finish
val topics = topicsDeferred.await().successOr(emptyList())
val people = peopleDeferred.await().successOr(emptyList())
val publications = publicationsDeferred.await().successOr(emptyList())
_uiState.loading=false //My
_uiState.topics=topics //My
_uiState.people=people //My
_uiState.publications=publications //My
}
}
}
fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent> {
// UiState of the InterestsScreen
val uiState = interestsViewModel.uiState //My
...
}
data class InterestsUiState(
var topics: List<InterestSection> = emptyList(), //My
var people: List<String> = emptyList(), //My
var publications: List<String> = emptyList(), //My
var loading: Boolean = false, //My
)
Code B
class InterestsViewModel(
private val interestsRepository: InterestsRepository
) : ViewModel() {
// UI state exposed to the UI
private var _uiState by mutableStateOf (InterestsUiState(loading = true))
val uiState: InterestsUiState = _uiState
private fun refreshAll() {
_uiState .loading = true
viewModelScope.launch {
// Trigger repository requests in parallel
val topicsDeferred = async { interestsRepository.getTopics() }
val peopleDeferred = async { interestsRepository.getPeople() }
val publicationsDeferred = async { interestsRepository.getPublications() }
// Wait for all requests to finish
val topics = topicsDeferred.await().successOr(emptyList())
val people = peopleDeferred.await().successOr(emptyList())
val publications = publicationsDeferred.await().successOr(emptyList())
_uiState=_uiState.copy(
loading = false,
topics = topics,
people = people,
publications = publications
)
}
}
}
Upvotes: 0
Views: 949
Reputation: 29875
I don't see your pattern described in the official docs:
https://developer.android.com/jetpack/compose/state
It is possible it worked under an older version of Compose and doesn't work under the current version??
According to the docs, recomposition can only occur when you use mutableStateOf
in conjunction with a remember
and set the value property to a new value to trigger the recomposition:
val someProperty = remember { mutableStateOf(0) }
someProperty.value = 123
But this is done in a composable. If you want to trigger this within your viewmodel, you should resort to using LiveData. Here's an example:
https://stackoverflow.com/a/69718724/753632
Using mutableStateOf on its own doesn't trigger recomposition. It is only used to store the state.
Upvotes: 1