I'm using a MutableMap to save the data which is updates every 5 seconds and I expect also to be updated the UI showing part of the Map. After trying different solution I found that if I add another Double variable both Map and Double are updated on the UI but if I keep only Map variable nothing changes:
ViewModel Variables:
private val _stockRealPriceFlow = MutableStateFlow<MutableMap<String, Double>>(mutableMapOf())
val stockRealPriceFlow: StateFlow<MutableMap<String, Double>> = _stockRealPriceFlow.asStateFlow()
private val _draftPrice = MutableLiveData<Double>()
val draftPrice: LiveData<Double> = _draftPrice
ViewModel Variables Update:
_stockRealPriceFlow.value[it.name] = it.currentPrice()
_draftPrice.value = stockRealPriceFlow["Draft"] ?: 0.0
Activity:
val stockRealPriceFlow by viewModel.stockRealPriceFlow.collectAsState()
val draftPrice by viewModel.draftPrice .observeAsState(0.0)
Column(
modifier = Modifier
.padding(8.dp)
) {
Text(text = stockRealPriceFlow["Draft"].toString())
Text(text = draftPrice.toString())
}
How that can be explained if the MutableMap variable is same in both cases? What is the correct way of working with the map on this case?
I expect UI always show the Map values.
The StateFlow doesn't provide a new value, that's why your UI won't update. Instead, the same MutableMap
is updated with new/changed values. That won't trigger a new value for the flow, though.
The solution is to never expose mutable values in your view model:
private val _stockRealPriceFlow = MutableStateFlow<Map<String, Double>>(emptyMap())
val stockRealPriceFlow: StateFlow<Map<String, Double>> =
_stockRealPriceFlow.asStateFlow()
To update the map of the mutable flow you need to replace the map with a new one that contains the updated element. Instead of setting _stockRealPriceFlow.value[it.name] = it.currentPrice()
you should use this:
_stockRealPriceFlow.update { oldMap->
oldMap + (it.name to it.currentPrice())
}