StateFlow vs SharedFlow

Flow and StateFlow Mid-level Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Predict the output

What does the collector print?

fun main() = runBlocking {
    val state = MutableStateFlow(0)
    val job = launch { state.collect { println(it) } }
    yield()
    state.value = 1
    state.value = 1
    yield()
    job.cancel()
}
Options
Hint 1 of 2

Does a new collector see the current value?

Hint 2 of 2

What does StateFlow do with an equal value?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A 0, then 1

Correct. The initial value is replayed, and setting the same value again is skipped.

Why not the others?
  • B 0, then 1, then 1. StateFlow ignores a value equal to the current one.
  • C 1, then 1. A new collector gets the current value (0) first.
  • D Nothing, because the collector starts too late. StateFlow replays the current value to new collectors.

30-second answer

StateFlow holds exactly one current value, always has an initial value, replays it to new collectors and skips values equal to the last one. It models state, like screen UI state. SharedFlow has no current value, can replay zero or more items and doesn't de-duplicate, so it suits broadcasts of events to several listeners.

Practise saying it · 35 s. No recording, just a timer

Explain StateFlow vs SharedFlow.

Say your answer out loud, then check which of these points you covered:

  • StateFlow holds one value with an initial value
  • It replays and skips equal values
  • SharedFlow is for broadcasts with configurable replay
  • Expose read-only types

Deep dive

MutableStateFlow(initial) is like MutableSharedFlow(replay = 1, onBufferOverflow = DROP_OLDEST) with that initial value, plus distinctUntilChanged and a readable .value.

Expose read-only types from a ViewModel: val state: StateFlow<UiState> = _state.asStateFlow().

StateFlow is conflated: a slow collector only sees the latest value, not every intermediate one.

SharedFlow with replay = 0 drops values emitted when nobody is collecting.

Common mistakes

  • Using StateFlow for one-time events, then seeing them again after rotation.
  • Expecting every StateFlow update to reach a slow collector.
  • Exposing the Mutable type from the ViewModel.

Senior take & follow-ups

The one-liner: StateFlow is a value, SharedFlow is a stream. Then mention conflation and equality skipping.

Follow-up questions

Think of your answer first, then open the hint.

  1. Why might the same toast show again after rotation?

    Show hint

    It's stored in a StateFlow, which replays the current value.

  2. What does extraBufferCapacity do?

    Show hint

    Lets emit not suspend when collectors are slow, up to that many items.

Similar on iOS: PassthroughSubject vs CurrentValueSubject CurrentValueSubject is the nearest match to StateFlow, but it doesn't skip equal values.

Suggest a fix if something here is wrong or out of date.