What is a SharedFlow in Kotlin coroutines, and how does it differ from a regular (cold) Flow?
answer
- Hot + multicast = SharedFlow
- Cold flow { } restarts per collector
- MutableSharedFlow = producer side (emit/tryEmit)
- asSharedFlow() to expose read-only
- No initial value unlike StateFlow
basics
~10 sSharedFlow is a hot stream that broadcasts the same values to all collectors at the same time. A regular Flow is cold and re-runs its code separately for each collector.
solid answer
~40 sA SharedFlow is a hot Flow: it stays active independently of collectors and broadcasts each emitted value to all current subscribers simultaneously. A cold Flow (built with flow { }) is inert until collected and restarts its producer block for every collector, so each collector gets its own independent run. SharedFlow is created via MutableSharedFlow(...), you push values with emit (suspending) or tryEmit (non-suspending), and read-only consumers see it typed as SharedFlow. It has no current value by default and no initial value, which makes it a natural event bus for one-off events (navigation, toasts, signals). It is the broadcast superclass of StateFlow.
go deeper
Can state hot vs cold and that SharedFlow broadcasts to all collectors.
Explains the read-only/mutable split and asSharedFlow() encapsulation, and the no-initial-value contrast with StateFlow.
Frames SharedFlow as an event bus, mentions replay/buffer knobs and never-completes semantics, and knows it's StateFlow's superclass.
Reasons about when broadcast-event semantics fit the architecture vs StateFlow/Channel and the lifecycle/back-pressure implications of a never-completing hot stream.
## Cold vs Hot A **cold** Flow (created with `flow { ... }`) is just a recipe: nothing runs until you call `collect`, and the producer block runs **separately for each collector**. Two collectors each get their own independent execution. A **hot** Flow exists and runs independently of whether anyone is collecting. `SharedFlow` is the canonical hot, multicast (broadcast) Flow: a single emitter feeds **all** active collectors the same values at the same time. ## SharedFlow vs MutableSharedFlow - `SharedFlow<T>` is the **read-only** interface a consumer collects from. - `MutableSharedFlow<T>` adds the producer side: `emit` and `tryEmit`. - You typically keep a private `MutableSharedFlow` and expose it as a public `SharedFlow` via `asSharedFlow()` so outsiders can't emit. ```kotlin private val _events = MutableSharedFlow<UiEvent>() val events: SharedFlow<UiEvent> = _events.asSharedFlow() suspend fun signal() { _events.emit(UiEvent.Refresh) } ``` ## Key properties - **No initial value / no current value**: unlike `StateFlow`, a fresh `SharedFlow` has nothing to show a new subscriber unless `replay > 0`. - **Multicast**: every collector observes the same emissions; the flow never terminates on its own. - **Buffering**: configurable via `replay`, `extraBufferCapacity`, and `onBufferOverflow`. ## When to use it Use `SharedFlow` for **events** that should fire once and be delivered to whoever is listening: navigation commands, snackbars, analytics signals. Use `StateFlow` for **state** (a single current value). For turning a cold Flow hot, prefer the `shareIn` operator (a sibling topic) rather than manual emission.
- Why expose MutableSharedFlow as SharedFlow with asSharedFlow()?To enforce encapsulation: external code can collect but cannot emit, keeping the producer the single source of emissions.
- Does a SharedFlow ever complete?No, by design it never completes on its own; collectors stay subscribed until their coroutine is cancelled.
A cold Flow is a vending machine each person operates themselves; a SharedFlow is a live radio broadcast everyone tuned in hears at once.
saying these in an interview costs you the question
- Claiming SharedFlow re-runs a producer block per collector (that's cold flow)
- Saying SharedFlow always has a current value (it doesn't unless replay>0)
- Confusing SharedFlow with Channel and assuming exactly-once-per-consumer delivery
- Thinking collect() on a SharedFlow eventually returns normally