What do the shareIn and stateIn operators do to a cold Flow, and what is the difference between their results?
answer
- Cold restarts per collector; hot shared once
- shareIn -> SharedFlow (replay configurable)
- stateIn -> StateFlow (always has .value)
- Both need scope + SharingStarted
- stateIn needs initialValue
basics
~10 sBoth turn a normal Flow that restarts for each collector into a shared one that runs once for everybody. shareIn gives a SharedFlow; stateIn gives a StateFlow that always has a current value.
solid answer
~40 sA cold Flow re-executes its producer block for every collector. shareIn and stateIn convert it into a hot flow whose single upstream is shared by all collectors. shareIn(scope, started, replay) returns a SharedFlow with a configurable replay cache. stateIn(scope, started, initialValue) returns a StateFlow, which is a SharedFlow specialization that always holds exactly one latest value (.value), conflates updates, and emits that value immediately to new collectors. Both need a CoroutineScope to host the shared upstream coroutine and a SharingStarted policy controlling when the upstream starts and stops. stateIn requires an initialValue (unless you use the suspending stateIn overload that waits for the first emission); shareIn does not.
code
kotlin · 3 linesval shared: SharedFlow<Int> = upstream.shareIn(scope, SharingStarted.Lazily, replay = 1)
val state: StateFlow<Int> = upstream.stateIn(scope, SharingStarted.Eagerly, initialValue = 0)
println(state.value) // StateFlow always has a current valuego deeper
Knows shareIn yields SharedFlow and stateIn yields StateFlow, and that both make a cold flow shared.
Explains cold-vs-hot precisely and why stateIn needs an initialValue while shareIn does not.
Connects sharing to deduplicating an expensive upstream (one subscription for N collectors) and notes conflation/distinct semantics of StateFlow.
Frames the choice as an API/lifecycle contract decision and reasons about scope ownership and resource lifetime implications.
## Cold vs hot A **cold** `Flow` is lazy: the lambda you pass to `flow { ... }` (or operators like `map`) re-runs *from scratch* for **each** collector. Two collectors mean two independent executions. A **hot** flow has a single producer running independently of collectors, and all collectors observe the *same* stream. `shareIn` and `stateIn` are the operators that **convert cold to hot** inside a `CoroutineScope`. ## shareIn ```kotlin fun <T> Flow<T>.shareIn( scope: CoroutineScope, started: SharingStarted, replay: Int = 0 ): SharedFlow<T> ``` It launches a coroutine in `scope` that collects the upstream once and re-emits items into a `SharedFlow`. `replay` is how many recent values are cached and replayed to new collectors. ## stateIn ```kotlin fun <T> Flow<T>.stateIn( scope: CoroutineScope, started: SharingStarted, initialValue: T\): StateFlow<T> ``` A `StateFlow` is a special `SharedFlow` that **always has a value** (`.value`), keeps exactly one latest value (`replay = 1`, conflated), and only emits when the value changes (distinct via `equals`). New collectors immediately get the current value. ## Why a scope and SharingStarted The shared upstream coroutine must live in some scope (e.g. `viewModelScope`). `SharingStarted` decides *when* that upstream coroutine actually starts and stops collecting — `Eagerly`, `Lazily`, or `WhileSubscribed(...)`. ## Key contrast - `shareIn` -> `SharedFlow`, replay configurable, no initial value, can have zero cached values. - `stateIn` -> `StateFlow`, always one current value, needs `initialValue`, conflates and de-duplicates.
- Why does stateIn require an initialValue but shareIn does not?A StateFlow must always have a current value available via .value for any new collector, so it needs a seed before the upstream emits. SharedFlow can legitimately have zero cached values.
- Does converting to hot change how many times the upstream runs?Yes — the upstream now runs at most once (shared) instead of once per collector, which is often the whole point (e.g. one network/db subscription).
Cold flow is cooking a fresh meal per guest; shareIn/stateIn is a buffet everyone shares from one kitchen.
saying these in an interview costs you the question
- Saying shareIn and stateIn are interchangeable
- Claiming the upstream still restarts per collector after conversion
- Thinking StateFlow can exist without a current value
- Forgetting that a CoroutineScope is required
- Confusing replay count with initialValue