Android · 24 min read

Top 50 Android interview questions, with short answers

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.

How to use this list

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:

  • no first sentence comes to you within ten seconds;
  • you name an API but cannot say who owns it or how long it lives;
  • you use “always” or “never” and cannot name the contract behind it;
  • you have no production example.

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.

Kotlin

1. “What does the !! 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.

2. “Sealed class or sealed interface for UI state?”

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.

3. “What do 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.

4. “When do you use 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.

5. “Why prefer 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.

6. “What is the difference between == 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.

7. “What are scope functions for, and when do they hurt?”

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.

Coroutines and Flow

8. “A coroutine keeps running after its ViewModel is cleared. Why?”

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.

9. “StateFlow or SharedFlow?”

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.

10. “How do you run two calls in parallel and combine them?”

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.

11. “How do you model one-time events like navigation?”

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.

12. “What is the difference between 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.

13. “What does 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.

14. “How does exception handling work in coroutines?”

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.

15. “What does 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.

16. “How do you test coroutines and Flow?”

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.

17. “How can a coroutine cause an ANR?”

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.

Jetpack Compose

18. “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.

19. “What triggers recomposition, and what gets skipped?”

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.

20. “What is state hoisting and what does it cost?”

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.

21. “What is 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.

22. “Common mistakes with 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.

23. “How do you collect a Flow in Compose?”

Answer: collectAsStateWithLifecycle(), which stops collection below the started state. Paired with WhileSubscribed upstream, nothing runs while the app is in the background.

24. “Why do lazy list items need stable keys?”

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.

25. “How do you find and fix recomposition problems?”

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.

Lifecycle and background work

26. “What is process death, and how do you test it?”

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.

27. “What does 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.

28. “What does 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.

29. “WorkManager or a foreground service?”

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.

30. “How do you support multi-window and foldables without losing state?”

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.

Architecture

31. “MVVM or MVI?”

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.

32. “What does a repository own?”

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.

33. “When do use cases help, and when are they ceremony?”

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.

34. “How do you refactor a god ViewModel?”

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.

35. “How would you introduce modularisation into a legacy app?”

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.

36. “How does dependency injection scoping work with Hilt?”

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.

Data and networking

37. “How do you build a single source of truth with Room?”

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.

38. “How do you handle Room migrations for users who skip versions?”

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.

39. “How do you implement token refresh without races?”

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.

40. “When is it safe to retry a request?”

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.

41. “How do you keep a paginated cached list correct after refresh?”

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.

Performance

42. “How do you measure and improve startup?”

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.

43. “What are the most common causes of ANRs?”

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.

44. “How do you find a memory leak?”

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.

45. “How do you investigate jank in a Compose screen?”

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.

Security

46. “Where do you store tokens and secrets?”

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.

47. “How do you implement certificate pinning without outages?”

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.

48. “A session review finds 24-hour access tokens, non-rotating refresh tokens, and client-only logout. What is wrong?”

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.

System design

49. “Design an offline-first app with sync.”

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.

50. “This morning your ANR rate went over the bad-behaviour threshold. What do you do in the first two hours?”

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.

What the short answers leave out

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.

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

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.

Free guide: the Phoenix Method