StateFlow and SharedFlow

Barış Keser
Appcent
Published in
3 min readDec 18, 2023

The Kotlin Flow library provides a component supporting reactive and asynchronous programming. Within this library, there are two significant types of flows, namely StateFlow and SharedFlow. In this article, we will concentrate on the fundamental differences between StateFlow and SharedFlow and discuss scenarios for the use of each.

What is the StateFlow?

StateFlow is a type of flow that represents the current state of a stream and can broadcast this state. In other words, StateFlow tracks the moment when a value changes and conveys the updated value to all subscribers observing it. StateFlow is commonly used, particularly for managing situations like UI (user interface) updates.

class ExampleViewModel : ViewModel() {
private val _currentState = MutableStateFlow("Initial State")
val currentState: StateFlow<String> = _currentState

fun updateState(newState: String) {
_currentState.value = newState
}
}

In the example above, the StateFlowViewModel class contains a private MutableStateFlow named _currentState. This is exposed externally through a StateFlow named currentState. The updateState function updates the current state.

StateFlow and LiveData

StateFlow and LiveData are similar constructs, both featuring observable data with different behaviors:

  • StateFlow requires an initial value, unlike LiveData.
  • The observe function in LiveData automatically cancels listening when the lifecycle transitions to the STOPPED state and resumes when it transitions to the STARTED state. However, the collect function in StateFlow does not automatically stop; to achieve similar behavior, the flow must be collected within a Lifecycle.repeatOnLifecycle block.
val flow = flow {
(1..3).forEach {
emit(it)
}
}
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
flow.collect{
println(it)
}
}
}

In the example above, the flow is collected only when lifecycle is in the STARTED state.

What is the SharedFlow?

SharedFlow is a type of flow that allows multiple subscribers to share the same values. Unlike StateFlow, when one subscriber receives a value, other subscribers can also receive that value. This enables updates to be instantly received by multiple subscribers from different locations.

class SharedFlowExample {
private val _sharedFlow = MutableSharedFlow<String>()
val sharedFlow: SharedFlow<String> = _sharedFlow

fun emitValue(value: String) {
viewModelScope.launch {
_sharedFlow.emit(value)
}
}
}

In the example above, the SharedFlowExample class contains a private MutableSharedFlow named _sharedFlow, and exposes this flow through a SharedFlow named sharedFlow. The emitValue function adds a new value to the shared flow.

StateFlow vs SharedFlow

While StateFlow requires an initial value, SharedFlow does not.

val _stateFlow = MutableStateFlow("Initial State")
val _sharedFlow = MutableSharedFlow<String>()

StateFlow only emits the latest value, while SharedFlow, with the use of the replay operator, can emit previous values as well.

val stateFlow = MutableStateFlow(0)
runBlocking {
stateFlow.value = 1
stateFlow.value = 2
stateFlow.value = 3
launch {
stateFlow.collect {
println(it)
}
}
}
Output:
3
val sharedFlow = MutableSharedFlow<Int>(replay = 3)
runBlocking {
launch {
sharedFlow.emit(0)
sharedFlow.emit(1)
sharedFlow.emit(2)
sharedFlow.emit(3)
sharedFlow.collect() {
println(it)
}
}
}
Output:
1
2
3

StateFlow emits consecutively repeating values only once. SharedFlow emits all values without any condition.

val stateFlow = MutableStateFlow(0)
runBlocking {
launch {
stateFlow.collect {
println(it)
}
}
stateFlow.value = 1
stateFlow.value = 1
stateFlow.value = 2
stateFlow.value = 2
stateFlow.value = 3
}
Output:
0
1
2
3
val sharedFlow = MutableSharedFlow<Int>()
runBlocking {
launch {
sharedFlow.collect {
println(it)
}
}
sharedFlow.emit(0)
sharedFlow.emit(1)
sharedFlow.emit(1)
sharedFlow.emit(2)
sharedFlow.emit(2)
sharedFlow.emit(3)
}
Output:
0
1
1
2
2
3

References

--

--