MutableStateFlow inits value after I set a new one but need to be vice versa

In Kotlin, MutableStateFlow is a type of Flow that represents a value that can be updated and observed by multiple consumers. By default, MutableStateFlow initializes its value lazily, which means that the initial value is not set until the first observer subscribes to the flow.
If you need to set the initial value of a MutableStateFlow before any observers subscribe to it, you can use the tryEmit method to set the value. This method attempts to set the value of the flow immediately, and returns true if the value was successfully set.

So I tried this sample:

val myFlow = MutableStateFlow("initial value")

if (!myFlow.tryEmit("new value")) {
    // Emit failed, handle error
}

And got false. Looks like I have no subscribers as for now.
I need to set the init data only once and also tried this:

coroutineScope.launch {
  merge(myFlow, data).collect {
      with(data.first()) {
         setMyFlow(d1, d2)
      }
      cancel()
  }
}

Unsuccessfully. So, I’m curious how to do it correctly?

From your description I’m not really sure what you try to achieve.

Could you provide a reproducible example in the Kotlin Playground where tryEmit() returns false for you? For me it returns true. To be honest, I would expect tryEmit() for MutableStateFlow to always succeed, because the only thing it has to do is to replace its stored value. I looked into the code and it does exactly this - it always returns true: kotlinx.coroutines/kotlinx-coroutines-core/common/src/flow/StateFlow.kt at 9c1b3afc3bc53b1e6a25a82a66337f606cbf8f2e · Kotlin/kotlinx.coroutines · GitHub

Also, where did you read this quoted text? Either I misread it, or it is entirely wrong. MutableStateFlow doesn’t initialize lazily. Actually, it’s exactly the opposite - state flows are the only flows which we can’t create without providing an initial value.

2 Likes

The quoted text is from ChatGPT. The context is next:

override fun onCreate(savedInstanceState: Bundle?) {
  viewModel.initData(data)
  setContent {
      MainScreen(viewModel)
  }
}

//...
val myFlow = MutableStateFlow(Pair(42,42))

fun initData(data: Flow<Data>){
  viewModelScope.launch {
        with(data.first()) {
           setMyFlow(d1, d2)
        }
        cancel()
  }
}

Found the bug: looks like data: Flow loads after compose was initialized and the value was rewritten.

ChatGPT is very much so not a reliable source for documentation. I’d suggest you consult the documentation for kotlinx-coroutines directly, or at the very least, paste in the documentation for Flow and MutableStateFlow into ChatGPT and then have it explain it.

1 Like

if you don’t care about suspeding until all your subscribers received the new emit, you just want to put a new value in your MutableStateFlow (and subscribers will get this value in the future when they will collect{} your flow) you can just do

val myFlow = MutableStateFlow("initial value")

myFlow.value = "new value"
// at this point the flow holds a new value