Room Database Interview Questions

DATA › Storage

How do you test Room DAOs, and what are the trade-offs between an in-memory database instance and mocking the DAO entirely?

What a strong answer covers: An in-memory Room database (Room.inMemoryDatabaseBuilder) run as an instrumented or Robolectric test exercises the real generated SQL, catching migration and query bugs a mocked DAO never would, at the cost of being slower and needing a device/emulator or Robolectric's SQLite shim. Mocking the DAO is faster and fine for testing a ViewModel or repository's orchestration logic, but it can't tell you whether your actual @Query annotations compile to correct SQL, which is exactly the class of bug Room's compile-time validation doesn't catch for runtime query correctness.

A screen observing a Room Flow<List<Item>> re-emits every time any row in that table changes, even completely unrelated ones. Why does this happen, and what performance problems does it cause at scale?

What a strong answer covers: Room's Flow invalidation tracker watches tables, not rows, so any write to a table invalidates every live query against that table and re-runs it, meaning a chat app's message list can re-query and re-diff a thousand rows because one unrelated row's read-status flag flipped. At scale this shows up as redundant query execution, unnecessary list diffing/recomposition, and battery drain from queries firing far more often than the UI actually changed; mitigations include splitting hot and cold columns into separate tables, or debouncing/distinctUntilChanged on the downstream Flow.

You have a screen listing orders, each with its line items loaded via @Relation. Walk me through the N+1 risk here, and why @Transaction doesn't actually fix the performance problem.

What a strong answer covers: Room's generated code for a @Relation POJO typically issues one query for the parent table and then a separate query per parent (or a batched IN-clause query) for the child rows, so a naive implementation can run one query per order to fetch its line items, which is classic N+1 and gets slow fast with hundreds of orders. @Transaction only guarantees the parent and child queries execute atomically and see a consistent snapshot, it says nothing about how many queries run; fixing the actual performance problem means either relying on Room's batched IN-clause fetch for the relation or hand-writing a JOIN query and mapping the flattened result yourself for large datasets.

Back to Room Database