Intermediate interview questions in Android & Kotlin, page 4

Which side-effect handler for a one-time coroutine on composition entry?
Tests Compose side-effect API boundaries. Answer: LaunchedEffect(Unit); it runs once and auto-cancels on exit. Contrast with rememberCoroutineScope for user-triggered callbacks. Red flag: picking SideEffect or rememberCoroutineScope and missing cancellation.

Which Compose side-effect for a one-time coroutine action?
Tests if you can choose the right Compose side-effect for a one-time coroutine. A great answer names LaunchedEffect(Unit), explains it runs once and cancels on exit. A red flag is suggesting rememberCoroutineScope directly in the composable body.

Which side-effect handler for a one-time coroutine action in Compose?
This tests your understanding of Compose lifecycles and side-effect handlers. A good answer names LaunchedEffect(Unit), explaining the constant key ensures the effect runs only once. A red flag is suggesting launching coroutines on every recomposition.

How do you display a large list efficiently in Jetpack Compose?
This tests understanding of Compose lazy versus eager layout. A strong answer names LazyColumn or LazyRow, notes visible-only composition, and contrasts Column which lays out everything upfront.

How to implement efficient large lists in Jetpack Compose?
This tests your grasp of Compose performance. Use LazyColumn to compose only visible items, unlike a Column which renders all items at once. A red flag is suggesting a scrollable Column, which has severe performance costs for large lists.

Implement an efficient list in Jetpack Compose
Tests your grasp of UI virtualization in Compose. Answer: Use LazyColumn as it only composes visible items. Contrast this with Column, which composes all items at once, causing poor performance. Mention the items DSL.

Why is LiveData<Boolean> problematic for one-time ViewModel events?
State is not events; suggest an Event wrapper with a consumed flag, or SharedFlow or Channel with no replay.

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.

Why is `LiveData<Boolean>` bad for one-time ViewModel events?
This tests your grasp of state vs. events. A LiveData<Boolean> is state; it re-triggers on rotation. Instead, expose events via a StateFlow and have the UI call an eventConsumed() function on the ViewModel to maintain unidirectional data flow.

How would you use a nested navigation graph for a login flow?
Tests modular navigation scoping. Strong answers group the three screens under a nested graph with its own start destination, noting encapsulation and reusability.

How to use a nested navigation graph for a login flow?
Tests your ability to structure complex UI flows using Navigation Component. A great answer defines a separate login graph XML, includes it in the main graph, and navigates to the graph's ID. This encapsulates the flow, making it reusable.

How do you share a ViewModel across multiple Fragments?
Tests ViewModel scoping and Fragment communication. A strong answer names activityViewModels or navGraphViewModels, warns about Activity memory retention and hidden coupling, and suggests a parent Fragment or data flow alternative.

How do you share a ViewModel between Fragments?
Tests your understanding of ViewModel lifecycle scoping beyond a single screen. To share, scope the ViewModel to the parent Activity or a navigation graph using activityViewModels() or navGraphViewModels().

Explain the purpose of a UseCase and how it fits into MVVM
UseCases encapsulate single business rules between ViewModel and Repository, keeping ViewModels lean and Repositories focused on data.

Explain the purpose of a UseCase or Interactor layer
Tests your grasp of separation of concerns. A great answer defines a UseCase as a single, reusable business operation that sits between the ViewModel and Repository. It keeps other layers clean and focused.

How do you add a non-null column with a default in Room?
Bump version; run ALTER TABLE ADD COLUMN with NOT NULL DEFAULT in a Migration; register via addMigrations.

Model a Room one-to-many Playlist-to-Song relationship
Tests Room relational modeling. Strong answer: Song foreign key, @Embedded Playlist with @Relation to List<Song>, DAO wrapped in @Transaction. Red flag: embedding songs in Playlist or skipping @Transaction, which causes N+1 queries.

Preferences vs Proto DataStore: when is Proto significantly better?
This tests type safety and schema trade-offs. A strong answer contrasts Preferences key-value pairs with Proto typed protobuf schemas, then names nested settings or migration needs as the Proto win. A red flag is recommending Proto for a single boolean.
Explain Retrofit Interceptors and write a static API key interceptor
Tests OkHttp interception and application versus network scope. Strong answers build a new request adding X-Api-Key via newBuilder and chain.proceed; contrast addInterceptor once versus addNetworkInterceptor per hop.

How do you differentiate network and server errors in suspend functions?
Catch IOException for connectivity and HttpException for HTTP errors; wrap in a sealed Result.
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