I am facing an issue wherein when updating stateFlow value in viewmodel from multiple threads, for some of the value I am not getting callback in UI. As an experiment I have tried the following
Below is the viewmodel code.
class MainViewModel : ViewModel() {
private val _value = MutableStateFlow(-1)
val value = _value.asStateFlow()
var count = 0
fun startUpdate() {
viewModelScope.launch(Dispatchers.IO) {
async {
updateFrom1()
}
async {
updateFrom1000()
}
}
}
fun updateValue(value: Int) {
_value.update { value }
}
suspend fun updateFrom1() = withContext(Dispatchers.IO) {
for (i in 1..1000) {
updateValue(i)
Log.d("Ujjwal", "UpdateFrom1 :$i")
}
}
suspend fun updateFrom1000() = withContext(Dispatchers.IO) {
for (i in 1000 downTo 1) {
updateValue(i)
Log.d("Ujjwal", "UpdateFrom1000 :$i")
}
}
}
And here is my activity code
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewmodel = MainViewModel()
setContent {
MyApplicationTheme {
// A surface container using the 'background' color from the theme
MyFunction(viewmodel)
}
}
}
}
@Composable
fun MyFunction(viewModel: MainViewModel) {
val value by viewModel.value.collectAsState()
when (value) {
else -> {
viewModel.count = viewModel.count + 1
Text(text = "value is ${viewModel.count}")
Log.d("Ujjwal", "count is : ${viewModel.count}")
}
}
LaunchedEffect(Unit ){
viewModel.startUpdate()
}
}
My expectation is at the end I want the value of count to be 2000 (That is it should get executed for all the updates of _value
)
For the function I have tried the following variant, but none of them have worked
fun updateValue(value: Int) {
_value.update { value }
}
fun updateValue(value: Int) {
viewModelScope.launch {
_value.update { value }
}
}
fun updateValue(value: Int) {
viewModelScope.launch(Dispatchers.IO) {
_value.update { value }
}
}
fun updateValue(value: Int) {
viewModelScope.launch(Dispatchers.IO) {
_value.value = value
}
}
fun updateValue(value: Int) {
viewModelScope.launch {
_value.value = value
}
}
fun updateValue(value: Int) {
viewModelScope.launch {
_value.emit(value)
}
}
fun updateValue(value: Int) {
viewModelScope.launch(Dispatchers.IO) {
_value.emit(value)
}
}
suspend fun updateValue(value: Int) = withContext(Dispatchers.IO) {
_value.emit(value)
}
suspend fun updateValue(value: Int) = withContext(Dispatchers.IO) {
_value.value = value
}
fun updateValue(value: Int) {
viewModelScope.launch {
mutex.withLock {
_value.value = value
}
}
}
Is there anything that I am missing or having some wrong assumption of how stateFlow is supposed to behave ?
For each execution, I get different value of count (usually around 8-14)