Android · 16 min
Senior Android interview questions and what follow-ups test
Twelve senior Android interview questions with what each scores, a weak and a senior answer, and the follow-up: coroutines, Flow, Compose, process death.
Android · 14 min read
Ten Android architecture interview questions and how senior answers are scored: layers, the domain layer, UDF, Hilt, modules, navigation and testing.
Android has an official answer to “how should I architect my app”: Google’s architecture guide, with a UI layer, an optional domain layer and a data layer. That makes the Android architecture round harder, not easier. Everyone can recite the guide. The interviewer wants to hear where you followed it, where you did not, and why.
| Signal | Strong | Weak |
|---|---|---|
| Decision | Chooses for this app and this team | Recites the official guide |
| Reasons | Team size, testing, the app’s age and complexity | “Google recommends it” |
| Cost | Names what the choice makes harder | “Clean architecture has no downsides” |
| Change | Says when they would do it differently | Defends every layer for every screen |
| Situation | Reasonable default | What it costs |
|---|---|---|
| Small app, one or two engineers | UI layer and data layer, no domain layer; manual DI or a small Hilt setup | Logic may leak into ViewModels as it grows |
| Team of five to ten | UI, data, and use cases only where logic is shared; Hilt | Code generation time (Hilt supports KSP); Hilt knowledge required |
| Several teams | Feature modules split into api and impl, core modules, convention plugins in Gradle |
Build configuration work; interface discipline |
| Large legacy app | New features in the target architecture, old code migrated when touched | Two styles side by side for a long time |
Weak: the three layers from the documentation, with no mention of the actual app.
Senior: the layers as they exist in the app, then the decisions: “We have no domain layer except in checkout, where three ViewModels share the pricing rules. Repositories own Room as the source of truth and expose Flows. The ViewModel exposes one StateFlow of UI state per screen.” Then one thing they would change. The follow-up: “A response arrives after the user switched accounts.” Which writer is allowed to update current state? A layer diagram does not answer that; a rule at every writer does.
What is scored: willingness to say no.
Senior: “Only where logic is shared between ViewModels or complex enough to deserve its own tests. A use case that only forwards a repository call adds a file and a layer of indirection for nothing. The official guide calls the domain layer optional for this reason.”
Senior: state flows down from the ViewModel as a single immutable UI state; events flow up from the UI as function calls or an event type; the ViewModel is the only place state changes. Then the practical benefit: “A bug report with a screenshot maps to exactly one state value, which I can reproduce in a test.” The follow-up: “How do you handle one-off events like a snackbar?” The current guidance is to model them as state that the UI consumes and then reports as handled, rather than a Channel that can lose events during a configuration change. A senior candidate knows why the recommendation moved.
Senior: compile-time checked graph, scoping tied to Android components, standard in Jetpack integrations. Cost: code generation time in builds (Hilt supports KSP, which is faster than kapt), errors that are hard to read for newcomers, and ceremony in small apps. An alternative for small apps is manual injection through a container class. Naming the cost is the whole point of the question. A repository that holds account data also needs a reset on sign-out, whatever its scope. The follow-up: “Which scope do you give a repository?” Start from no scope: a new instance per injection is cheap, and @Singleton has to earn its place with state that really is app-wide or an object that is expensive to build. Then show you know the failure modes. Scope a shared cache to each ViewModel and two screens show different data. Make an object that holds one screen’s state a @Singleton and the next screen opens with stale state, and the singleton keeps it alive.
Senior: feature modules with an api module (interfaces, navigation routes, models the outside needs) and an impl module, so features depend only on each other’s api. Core modules for networking, database, design system. The app module wires implementations. Gradle convention plugins keep build files consistent. Measure build time before and after. The weak answer splits by layer: :ui, :domain, :data. It looks clean on a slide, but one feature change now edits three modules, every team merges into the same ones, and no module has an owner. With four or five engineers I would also say that heavy modularisation may not pay for itself yet. Some rules apply at any size: no feature depends on another feature’s impl, core does not depend on features, and there is no :core:common catch-all. Put those in a CI graph check so a violation fails the build instead of waiting for a reviewer.
Staff: ownership of core modules, a review rule for changes to shared api modules, and how you stop the “common” module from becoming a dumping ground.
Senior: each feature exposes its destinations through its api module (type-safe routes with Navigation Compose, for example), and the app module assembles the graph. A feature never references another feature’s screen class directly. Deep links resolve to routes, not to activities. An id in a route is a lookup input, not permission: check the account and whether the resource still exists before showing it. If the user is signed out, keep the target, sign in, then evaluate it again with current facts instead of restoring a saved stack.
What is scored: matching the scope to the lifetime of the work.
Senior: not viewModelScope, which dies with the screen. For work that must finish, WorkManager. For work tied to the app process while it lives, an application-scoped CoroutineScope injected where needed. The answer depends on whether the work must survive process death. Leaving a screen and destroying its ViewModel are not always the same event, so name the scope you mean. If the work must survive process death, write the operation to disk first and schedule it second.
Senior: ViewModel tests with fake repositories and a test dispatcher; repository tests against an in-memory Room database; a few Compose UI tests for critical flows; screenshot tests for the design system if the team maintains one. Fakes over mocks for repositories, because a fake keeps behaving like the real thing as tests grow. Say what you would not test. If you use a fake, run the same contract tests against the fake and the real implementation, so the fake cannot drift.
Staff-level: ask what problem it solves and how you would measure the improvement; propose migrating incrementally, screen by screen when they are next changed; set a boundary between old and new. Say which side is authoritative at each step: two writers to the same data is its own bug, and a flag that hides the new screen can leave its worker running. A big-bang migration needs a business reason, not an architectural preference.
The honest answer wins: a decision that aged badly, how you noticed, and what changing it would cost now. “Nothing” loses.
“What does that cost you?” Prepare a cost for every choice. The iOS version of this round is iOS architecture interview questions, and the round these answers feed into is Android system design interview.

Android · 16 min
Twelve senior Android interview questions with what each scores, a weak and a senior answer, and the follow-up: coroutines, Flow, Compose, process death.

Mobile system design · 15 min
What an Android design round adds: process death, WorkManager, Doze, FCM priority and Room as source of truth, with a worked chat design and its follow-ups.

iOS · 14 min
Ten iOS architecture interview questions and how senior answers are scored: MVVM, TCA, navigation, dependency injection, SPM modules, testing.