Sharing Flows & Lifecycle-Safe Collection Quiz

KOTLIN › Flow

Two fragments collect the same cold flow exposed by a ViewModel. What happens?

Answer: The producer runs twice, so the underlying query executes twice

Cold means the producer belongs to the collector. Sharing one execution requires converting to hot with stateIn or shareIn.

Which sharing policy stops the upstream when nobody is listening?

Answer: SharingStarted.WhileSubscribed(5_000)

Eagerly and Lazily both run until the scope dies, differing only in when they start. Only WhileSubscribed reacts to the subscriber count falling to zero.

Why is five seconds the conventional WhileSubscribed timeout?

Answer: It outlasts a configuration change but not backgrounding

Rotation completes well inside it so the upstream survives and there is no re-query, while backgrounding exceeds it so real resources are released.

What does replayExpirationMillis control?

Answer: How long the cached value survives after the upstream stops

stopTimeout is about the producer and replayExpiration is about the cache. The default keeps the cached value forever, so a returning screen renders last known state instantly.

What is wrong with this ViewModel code?

Answer: Each call builds a new shared flow, so nothing is shared between callers

Sharing needs one instance. As a function, every caller gets a fresh upstream and its own query, which is the situation stateIn was supposed to fix.

Why was launchWhenStarted deprecated?

Answer: It suspends the collector instead of cancelling it, so the upstream keeps producing

A suspended collector still holds its subscription, so cursors stay open and WhileSubscribed never observes the subscriber count reaching zero.

The app is backgrounded. What happens to a collectAsState() subscription?

Answer: It keeps collecting, because a backgrounded Activity does not leave composition

That variant is tied to composition rather than lifecycle, and backgrounding does not end composition. It is the launchWhenStarted problem in Compose form.

In a Fragment, which scope should collect a flow that updates views?

Answer: viewLifecycleOwner.lifecycleScope

The Fragment scope lives until onDestroy while the view dies at onDestroyView, so using it renders into a released binding. The view lifecycle owner cancels at the right moment.

A ViewModel uses SharingStarted.Eagerly and the Fragment uses repeatOnLifecycle. Does the upstream stop when backgrounded?

Answer: No: Eagerly runs the upstream regardless of subscribers

Both halves of the handshake are required. Cancelling the subscription only helps if the sharing policy reacts to subscriber count, which Eagerly does not.

How should a Fragment collect three separate flows?

Answer: One repeatOnLifecycle block containing three launch calls

Each repeatOnLifecycle is its own coroutine with its own overhead, so one block with a launch per flow is the idiomatic shape.

Which converter should expose a stream of one-off navigation events?

Answer: shareIn, since events have no meaningful current value

stateIn requires a current value and conflates, which is wrong for events: a repeated event would be dropped and a stale one replayed. shareIn produces a SharedFlow instead.

What must you supply when calling collectAsStateWithLifecycle on a plain Flow?

Answer: An initial value, since Compose must render something on the first frame

A StateFlow supplies its own current value but a bare Flow does not. That is a good reason to expose StateFlow from a ViewModel, so the initial value is decided once rather than per screen.

You want to convert a cold Flow into a hot stream that always holds a current value and replays it to every new collector while sharing a single upstream collection. Which operator do you use?

Answer: stateIn

stateIn turns a cold flow into a StateFlow that always has a current value and emits it to new subscribers. shareIn produces a SharedFlow without an always-present value, and buffer does not make the flow hot at all.

In a View-based Activity, what is wrong with collecting this way, with no further wrapping?

Answer: Collection keeps running in the background, wasting work on a stopped UI

Plain lifecycleScope collection runs until the scope is destroyed, so it continues while the UI is stopped. Wrapping in repeatOnLifecycle(Lifecycle.State.STARTED) cancels and restarts collection with visibility.

In Jetpack Compose, what is the recommended way to consume a ViewModel StateFlow as UI state?

Answer: vm.state.collectAsStateWithLifecycle(), collects only while STARTED

collectAsStateWithLifecycle() (from lifecycle-runtime-compose) ties collection to the lifecycle, collecting only while at least STARTED and stopping otherwise, unlike plain collectAsState() which keeps collecting in the background.

You convert a cold repository flow into UI state with stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), Loading). What does WhileSubscribed(5000) achieve?

Answer: It keeps the upstream alive 5s after the last collector unsubscribes

WhileSubscribed(stopTimeoutMillis = 5000) keeps the upstream producer alive for 5s after the last subscriber unsubscribes, so a configuration change does not tear down and restart the producer.

Back to Sharing Flows & Lifecycle-Safe Collection