Flow Context, Errors & Backpressure Flashcards

KOTLIN › Flow

What does context preservation guarantee in Flow?
The collect lambda runs in the context that called collect, whatever the flow does internally. A flow may not change the collector context behind its back, which is why collecting on Main needs no wrapping.
What causes "Flow invariant is violated" and how do you fix it?
Calling emit from a different context than the flow { } builder own, usually by wrapping it in withContext. The fix is flowOn, which moves the producer declaratively. If you genuinely need to emit from another coroutine, use channelFlow or callbackFlow.
Which part of a chain does flowOn affect?
Only what is above it, and only what a lower flowOn has not already claimed. Read a chain bottom-up to work out which stage runs where. The collector always stays in its caller context.
Why does flowOn change timing as well as threading?
Because moving the producer to another dispatcher requires crossing a thread boundary, which flowOn does with a buffered channel. So flowOn implies buffer: the upstream can now run ahead of the collector instead of emitting in lockstep.
What can the catch operator see, and what can it not?
It sees failures from the producer and every operator above it. It cannot see anything below it, and never sees an exception thrown inside the collect lambda. Wrap the whole collect call in try/catch for that.
What does retry actually re-run?
The entire upstream, re-collected from scratch. For a cold flow that means running the producer again, so any side effects in it repeat. retryWhen gives you the attempt index so you can back off between tries.
How does Flow apply backpressure?
emit is a suspending function, so the producer suspends until the collector is ready. There is no request(n) protocol and no overflow strategy by default, which is why a plain chain never drops values and never queues without bound.
What are the three BufferOverflow policies?
SUSPEND (default) makes the producer wait so nothing is lost; DROP_OLDEST discards the front of the queue, which is exactly what conflate() is; DROP_LATEST discards the value being emitted and keeps the queue.
What is the difference between conflate() and collectLatest?
conflate drops intermediate values but lets the collector block run to completion. collectLatest delivers every value but cancels the collector block mid-work when a new one arrives, which suits expensive cancellable work like an in-flight search.
What is operator fusion in Flow?
flowOn, buffer, conflate and channelFlow merge adjacent instances into a single channel configuration rather than each allocating one. The trap: conflate().buffer(50) fuses into one plain buffer, silently discarding the conflation.
Why might (1..1000).asFlow() ignore cancellation?
Because the free cancellation check lives inside the flow { } builder emit, and asFlow on a range emits without suspending. Add cancellable(), or use ensureActive() inside the collector.
When does onCompletion run?
On every ending: values exhausted, upstream failed, or collection cancelled. Its cause parameter is null on success. That makes it the right place for cleanup like hiding a loading spinner.
buffer vs conflate vs collectLatest for a slow collector?
buffer runs producer and collector concurrently, queueing emissions. conflate keeps only the latest value, dropping intermediates the collector missed. collectLatest cancels the in-progress collector block and restarts it with each new value.

Back to Flow Context, Errors & Backpressure