0
0
KotlinComparisonIntermediate · 4 min read

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.

FeatureStateFlowSharedFlow
TypeHot flow with stateHot flow without state by default
Value HoldingAlways holds latest valueDoes not hold value unless replay > 0
Replay BehaviorReplays only the latest valueCan replay multiple values based on replay parameter
Use CaseState management (UI state)Event streams, broadcasts, one-time events
Initial ValueRequires initial valueNo initial value required
Subscribers BehaviorNew subscribers get latest state immediatelyNew 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.

kotlin
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()
}
Output
StateFlow value: 0 StateFlow value: 1 StateFlow value: 2
↔️

SharedFlow Equivalent

Here is a similar example using SharedFlow to emit events without holding state.

kotlin
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()
}
Output
SharedFlow event: 1 SharedFlow event: 2
🎯

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.
Use StateFlow for continuous state updates and SharedFlow for discrete events.
StateFlow requires an initial value; SharedFlow does not.
Pick based on whether you need state retention (StateFlow) or event broadcasting (SharedFlow).