Skip to content
tezvyn:

Why is LiveData<Boolean> problematic for one-time ViewModel events?

Source: developer.android.comMediumHow cards are made

Why is LiveData<Boolean> problematic for one-time ViewModel events?
Summary

LiveData replays one-time events after rotation.

Key points

State is not events; suggest an Event wrapper with a consumed flag, or SharedFlow or Channel with no replay.

Watch out for

Praising SingleLiveEvent or onCleared resets as fix.

What's really being asked

This question probes your understanding of the difference between UI state and one-time UI events. LiveData is designed to hold state that persists across configuration changes, but events like showing a Snackbar or navigating to a new screen should happen exactly once. The interviewer wants to see if you recognize why a state-holding mechanism fails for ephemeral actions and whether you can name production-grade alternatives.

The full answer

First, explain the replay problem. When you post true to a LiveData<Boolean> from a ViewModel, the value survives rotation. The new Fragment observes the same ViewModel, and because LiveData delivers its latest value to new active observers, the true flag fires again, causing a duplicate Toast or navigation action. Second, clarify that state answers what the UI should look like right now, while an event answers what the UI should do once. Third, offer concrete solutions. The classic LiveData approach is an Event wrapper, a single-use data class with a handled Boolean flag and a getContentIfNotHandled method that returns the payload only on first read. In modern Kotlin code, the better path is often a SharedFlow with replay set to zero, or a Channel, both of which do not replay emissions to new collectors and naturally model one-time events. Fourth, mention that in Compose you collect these flows in a LaunchedEffect as a side effect rather than as state.

The mistakes people make

A frequent mistake is proposing SingleLiveEvent as the perfect fix without acknowledging that it silently drops events when multiple observers are attached. Another red flag is suggesting that you reset the Boolean to false inside ViewModel.onCleared or immediately after observing it, because onCleared only runs when the ViewModel is truly destroyed, not on rotation, and manual resets race with the lifecycle. Some candidates also confuse the issue by suggesting you trigger the event from the Fragment directly, which breaks testability.

What usually comes next

The interviewer may ask how you would test a one-time event flow, which should lead you to describe collecting the SharedFlow in a test coroutine and asserting exactly one value is emitted. They might also ask what happens after process death and restoration, pushing you to discuss whether the event should be saved in SavedStateHandle or treated as transient and lost. Another follow-up is how you would handle multiple simultaneous events, which invites a discussion about buffered channels or queues inside the ViewModel.

A concrete example

Imagine a login screen where tapping a button calls viewModel.login. If the ViewModel exposes a LiveData<Boolean> called navigateToHome, setting it to true triggers navigation. After the user rotates the phone, the new Fragment observes the same ViewModel, sees true again, and navigates a second time. The fix is to expose a SharedFlow<Unit> named navigateToHomeEvents with replay set to zero. The Fragment collects this flow in a lifecycle-aware coroutine and calls findNavController.navigate once. On rotation, the new collector sees no replayed value, so navigation happens exactly once.

Interview question

Why does a ViewModel's LiveData<Boolean> trigger duplicate navigation after device rotation?

  • a.LiveData replays the latest value to new active observers upon resubscriptionCorrect
  • b.The ViewModel is destroyed and recreated alongside the Fragment during rotation
  • c.ViewModel.onCleared does not run during rotation, so the Boolean is never reset
  • d.The observer is not removed in onDestroyView, causing duplicate subscriptions
Why?

LiveData caches the latest value and emits it to any new active observer, causing the event to refire after rotation. While tempting, blaming onCleared is wrong because it only runs when the ViewModel is permanently destroyed, not during a configuration change.

Just read this? Test yourself on what you have been reading.

Read the original → developer.android.com

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on android — each one lists the topics its interview covers.

See open roles