Lifecycle, LiveData & repeatOnLifecycle Quiz

ARCHITECTURE › Components

An observer is registered with observe(lifecycleOwner, observer). The owner is currently in the CREATED state (e.g. activity stopped). LiveData's value then changes. What happens?

Answer: It is not notified now, but gets the latest value when STARTED

LiveData only delivers to active (STARTED/RESUMED) observers. A CREATED-but-not-started owner is inactive, so it gets the most recent value when it next becomes active.

Which statement about repeatOnLifecycle(Lifecycle.State.STARTED) { flow.collect { } } is correct?

Answer: The collect block is cancelled below STARTED, re-launched on return

repeatOnLifecycle cancels its child coroutine when the state drops below the target and starts a fresh one each time the target state is reached again, repeating until DESTROYED.

Why is launchWhenStarted considered an unsafe/deprecated way to collect a Flow from lifecycleScope?

Answer: It suspends on stop instead of cancelling, so upstream keeps running

launchWhenX pauses the coroutine but keeps the collection (and its upstream producer) alive in the background, wasting resources. repeatOnLifecycle cancels it outright.

You need to update a LiveData value from a background thread doing network work. Which call is correct?

Answer: Call postValue(), which schedules the update onto the main thread

setValue() must run on the main thread and crashes otherwise; postValue() can be called from any thread and posts the value to the main thread.

In Jetpack Compose, what is the idiomatic, lifecycle-aware way to collect a ViewModel's StateFlow?

Answer: viewModel.state.collectAsStateWithLifecycle()

collectAsStateWithLifecycle (lifecycle-runtime-compose) collects only while at least STARTED and stops in the background, unlike a plain LaunchedEffect collect which keeps running off-screen.

Which scenario is the textbook use case for switchMap rather than map?

Answer: Mapping a userId LiveData to getUser(userId) LiveData

switchMap is for chaining to a new LiveData per input value and swapping the active source; mapping an id to a repository lookup returning LiveData is the canonical example. map handles plain synchronous transforms.

Which guidance about LiveData vs Flow in a layered architecture is correct for modern Android?

Answer: Keep Flow in the data layer, expose StateFlow or asLiveData() to UI

Flow belongs in the data layer (threading, operators, composition); the ViewModel exposes it as lifecycle-friendly StateFlow or via asLiveData(). LiveData transforms run on the main thread, so repositories should not return LiveData.

You call liveData.observeForever(observer) from a long-lived singleton. What is the key risk compared with observe(owner, observer)?

Answer: The observer stays permanently active, never auto-removed, so it leaks

observeForever has no lifecycle to bound it, so the observer stays active forever and LiveData never removes it automatically; forgetting removeObserver leaks the observer and everything it references.

When observing LiveData inside a Fragment that inflates a view, which LifecycleOwner should you pass to observe()?

Answer: viewLifecycleOwner, since the view can be recreated separately

A Fragment's view can be destroyed and recreated (e.g. while on the back stack) while the Fragment instance survives, so observing with viewLifecycleOwner scopes the observer to the current view and avoids leaks and duplicate observers.

You write lifecycleScope.launch { repeatOnLifecycle(STARTED) { collectA() }; collectB() }. What happens to collectB()?

Answer: collectB waits until DESTROYED, as repeatOnLifecycle suspends there

repeatOnLifecycle is a suspend function that only returns once the lifecycle is DESTROYED, so code placed after it in the same coroutine is effectively unreachable while the screen is alive; each collector must live inside the repeatOnLifecycle block.

You need a single LiveData that emits whenever EITHER a cached LiveData or a network LiveData changes. Which API fits best?

Answer: MediatorLiveData, calling addSource() for each input

MediatorLiveData.addSource() observes multiple inputs and emits a combined result when any of them changes, whereas map and switchMap each transform only a single upstream source.

A background loop calls postValue(1), postValue(2), postValue(3) in rapid succession before the main thread gets a chance to run. What is guaranteed about what observers see?

Answer: Observers may see only 3, since pending postValue updates coalesce

postValue schedules a task on the main thread, and if several posts are queued before that task runs, only the most recent value is dispatched, so intermediate values can be dropped.

Which statement correctly distinguishes StateFlow from a plain SharedFlow when exposing UI state from a ViewModel?

Answer: StateFlow holds one current value, requires an initial, and conflates updates

StateFlow is a conflated state holder: it requires an initial value, always exposes a current value, and replays only the latest value to new collectors, which is exactly why it suits UI state; SharedFlow is more configurable and need not hold a value.

Why is implementing DefaultLifecycleObserver preferred over the older @OnLifecycleEvent-annotated LifecycleObserver?

Answer: The @OnLifecycleEvent API is deprecated; DefaultLifecycleObserver is type-safe and reflection-free.

@OnLifecycleEvent was deprecated in favor of DefaultLifecycleObserver, whose overridable onCreate/onStart/onStop callbacks are type-safe and avoid the reflection and annotation processing the old approach relied on.

Back to Lifecycle, LiveData & repeatOnLifecycle