StateFlow vs SharedFlow in Kotlin: Key Differences and Usage
StateFlow is a hot flow that always holds a single updatable state and replays the latest value to new subscribers, while SharedFlow is a more general hot flow that can replay multiple values and does not hold state by default. Use StateFlow for state management and SharedFlow for event streams or broadcasts.Quick Comparison
This table summarizes the main differences between StateFlow and SharedFlow in Kotlin.
| Feature | StateFlow | SharedFlow |
|---|---|---|
| Type | Hot flow with state | Hot flow without state by default |
| Value Holding | Always holds latest value | Does not hold value unless replay > 0 |
| Replay Behavior | Replays only the latest value | Can replay multiple values based on replay parameter |
| Use Case | State management (UI state) | Event streams, broadcasts, one-time events |
| Initial Value | Requires initial value | No initial value required |
| Subscribers Behavior | New subscribers get latest state immediately | New subscribers get replayed events if configured |
Key Differences
StateFlow is designed to represent a state that changes over time. It always holds a current value and emits it immediately to any new subscriber. This makes it perfect for UI state management where you want to show the latest state instantly.
On the other hand, SharedFlow is more flexible and general-purpose. It does not hold a state by default and can be configured to replay zero or more past values to new subscribers. This makes it ideal for broadcasting events like navigation commands or messages that should be handled once or multiple times.
Another key difference is that StateFlow requires an initial value when created, ensuring there is always a state to emit. SharedFlow does not require an initial value and can be configured with different replay and buffer sizes to control how many past events are replayed or buffered.
Code Comparison
Here is an example showing how to use StateFlow to hold and update a simple counter state.
import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { val stateFlow = MutableStateFlow(0) // initial value 0 // Launch a coroutine to collect state updates val job = launch { stateFlow.collect { value -> println("StateFlow value: $value") } } // Update the state stateFlow.value = 1 delay(100) stateFlow.value = 2 delay(100) job.cancel() }
SharedFlow Equivalent
Here is a similar example using SharedFlow to emit events without holding state.
import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { val sharedFlow = MutableSharedFlow<Int>(replay = 0) // no replay // Launch a coroutine to collect events val job = launch { sharedFlow.collect { value -> println("SharedFlow event: $value") } } // Emit events sharedFlow.emit(1) delay(100) sharedFlow.emit(2) delay(100) job.cancel() }
When to Use Which
Choose StateFlow when you need to represent and observe a state that always has a current value, such as UI state or configuration data. It ensures new subscribers immediately receive the latest state.
Choose SharedFlow when you want to broadcast events or messages that do not represent state, like user actions, navigation commands, or one-time notifications. It offers more flexibility with replay and buffering options.
Key Takeaways
StateFlow always holds and replays the latest state value to new subscribers.SharedFlow is a flexible event stream that can replay multiple past events or none.StateFlow for continuous state updates and SharedFlow for discrete events.StateFlow requires an initial value; SharedFlow does not.StateFlow) or event broadcasting (SharedFlow).