Skip to main content
Donovan LaDuke - Developer

Reactive Programming in Kotlin - StateFlow

Featured in Android Weekly Issue 598

The final Flow type to cover is the StateFlow, which is a child of SharedFlow. To learn more about SharedFlow and specifically what a "hot" flow is, check out the previous article here. Now to dive into what makes StateFlow special.

StateFlow is a specific SharedFlow #

Unlike the differences between a Flow and a SharedFlow, SharedFlow and StateFlow have a lot in common. In fact you can make your own StateFlow by setting up a SharedFlow with a very specific set of properties. First set the replay value to 1 so only the single most recent value is re-emitted to subscribers. Next, set the buffer policy to DROP_OLDEST so the only item in the buffer is the current value. Then immediately tryEmit the initial value. Finally, apply the distinctUntilChanged() operator.

This setup covers the most important things to know about a StateFlow

Using a StateFlow #

A StateFlow is created using the MutableStateFlow constructor or by using stateIn() applied to a Flow.

val mutable = MutableStateFlow(initialValue = "Hello")
val stateFlow = mutable.asStateFlow()

val myFlow = flowOf(1,2,3)
val flowSharedFlow = myFlow.stateIn(
    scope = coroutineScope, 
    started = SharingStarted.Lazily, 
    initialValue = "Hello"

Since the buffer policy is a drop policy instead of a suspend policy, there is no tryEmit vs emit. Instead the value is updated either directly or using the .update functions. Both functions work very similarly but .update and its siblings (updateAndGet and getAndUpdate) are atomic operations on the value, preventing tricky race conditions.

val myFlow = MutableStateFlow("Hello")

myFlow.value = "Good Bye"

myFlow.update { current ->
  // New value is result of this block
  current + " for now!"

myFlow.value // "Good Bye for now!"

Just like all other Flow types, a StateFlow can be collected using a terminal operator, but additionally the latest value can be accessed using the .value property.

val stateFlow = MutableStateFlow("Hello").asStateFlow()

// Subscribe to value
stateFlow.collect { ... }

// Get the current value one time
val currentValue = stateFlow.value

Conclusion #

All the features of StateFlow make it an excellent option for managing state and is the preferred object for exposing state to consume in Jetpack Compose. A single current value that can be easily accessed combined with the power of reactivity makes StateFlow a bit of the best of both worlds. This is the last post on this topic for now, but feel free to email me if there are questions or future topics of interest in this area. Until next time, thanks!

Did you find this content helpful?

Please share this post and be sure to subscribe to the RSS feed to be notified of all future articles!

Want to go above and beyond? Help me out by sending me $1 on Ko-fi. It goes a long way in helping run this site and keeping it advertisement free. Thank you in advance!

Buy me a Coffee on Ko-fi