Reputation: 87
I am trying to switch from LiveData to StateFlow in populating my ListAdapter.
I currently have a MutableLiveData<List<CustomClass>>
that I am observing to update the list adapter as such:
viewModel.mutableLiveDataList.observe(viewLifecycleOwner, Observer {
networkIngredientAdapter.submitList(it)
}
This works fine. Now I am replacing the MutableLiveData<List<CustomClass>?>
with MutableStateFlow<List<CustomClass>?>
in the viewModel as such:
private val _networkResultStateFlow = MutableStateFlow<List<IngredientDataClass>?>(null)
val networkResultStateFlow : StateFlow<List<IngredientDataClass>?>
get() = _networkResultStateFlow
fun loadCustomClassListByNetwork() {
viewModelScope.launch {
//a network request using Retrofit
val result = myApi.myService.getItems()
_networkResultStateFlow.value = result
}
}
I am collecting the new list in a fragment as such:
lifecycleScope.launchWhenStarted {
viewModel.networkResultStateFlow.collect(){
list -> networkIngredientAdapter.submitList(list)}
}
However, the list Adapter does not update when I call loadCustomClassListByNetwork(). Why am I not able to collect the value
Upvotes: 0
Views: 2122
Reputation: 87
I haven't mentioned in the original question but there are two collect calls being made in the created coroutine scope as such:
lifecycleScope.launchWhenStarted {
viewModel.networkResultStateFlow.collect(){
list -> networkIngredientAdapter.submitList(list)}
viewModel.listOfSavedIngredients.collectLatest(){
list -> localIngredientAdapter.submitList(list)}
}
Previously only the first collect call was working so that only one list was updating. So I just created two separate coroutine scopes as such and it now works:
lifecycleScope.launchWhenStarted {
viewModel.networkResultStateFlow.collect(){
list -> networkIngredientAdapter.submitList(list)}
}
lifecycleScope.launchWhenStarted {
viewModel.listOfSavedIngredients.collectLatest(){
list -> localIngredientAdapter.submitList(list)}
}
Note: Using launch
, launchWhenStarted
or launchWhenCreated
yielded the same results.
I'll edit my response once I figure out the reason for needing separate scopes for each call to collect.
EDIT: So the reason only one listAdapter was updating was because I needed a separate CoroutineScope for each of my StateFlow since Flows by definition run on coroutines. Each flow uses its respective coroutine scope to collect its own value and so you cannot have flows share the same coroutine scope b/c then they would be redundantly collecting the same value. The answer provided by @ruby6221 also creates a new coroutine scope and so likely works but I cannot test it due to an unrelated issue with upgrading my SDK version, otherwise I would set it as the correct answer.
Upvotes: 0
Reputation: 286
Try to replace code in fragment with below:
lifecycleScope.launch {
viewModel.networkResultStateFlow.flowWithLifecycle(lifecycle)
.collect { }
}
Upvotes: 1