Android · 22 min read

Android interview questions in 2026, round by round

Android interview questions for 2026, organised by round: Kotlin, coroutines, Compose, lifecycle, architecture, system design, testing, performance, security.

Every list of Android interview questions looks the same from the outside: a hundred definitions, sorted alphabetically, with a two-line answer under each. I have run over 500 technical interviews, all from the hiring side, and I have never once scored a candidate on whether they could define lateinit. I scored them on what happened after the definition, when I changed the lifetime, broke the network, or asked how they knew.

This guide is organised the way a real Android loop is organised: by round. For each round you get the questions that come up in 2026, what the interviewer is scoring, a weak answer, and a strong one. Twenty questions in total, with links to the deeper guide for each area. None of the questions is attributed to a company. Loops change, and I will not claim a list I cannot verify.

How an Android loop is structured in 2026

A typical loop for a mid-level or senior role looks like the table below; companies differ in the number of rounds, their names and their order, so treat it as a map, not a schedule.

Round What it usually contains Deeper guide
Screen Kotlin, coroutines basics, one lifecycle question Android technical interview questions
Language Kotlin semantics, null safety, sealed types, inline functions Kotlin interview questions
Concurrency Coroutines, cancellation, Flow, testing Kotlin coroutines interview questions
UI Compose state, recomposition, side effects Jetpack Compose interview questions
Coding Build a small feature live, or fix a broken one Android coding interview
Architecture and design Layers, offline-first, sync, modularisation Android architecture, Android system design
Behavioural Ownership, incidents, disagreement Senior Android interview questions

A mid-level loop leans on the first four rows. A senior loop spends more time in the last three, and it uses the first four as a filter rather than the decision. If you want the full list in one place, the top 50 Android interview questions page covers every area in short form.

The five questions behind every answer

Before the questions, the model. Almost every Android question collapses into a small set of decisions, and when you blank on an API name you can fall back to these:

  • Who owns this state or this work?
  • How long should it live, and what survives rotation, process death and logout?
  • Where is the single source of truth?
  • What can still fail once the operation looks like it succeeded?
  • What evidence would prove the claim?

When I write up a candidate, the strongest ones reach for these questions before they reach for a library. A candidate who forgets the exact name of collectAsStateWithLifecycle but explains exactly who stops collecting when the screen goes to the background loses almost nothing. A candidate who names the API perfectly and cannot say who owns the collection usually does not recover.

Kotlin

1. “What problems does the !! operator cause at scale, and how would you reduce it safely?”

What is scored: whether you see !! as a missing modelling decision rather than a style issue.

Weak answer: “It can crash, so you should use ?. instead.”

Senior answer: “Every !! is a claim that the compiler cannot check, so it moves a null check from compile time to a production crash. In a large codebase they cluster at boundaries: Java interop, Bundle arguments, fields set in onCreate. I would not replace them mechanically with ?., because that swaps a crash for silent wrong behaviour. I would fix the model: make the value non-null at construction, pass it through the constructor, or represent the missing case explicitly with a sealed type. Then add a lint or detekt rule so new ones need a justification in review.”

The follow-up is usually “and the ones you cannot remove?” A good answer keeps them but replaces them with requireNotNull or checkNotNull with a message, so the crash report says which invariant broke.

2. “When would you use a sealed interface instead of a sealed class for UI state?”

What is scored: whether you understand what each construct constrains.

Weak answer: “Sealed interfaces are newer, so I use those.”

Senior answer: “A sealed class gives the subtypes a shared constructor and shared state, and each subtype can only extend one class. A sealed interface lets a type belong to several sealed hierarchies and lets data object and data class implementations stay flat. For UI state I usually pick a sealed interface, because loading, content and error rarely share fields, and a type like Error sometimes needs to belong to both a screen state and a domain result. Either way the point is the exhaustive when: adding a state breaks every place that forgot to handle it, which is the feature.”

3. “Explain inline, noinline and crossinline, and when inline helps on Android.”

What is scored: whether you know the cost inline removes and the one it adds.

Weak answer: “Inline makes functions faster.”

Senior answer: “inline pastes the function body, lambdas included, into each call site, so no lambda object is allocated and non-local return becomes possible. It helps for small higher-order functions called in hot paths, and it enables reified type parameters. noinline keeps one lambda as an object, for example when you need to store it. crossinline keeps inlining but forbids non-local returns, which you need when the lambda runs inside another context such as a Runnable. The cost is code size, so inlining large functions is a regression, not an optimisation.”

A deeper set of language questions, including variance and delegation, is in the Kotlin interview questions guide. The Kotlin round is short in most loops, but it sets the tone for how carefully the interviewer listens to everything after it.

Coroutines and Flow

This is the round that decides the most Android loops I have seen, because it is where production bugs live. The full treatment is in Kotlin coroutines interview questions; these are the three that come up most.

4. “Your ViewModel was cleared, but a coroutine from viewModelScope is still running. Why?”

What is scored: whether you know cancellation is cooperative.

Weak answer: “You should use viewModelScope so it cancels automatically.”

Senior answer: “The scope did cancel it. The coroutine did not respond. Cancellation is checked at suspension points, so there are three usual culprits: blocking code or a tight CPU loop that never suspends, a catch (e: Exception) that swallows the CancellationException, or work that was launched in a different scope, like an application scope or GlobalScope, so it was never a child. I would check them in that order. The fixes are ensureActive() in CPU loops, rethrowing CancellationException, and making sure the work is a child of the scope that owns the screen.”

5. “StateFlow or SharedFlow for a navigation event?”

What is scored: whether you think in delivery guarantees.

Weak answer: “StateFlow for state, SharedFlow for events.”

Senior answer: “Neither fits by default. StateFlow hands its current value to each new collector, so after rotation the screen navigates again. SharedFlow with no replay drops the event if nobody is collecting at that moment, for example during a configuration change. The pattern I prefer is to model the event as state with explicit consumption: the state holds a pending message or destination, the UI acts on it and calls back to clear it. It survives recreation and cannot fire twice.”

6. “Two network calls should run in parallel. How do you structure them?”

What is scored: structured concurrency and failure semantics.

Weak answer: “Two launch calls and a shared variable for each result.”

Senior answer: “Two async calls inside coroutineScope, then await both. The results come back as values, the scope does not return until both finish, and if one fails the other is cancelled and the exception reaches the caller in one place. If the product can show partial results, that is the wrong tool, and I would use supervisorScope and capture each failure per branch. The choice is a product question: is partial success a valid screen?”

Jetpack Compose

7. “What is the difference between remember and rememberSaveable, and when does the wrong one cause a bug?”

What is scored: whether you know what survives what.

Weak answer: “rememberSaveable survives rotation.”

Senior answer: “remember keeps a value across recompositions while the composable stays in the composition. It is lost on configuration change and on process death. rememberSaveable writes the value into the saved instance state, so it survives both, as long as it fits in a Bundle or has a Saver. The visible bug is a half-filled form or a scroll position that resets after the user comes back from another app. The trap on the other side is putting large objects into saved state; that belongs in a database or SavedStateHandle keyed by an ID.”

8. “A colleague claims every state change recomposes the entire screen. Is that right?”

What is scored: a precise model of invalidation and skipping.

Weak answer: “Compose is smart, it only updates what changed.”

Senior answer: “A state write invalidates the recomposition scopes that read that state. During recomposition, a composable whose parameters are stable and unchanged can be skipped. So the area that re-runs depends on where the state is read and whether the inputs are stable. A large area re-runs when state is read high in the tree, when a parameter type is unstable, or when a lambda is recreated each time. I would check with the Layout Inspector’s recomposition counts and the compiler reports before changing anything.”

9. “How do you observe a Flow from Compose without wasting work in the background?”

What is scored: the pairing of upstream and downstream lifecycle.

Weak answer: “collectAsState().”

Senior answer: “collectAsStateWithLifecycle() in the UI, so collection stops when the lifecycle drops below started. On the ViewModel side, stateIn with SharingStarted.WhileSubscribed(5_000), so the upstream stops a few seconds after the last collector leaves but survives a rotation without restarting. Either half on its own leaves something running while the app is in the background.”

The Jetpack Compose interview questions guide covers side effects, stability and state hoisting in more depth. In my experience, Compose questions are where a confident candidate most often overclaims, so it is worth rehearsing the limits of each API as carefully as the API itself.

Lifecycle and process death

10. “The user fills a multi-step form, switches apps, and the system kills the process. What do they see when they return?”

What is scored: whether you know process death is normal, not an edge case.

Weak answer: “The ViewModel keeps the data.”

Senior answer: “The ViewModel is gone with the process. The system restores the activity and the back stack, and gives back the saved instance state, so anything not written there or to disk is lost. For a multi-step form I would keep small identifiers and the current step in SavedStateHandle, and write the draft itself to Room so it survives even a force stop. I test it with ‘Don’t keep activities’ and by killing the process from the command line while the app is in the background, not by rotating.”

11. “How do Android 14 and later foreground service rules change long-running work?”

What is scored: current platform knowledge and the habit of checking it.

Weak answer: “Just start a foreground service.”

Senior answer: “Since Android 14, apps targeting it must declare a foreground service type in the manifest and hold the matching permission, and some types have runtime prerequisites, such as location permission for the location type. Android 15 then put a time limit on the data sync and media processing types, with an onTimeout callback when it runs out. Starting from the background has been restricted since Android 12, and the notification is part of the contract, since users can see and act on it. So I start by asking whether the work is user-visible and ongoing, like playback, navigation or a call. If it is deferrable, it belongs in WorkManager with constraints. If it is a user-initiated transfer, it goes to a user-initiated data transfer job. I would check the current documentation before the interview, because these rules have changed across recent releases.”

Architecture

12. “MVVM or MVI: how do you choose?”

What is scored: trade-offs, not allegiance.

Weak answer: “MVI is better because it is unidirectional.”

Senior answer: “Both can be unidirectional. The practical difference is how state changes are expressed. MVI routes every change through an intent and a reducer, which makes state transitions explicit and easy to test, at the cost of ceremony on simple screens. MVVM with a single immutable UiState in a StateFlow gets most of the benefit with less code. On a screen with many interacting inputs, like a checkout, I lean toward a reducer. On a settings screen, I do not. What I care about in review is one source of truth per screen and no state mutated from the view.”

13. “You inherit a ViewModel with 900 lines. How do you refactor it without breaking the app?”

What is scored: incremental change and safety nets.

Weak answer: “Rewrite it with clean architecture.”

Senior answer: “First I write characterization tests around the behaviour that matters, using a fake repository, so I have a net. Then I extract by responsibility: formatting into mappers, business rules into plain classes or use cases, and independent sections of the screen into their own state holders. Each step ships on its own. I stop when the ViewModel mostly coordinates. A rewrite would freeze the feature for weeks and lose the bug fixes nobody wrote down.”

The Android architecture interview questions guide goes deeper into modularisation and the repository seam. Architecture questions reward candidates who talk about migration paths, because every real codebase is halfway through one.

System design

14. “Design an offline-first app for technicians who work without signal for hours.”

What is scored: the source of truth, the durable operation model, and failure handling.

Weak answer: “Cache the data locally and sync when online.”

Senior answer: “I would clarify first: can two people edit the same job, how large are photos, can anything never be lost? Then the local database is the source of truth, and screens read only from it. Each user action writes the change and an outbox entry in one transaction, so the pending sync can never be lost between separate writes. WorkManager drains the outbox under network constraints, each operation carries a stable ID so the server can deduplicate retries, and photos upload separately with resumable offsets. Conflicts use a server version per record rather than client clocks.”

15. “How would you design a feed with pagination that stays smooth while data changes?”

What is scored: paging, identity and invalidation.

Weak answer: “Use Paging 3.”

Senior answer: “Paging 3 with a RemoteMediator, Room as the source of truth and remote keys stored alongside the items. On refresh, I replace items and keys in one transaction so the UI never sees a half-updated table. In the list, keys are stable domain IDs, never positions, so inserted items do not break scroll position or item state. And I define what ‘fresh’ means for the product, because a feed refreshed on every resume burns battery for no user benefit.”

The Android system design interview guide has a full worked example with the follow-ups. For design rounds, the pattern I look for is simple: constraints first, then the source of truth, then the failure cases, then how you would know it works in production.

Testing

16. “How do you test coroutine and Flow code without flaky tests?”

What is scored: virtual time and injected dispatchers.

Weak answer: “I add a delay and check the result.”

Senior answer: “runTest so delays are skipped in virtual time, a main dispatcher rule that swaps Dispatchers.Main for a test dispatcher, Turbine to assert emissions in order, and backgroundScope for collectors that should die with the test. The discipline that makes it work is injecting dispatchers: one hardcoded Dispatchers.IO in a repository and that path escapes virtual time. When I need to see a loading state, I gate the fake with a CompletableDeferred so the test decides when loading ends.”

17. “What would you test in a Room migration before shipping it?”

What is scored: thinking about users on old versions.

Weak answer: “I test that the app opens.”

Senior answer: “Every path a real user can take, not only N to N plus 1. Users skip versions, so I either provide migrations for each step and let Room chain them, or add direct migrations for the common jumps. I export schemas and use MigrationTestHelper to create the database at an old version, insert data, run the migration and validate the result. A destructive fallback is a product decision, not a default, because it deletes user data.”

Performance

18. “How do you measure and improve app startup?”

What is scored: evidence before optimisation.

Weak answer: “Use lazy loading and remove libraries from Application.onCreate.”

Senior answer: “I measure first, with Macrobenchmark on a release-like build on a mid-range device, cold and warm, and I look at production startup metrics from Android vitals. Then I trace what runs before first frame: content providers from libraries, eager dependency graphs, disk reads on the main thread. Fixes are deferring initialization, a Baseline Profile so hot code is precompiled, and removing work from the critical path. I keep the benchmark in CI so the gain does not disappear in the next quarter.”

A candidate who says “I would profile it” without naming the tool, the build type or the device class gets a polite nod and a low score. Performance answers are the easiest place to show production experience, because the details only come from having done it.

Security

19. “Where would you store an auth token on Android?”

What is scored: threat model, not a single API.

Weak answer: “In EncryptedSharedPreferences, so it is secure.”

Senior answer: “It depends on the threat. App-private storage already protects against other apps on a non-rooted device. Encryption with a key in the Android Keystore adds protection against file extraction, and a hardware-backed key cannot be exported. EncryptedSharedPreferences is deprecated now, so the current stack is a Keystore key with Tink encrypting DataStore or a file, and the token excluded from backups through the data extraction rules. I would keep access tokens short-lived, rotate refresh tokens, and make logout revoke on the server, not only clear local storage. On a rooted device the client is not trustworthy anyway, so the server has to enforce anything that matters.”

20. “Your retry interceptor retried a payment POST during a timeout and charged a user three times. What is the fix?”

What is scored: idempotency and incident thinking.

Weak answer: “Do not retry POST requests.”

Senior answer: “A timeout does not tell you the server failed; it may have committed. The root cause is retrying a non-idempotent operation without a way to deduplicate. The fix is an idempotency key generated once per user intent and sent with every retry, so the server returns the original result instead of charging again. Retries go only to operations that are idempotent by contract. And the invariant I would write in the incident review is: no retry path for money without a server-side deduplication key.”

Common mistakes I see in Android interviews

These are the patterns that show up most often in my write-ups, across levels:

  1. Naming the API and stopping. “Use viewModelScope” is the start of an answer, not the answer.
  2. Absolutes without a contract: “always”, “never”, “guarantees”. Interviewers push on every one.
  3. Testing rotation and calling it process death.
  4. Designing systems that branch on isOnline in every screen.
  5. Performance claims without a tool, a device or a number.
  6. Defending an incomplete first answer instead of tightening it.

The last one matters more than the others. When your first answer is incomplete, the strongest move is to say so: “Let me make that more precise,” then separate the case your answer covers from the one it does not. That sentence has rescued more candidates I have interviewed than any fact.

How to practise these questions

Reading answers builds recognition. Interviews test production. Pick the round you are least comfortable in, set a timer for two minutes per question, and answer out loud before reading the strong answer. Mark every question where you could not produce a first sentence in ten seconds, used an absolute you could not defend, or could not answer the follow-up.

Then run a full mock. The Android mock interview guide gives you a complete script with timings, follow-ups and a scoring rubric you can use alone with a recording or with a partner. If your loop is senior, the senior Android interview questions guide covers the follow-ups that separate levels.

What changed in 2024 to 2026

  • Kotlin 2.0.0, released 21 May 2024, made the K2 compiler the default and Stable on JVM, Native, Wasm and JS (What’s new in Kotlin 2.0.0).
  • In the same release the Jetpack Compose compiler plugin moved into the Kotlin repository and gained its own Gradle plugin.
  • Answers about build speed or compiler plugins that describe the old compiler describe a toolchain most projects have left.

Sources

What to do next

If you only do one thing after reading this, pick three questions from the round you fear most and answer them out loud tonight, with a timer running. Then ask yourself the follow-up I would ask. The gap between the first answer and the second one is exactly what the loop will measure.

Free guide: the Phoenix Method