Skip to content
tezvyn:

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

Source: developer.android.comMediumHow cards are made

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

Tests if you know LiveData holds state, not events. A good answer explains that LiveData re-emits on configuration changes, causing repeated events. The solution is to model events as part of the UI state and consume them.

What's really being asked

This question probes your understanding of the fundamental difference between state and events in UI programming. It specifically tests your knowledge of LiveData's behavior as a state holder, particularly its tendency to re-emit the last value to new observers (e.g., after a configuration change). An interviewer wants to see if you can identify this common bug and articulate the modern, recommended architectural pattern for handling one-time events reliably.

The full answer

First, identify the core problem: LiveData is designed to hold and represent the current state. When a configuration change occurs (like a screen rotation), the UI controller (Activity/Fragment) is destroyed and recreated. The new instance subscribes to the ViewModel's LiveData and immediately receives the last emitted value, causing a one-time event like a Toast or navigation to trigger again.

Second, propose the modern, recommended solution: model events as part of your UI state. Instead of a separate LiveData<Event>, the ViewModel exposes a single StateFlow<UiState>. The event (e.g., a message to show) is a nullable property within the UiState data class. When an event needs to be triggered, the ViewModel updates the state with the event data.

Third, explain the consumption mechanism. The UI collects the state flow. When it sees a non-null event, it handles it (e.g., shows a Toast) and immediately calls a function on the ViewModel (e.g., userMessageShown()) to signal that the event has been consumed. The ViewModel then updates the state to set the event property back to null, preventing it from being triggered again.

Fourth, you can briefly mention older patterns like a custom Event wrapper class (often called SingleLiveEvent) as a historical context, but you should frame the state-based approach as superior for its predictability, testability, and alignment with a single source of truth principle.

The mistakes people make

A major red flag is not understanding why LiveData<Boolean> is a problem. This suggests a lack of experience with Android lifecycles. Another poor answer is suggesting a race-condition-prone fix, like using a Handler to post a delayed _liveData.value = false. The most common mediocre answer is confidently proposing SingleLiveEvent as the definitive solution without acknowledging the modern state-flow-based approach, which indicates outdated knowledge.

What usually comes next

Expect follow-ups like: "How would you implement the state consumption logic in a Fragment using coroutines?" or "What are the specific downsides of the SingleLiveEvent wrapper approach?" (e.g., it can still be problematic with multiple observers). Another likely question is "How does this pattern change or simplify in Jetpack Compose?" (Hint: LaunchedEffect is ideal for this).

A concrete example

A ViewModel has val navigateToDetails: LiveData<Boolean>. On success, it sets the value to true. The Fragment observes this and navigates. If the user rotates the screen on the details page and then navigates back, the original Fragment is recreated, observes the true value again, and incorrectly re-navigates. The correct approach is to have a val navigationTarget: NavigationTarget? in a UiState object. The UI navigates when it's non-null, then immediately calls viewModel.onNavigationComplete() to set it back to null.

Interview question

A ViewModel uses a `LiveData<Boolean>` to trigger a one-time action, like showing a toast. What is the primary issue with this approach?

  • a.The LiveData value is lost if the app is killed by the system, so the event might not fire.
  • b.It requires using `observeForever`, which can easily lead to memory leaks if not managed carefully.
  • c.After a screen rotation, the UI re-subscribes and immediately receives the last value, causing the toast to be shown again.Correct
  • d.It is not thread-safe and can lead to race conditions if multiple threads update the value.
Why?

LiveData is a state holder; it retains its last value and provides it to any new observer. This causes issues for one-time events during configuration changes, as the recreated UI will receive the old event. While state loss on process death is a concern, it is not the specific bug this pattern introduces.

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