Kotlin’s Flow API has transformed the way we think about asynchronous data streams. But when your app needs to hold state or broadcast events, two specialized types of Flows shine the brightest: StateFlow and SharedFlow.
In this guide, we’ll break down StateFlow and SharedFlow in a simple way. Whether you’re working with Jetpack Compose, MVVM, or traditional Android UI, you’ll understand when and how to use each one — with examples.
StateFlow — Holds a State
StateFlow is similar to LiveData and is used to store a single state that updates over time.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val stateFlow = MutableStateFlow(0)
val job = launch {
stateFlow.collect { value ->
println("Collector received: $value")
}
}
delay(500)
stateFlow.value = 1
delay(500)
stateFlow.value = 2
delay(500)
job.cancel()
}
//Output
Collector received: 0
Collector received: 1
Collector received: 2
StateFlow always emits the latest value to collectors. It behaves like LiveData, and collectors receive the current state immediately upon subscription.
SharedFlow — Broadcasts Data to Multiple Collectors
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
// Create a MutableSharedFlow with a buffer capacity of 2
val sharedFlow = MutableSharedFlow<Int>(
replay = 0,
extraBufferCapacity = 2
)
val job1 = launch {
sharedFlow.collect { value ->
println("Collector 1 received: $value")
}
}
val job2 = launch {
sharedFlow.collect { value ->
println("Collector 2 received: $value")
}
}
// Delay to ensure collectors are active before emitting
delay(100)
sharedFlow.emit(10)
sharedFlow.emit(20)
delay(500)
job1.cancel()
job2.cancel()
}
// Output
Collector 1 received: 10
Collector 2 received: 10
Collector 1 received: 20
Collector 2 received: 20
By default, MutableSharedFlow
has no buffer and replay = 0
, meaning it won’t emit any value unless a collector is ready at the moment of emission.
- We set
extraBufferCapacity = 2
, allowingSharedFlow
to buffer a couple of values while the collectors start. - We add
delay(100)
before emitting, ensuring both collectors are already collecting.
This way, both collectors reliably receive all values.
SharedFlow broadcasts emitted values to all active collectors. It’s great for one-time events (like navigation, snackbars, etc.), and multiple collectors will receive the same emissions.
Conclusion
Kotlin’s StateFlow
and SharedFlow
are powerful tools to build reactive UIs that are predictable, scalable, and cleanly architected. Understanding the difference between state and event helps you choose the right flow for the right situation.