0

I have a counter logic using Flow in ViewModel, and auto increment.

class MainViewModel(
    private val savedStateHandle: SavedStateHandle
): ViewModel() {

    val counterFlow = flow {
        while (true) {
            val value = savedStateHandle.get<Int>("SomeKey") ?: 0
            emit(value)
            savedStateHandle["SomeKey"] = value + 1
            delay(1000)
        }
    }
}

In the Activity

val counterFlowStateVariable = viewModel.externalDataWithLifecycle.collectAsStateWithLifecycle(0)

This counter will only increment and count during the App is active

  • It stops increment when onBackground, and continues when onForeground. It doesn't get reset. This is made possible by using collectAsStateWithLifecycle.
  • It stops increment when the Activity is killed by the system and restores the state when the Activity is back. The counter value is not reset. This is made possible by using savedStateHandle

I'm thinking if I can use a stateFlow instead of flow?

Elye
  • 53,639
  • 54
  • 212
  • 474

1 Answers1

0

I would say, you should. flow is cold, meaning it has no state, so previous values aren't stored. Because your source of emitted values is external (savedStateHandle) and you mix emitting and saving that value within the flow builder, you introduce a synchronization problem, if more than one collector is active.

Perform small test:

// this value reflects "saveStateHandle"
var index = 0
val myFlow = flow {
  while(true) {
      emit(index)
      index++
      delay(300)
  }
}

Now collect it three times:

launch {
    myFlow.collect {
        println("First: $it")
    }
}
delay(299)
launch {
    myFlow.collect {
        println("second: $it")
    }
}
delay(599)
launch {
    myFlow.collect {
        println("third: $it")
    }
}

You'll start noticing that some collectors are reading previous values (newer values already read by other collectors), meaning their save operation will use that previous value, instead up to date one.

Using stateFlow you "centralize" the state read/update calls, making it independent of a number of active collectors.

var index = 0
val myFlow = MutableStateFlow(index)
launch {
    while (true) {
        index++
        mySharedFlow.value = index
        delay(300)
    }
    
}
Krzysztof Borowy
  • 538
  • 1
  • 5
  • 21