Skip to content
tezvyn:

Room DAO: Flow<List<User>> vs suspend fun getUsers(): List<User>

Source: developer.android.comHardHow cards are made

Room DAO: Flow<List<User>> vs suspend fun getUsers(): List<User>

This tests reactivity versus one-shot queries in Room and coroutines. Flow emits on every table change on Room's dispatcher, while suspend returns a single snapshot requiring manual refresh.

What's really being asked

The interviewer wants to know if you understand the architectural contract between Room, Kotlin coroutines, and the UI layer. Specifically, they are looking for clarity on reactive data observation versus one-shot querying, dispatcher behavior, and lifecycle-aware collection. This distinction is central to building responsive apps that do not waste resources polling the database or miss updates.

The full answer

First, explain that Flow<List<User>> is an observable query. Room sets up an internal observer on the table; whenever the data changes, Room re-runs the query and emits the new list downstream. This happens automatically without manual refresh calls. Second, explain that suspend fun getUsers(): List<User> is a one-shot operation. It runs the query once, returns the result, and completes. The caller receives a static snapshot that becomes stale immediately if another process writes to the database. Third, discuss threading. Room executes both variants on a background dispatcher that it manages for queries, so neither blocks the main thread. However, the Flow remains active after the first emission, holding resources until the collector cancels it. Fourth, cover UI implications. A Flow should be collected in a lifecycle-aware scope such as viewModelScope or lifecycleScope so the UI re-composes or updates automatically. A suspend function result must be stored in state and manually refreshed, often through a user pull-to-gesture or a periodic polling mechanism. Fifth, mention error handling and backpressure. Flow allows you to handle errors and apply operators like distinctUntilChanged or map in the ViewModel, while a suspend function pushes error handling to the single call site.

The mistakes people make

A major red flag is saying Flow is just an asynchronous wrapper around a suspend function. Another is claiming that suspend fun automatically re-runs when the database changes. Some candidates incorrectly state that Flow queries run on the main thread unless you specify a dispatcher, which reveals confusion about Room's internal threading model. Also, suggesting that you should call a suspend function in a loop to mimic Flow shows a lack of understanding of reactive streams and battery efficiency.

What usually comes next

The interviewer may ask how you would handle a rapidly changing table with Flow to avoid excessive UI updates; expect to mention distinctUntilChanged or conflate. They might ask what happens if you collect a DAO Flow in a Fragment without lifecycle awareness; you should mention repeatOnLifecycle to prevent wasted background work. Another follow-up is how to combine this Flow with network fetching; a good answer introduces combine or flatMapLatest in the ViewModel. They may also probe error handling, asking what happens if the database is locked or corrupted during emission.

A concrete example

Imagine a chat app displaying a user list. Using Flow<List<User>>, the screen updates instantly when a new user is inserted by a background sync worker. The ViewModel collects the Flow in viewModelScope and exposes it to Compose via StateFlow; the UI re-composes automatically. If you instead used suspend fun getUsers(), the background worker would insert the new user, but the screen would remain stale until the user triggered a manual refresh or the activity recreated and called the function again.

Interview question

What is the key architectural difference between returning Flow<List<User>> and suspend fun getUsers(): List<User> from a Room DAO?

  • a.Flow runs queries on the main thread by default unless a dispatcher is specified, whereas suspend runs on a background thread.
  • b.Flow emits a new result automatically whenever the underlying table changes, while suspend returns a single static snapshot.Correct
  • c.Suspend fun automatically re-runs whenever the database is modified and emits updated lists.
  • d.Flow is simply an asynchronous wrapper that calls the suspend function once and buffers the result.
Why?

Room internally observes the table for Flow queries and re-emits on every change, whereas a suspend function executes once and returns a fixed snapshot. Distractor D is tempting because both APIs use coroutines, but suspend functions do not auto-rerun or emit streams; refreshing them requires explicit manual calls.

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. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.

See open roles