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 · 24 min read
The top 50 Android interview questions for 2026, grouped by area: Kotlin, coroutines, Compose, lifecycle, architecture, data, performance, security, design.
These are the top 50 Android interview questions I would rehearse before a loop in 2026. I picked them from the hiring side: after more than 500 technical interviews, these are the areas where answers separate candidates, not the trivia that fills most lists. They are grouped by area so you can drill the round you are about to face.
Each answer is short on purpose. It is the first thing you should be able to say in about thirty seconds, plus the one detail that keeps it standing when the interviewer pushes. For the full treatment with weak answers and follow-ups, each section links to the deeper guide. None of these questions is attributed to a company.
Do not read all 50 once. Read one area, cover the answer, and say your own out loud. Mark every question where any of the following is true:
The marked questions are your study list. Everything else is already good enough, and rereading it is comfort, not preparation. Most candidates I interview have a handful of weak areas, not fifty weak questions, so the list shrinks fast once you are honest about it.
!! operator cost in a large codebase?”Answer: Each one is an unchecked promise that turns a compile-time null check into a production crash. Fix the model instead: non-null at construction, constructor injection, or a sealed type for the missing case. Where one must stay, use requireNotNull with a message.
Answer: Sealed interface when subtypes share no state, or when a type must belong to more than one hierarchy. Sealed class when subtypes need a shared constructor. The real value is the exhaustive when that breaks the build when a state is unhandled.
inline, noinline and crossinline do?”Answer: inline copies the body and lambdas into the call site, removing the lambda allocation and allowing non-local returns and reified types. noinline keeps one lambda as an object. crossinline forbids non-local return from a lambda that runs in another context. The cost is code size.
reified type parameters?”Answer: When a function needs the type at runtime, for example inline fun <reified T> Gson.fromJson(json: String). It only works on inline functions because the type is substituted at each call site.
val and immutable data classes?”Answer: Immutable state cannot be changed behind a StateFlow’s back, so equality-based deduplication works and no thread sees a half-updated object. Use copy() for updates. var is fine for local variables in a tight scope, not for state shared across layers.
== and ===, and why does it matter for data classes?”Answer: == calls equals, === compares references. Data classes generate equals from constructor properties only, so a property in the class body is ignored, and an Array property compares by reference. Both cause surprising behaviour in state comparison.
Answer: let, run, apply, also and with differ by receiver (this or it) and return value. They help for null handling and object setup. They hurt when nested, because nobody can tell what it refers to three levels in.
The Kotlin interview questions guide covers variance, delegation and the generated code behind each feature. In most loops the Kotlin section is a filter, so aim for clean, short answers rather than depth.
Answer: Cancellation is cooperative. Blocking code never reaches a suspension point, a broad catch can swallow CancellationException, or the work was launched in another scope. Fix with ensureActive(), rethrowing, and keeping work as a child of the owning scope.
Answer: StateFlow always has a value, conflates, and skips equal values: it describes current state. SharedFlow broadcasts every emission to active collectors with configurable replay and buffering: it carries events. Choose by the delivery guarantee you need.
Answer: coroutineScope { val a = async { ... }; val b = async { ... }; combine(a.await(), b.await()) }. If one fails, the other is cancelled and the error reaches the caller. Use supervisorScope only when partial results are a valid product state.
Answer: As state with explicit consumption. StateFlow replays to new collectors after rotation, SharedFlow with no replay drops events while nobody collects. A pending value in UI state, cleared by the UI after it acts, survives recreation and fires once.
launch and async?”Answer: launch returns a Job and is for work without a result; exceptions propagate to the parent immediately. async returns a Deferred; the result or exception is delivered at await, though a failure still cancels the parent in a regular scope.
withContext(Dispatchers.IO) do, and what does it not do?”Answer: It moves the block to a thread pool sized for blocking I/O and returns the result, which makes the call main-safe. It does not make a blocking call cancellable; the coroutine can be cancelled while the thread stays blocked.
Answer: In a regular scope, a failing child cancels its parent and siblings. SupervisorJob or supervisorScope stops that upward cancellation. CoroutineExceptionHandler only handles uncaught exceptions from root coroutines started with launch; it is a last resort, not error handling.
stateIn(scope, WhileSubscribed(5_000), initial) do?”Answer: It turns a cold flow into a StateFlow that starts when the first collector arrives and stops five seconds after the last one leaves. The timeout covers a configuration change, so rotation does not restart the upstream.
Answer: runTest for virtual time, a main dispatcher rule, Turbine for ordered emissions, backgroundScope for long collectors, and injected dispatchers everywhere. A hardcoded Dispatchers.IO escapes virtual time and makes the test flaky.
Answer: Blocking work on Dispatchers.Main hidden behind a suspend signature, a runBlocking on the main thread, or the main thread waiting on a lock held by background work. Check the ANR trace for what the main thread is waiting on before changing dispatchers.
The Kotlin coroutines interview questions guide has each of these with a weak answer, a senior answer and the follow-up. This is the section I would spend the most time on, because it is the one where interviewers push hardest.
remember or rememberSaveable?”Answer: remember survives recomposition only. rememberSaveable also survives configuration change and process death through saved state, as long as the value fits in a Bundle or has a Saver. Using remember for form input loses the user’s work.
Answer: Writing to snapshot state invalidates only the scopes reading it. Composables with stable, unchanged parameters can be skipped. Reading state high in the tree, unstable parameter types and fresh lambdas widen the area that re-runs.
Answer: Moving state up to the caller and passing value plus event callbacks down, so the composable is stateless, reusable and testable. The cost is more parameters and a caller that has to own the state.
derivedStateOf for?”Answer: For state whose inputs change more often than its result, such as showing a button when scroll passes a threshold. Readers are invalidated only when the result itself changes. It is not a cache for expensive calculations.
LaunchedEffect?”Answer: Keying on Unit when the effect depends on a value, so it never restarts; keying on an unstable object, so it restarts every recomposition; and doing side effects in the composable body, which run on every recomposition.
Answer: collectAsStateWithLifecycle(), which stops collection below the started state. Paired with WhileSubscribed upstream, nothing runs while the app is in the background.
Answer: Without keys, identity is the position. Insert an item at the top and every item’s remembered state and animation shift to the wrong row. Use a stable domain ID.
Answer: Measure first: Layout Inspector recomposition counts, compiler stability reports, and a frame trace. Then move state reads down, make types stable, and hoist expensive work out of composition.
The Jetpack Compose interview questions guide covers the stability model and effect lifetimes in full. Compose answers go wrong most often through overclaiming, so practise saying what each API does not guarantee.
Answer: The system kills a backgrounded app to reclaim memory, then restores the activity stack and saved state when the user returns. ViewModels and in-memory state are gone. Test with “Don’t keep activities” and by killing the process while backgrounded.
SavedStateHandle give you?”Answer: A key-value map in the ViewModel that is written to saved instance state, so small values like IDs, filters and the current step survive process death. Large data belongs in a database.
repeatOnLifecycle solve?”Answer: It starts collection when the lifecycle reaches a state, usually STARTED, and cancels it when it drops below, restarting each time. It prevents collecting into a stopped UI. The common mistake is calling it in a fragment with the fragment’s lifecycle instead of viewLifecycleOwner.
Answer: WorkManager for deferrable, guaranteed work with constraints, which survives process death and reboot. A foreground service for immediate, user-visible work. Since Android 14, foreground services need a declared type and matching permission, and Android 15 limits how long the data sync type may run. User-initiated transfers have their own job type.
Answer: Treat size and posture changes as configuration changes: state in ViewModels and saved state, layouts driven by window size classes, never by device type. Test resizing while a form is half-filled.
Answer: Both can be unidirectional. MVI makes every transition explicit through a reducer, which pays off on complex screens. MVVM with one immutable UI state is lighter for simple ones. The non-negotiable part is one source of truth per screen.
Answer: Access to data and the choice of source: database, network, cache. It exposes domain data, often as a Flow. The ViewModel turns domain data into UI state. A repository returning UI models couples the data layer to one screen.
Answer: They help when logic is shared across screens or combines several repositories. A use case that only forwards one repository call adds a file and no value.
Answer: Characterization tests first, then extract by responsibility: mappers, domain rules, and independent sections into separate state holders. Ship each step. Stop when the ViewModel mostly coordinates.
Answer: Start with the build and ownership pain you can measure. Extract leaf modules first (design system, networking, analytics), then features behind API modules. Enforce dependency direction in the build, not in a wiki.
Answer: Each component has a lifetime: singleton, activity, ViewModel. A binding scoped to a component lives as long as it. Scoping too wide holds memory and stale state; unscoped creates a new instance each time.
The Android architecture interview questions guide goes further into modules and boundaries. Architecture questions reward migration thinking, because interviewers know every real app is between two patterns.
Answer: The UI reads only from Room through a Flow. Network results are written to Room, never shown directly. Local writes go to Room first, with an outbox for sync.
Answer: Provide every step so Room can chain them, or direct migrations for common jumps. Export schemas and test each path with MigrationTestHelper. Destructive fallback deletes user data and is a product decision.
Answer: An OkHttp Authenticator that refreshes on 401, behind a lock or single-flight coordinator so only one refresh runs. Other requests wait, then retry with the new token. Check whether the token already changed before refreshing again.
Answer: When the operation is idempotent. A timeout does not mean failure; the server may have committed. Retry non-idempotent calls only with an idempotency key the server uses to return the original result.
Answer: Paging 3 with a RemoteMediator, Room as the source, and items plus remote keys replaced in one transaction on refresh. Stable keys in the list keep scroll position.
Answer: Macrobenchmark on a release build and a mid-range device, plus production startup data from Android vitals. Remove work from before the first frame, defer initialization, and ship a Baseline Profile. Keep the benchmark in CI.
Answer: Disk or network on the main thread, lock contention with background threads, slow broadcast receivers and services, and heavy work in Application.onCreate. Use the ANR traces and ApplicationExitInfo to see what the main thread was waiting on.
Answer: LeakCanary in debug builds, then a heap dump to find the reference chain keeping a destroyed object alive. Common roots: static references to a context, listeners never unregistered, and views held past onDestroyView.
Answer: Reproduce on a release build, capture a system trace, and check whether frames are lost in composition, layout or drawing. Then fix the specific cause: broad state reads, unstable items, or work in the composable body.
Answer: App-private storage, encrypted with a key held in the Android Keystore, for example Tink over DataStore; EncryptedSharedPreferences is deprecated. Exclude secrets from backups. Keep access tokens short-lived and rotate refresh tokens. Anything shipped in the APK, including API keys, should be treated as public.
Answer: Pin public keys, not certificates, include a backup pin, and declare the pins in Network Security Config with an expiration date, so an old app version stops enforcing stale pins instead of failing. Plan rotation before shipping, or a certificate change becomes an outage.
Answer: Long-lived access tokens widen the window for a stolen token. Non-rotating refresh tokens let theft go undetected. Client-only logout leaves the session valid on the server. Fix: short access tokens, rotation with reuse detection, and server-side revocation.
Answer: Clarify conflicts and loss tolerance. The local database is the source of truth. Each action writes the change and an outbox operation in one transaction. WorkManager drains the outbox with stable operation IDs for deduplication. Conflicts use server versions, not client clocks.
Answer: Establish impact first: versions, rollout percentage, devices, screens. If the new release correlates and a halt is safe, stop the rollout. Split roles: mitigation, investigation, communication. Report confirmed facts separately from the leading hypothesis, with a time for the next update.
The Android system design interview guide works through a full design with the follow-ups. In design rounds, a clear set of constraints in the first three minutes does more for your score than any diagram.
Every answer above is a first answer. The loop is decided by the second. When I interview, I push in four predictable ways: I make your answer slightly too absolute and see if you correct it, I change the lifetime (rotation, process death, logout), I make the happy path fail, and I ask how you know.
So for each question you marked, prepare one sentence for the push, not a longer first answer. And if your first answer turns out to be incomplete in the room, say so in one sentence and tighten it. That habit scores better than a perfect first answer followed by a defensive second one.
Fifty questions is a map, not a study plan. Use it once to find the five or six areas where your first sentence does not come, then spend your time there. That is how you turn a long list into a short, honest one.

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.

Android · 16 min
Android technical interview questions and answers: lifecycle, process death, coroutines, data, security and testing, with the follow-up to each.

Android · 13 min
Kotlin interview questions as Android loops ask them: null safety, coroutines, cancellation, Flow, sealed types and generics, with each follow-up.