Skip to content

Android App Development Interview Questions for 10 Years Experience

40 questions with answers for candidates with 10+ years of experience — 1 easy, 9 medium, 30 hard.

What interviewers expect: 10 years experience

At ten years, you are considered for principal engineer, mobile architect or engineering manager roles. Interviews focus on organisation-wide mobile platform decisions, developer productivity, build infrastructure, security and compliance, and aligning engineering with business goals. You should still be technically sharp on modern Android, but the emphasis is on judgement, communication and building strong teams.

This set is weighted towards Testing, Performance and Play Store (7), App Architecture, MVVM and Hilt (6), Jetpack Compose (5), Room, DataStore and WorkManager (5).

Mobile platform architecture Engineering productivity at scale Business and technology alignment Leadership and organisation building
Solved at this levelStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

A composable makes an API call every time the screen recomposes. What is wrong and how do you fix it?

Save to ▾
Show answer
The call is placed directly in the composable body, which runs on every recomposition. Composables must be side-effect free. Move loading to the ViewModel, triggered in init or by a user event, and expose the result as StateFlow. If something must start from composition, wrap it in LaunchedEffect with a stable key like the item ID, so it runs once per key rather than on every recomposition.
02

Users report the app loses form data when they switch to another app and come back after a while. Why?

Save to ▾
Show answer
The system killed the process to reclaim memory while the app was in the background. When the user returns, Android recreates the Activity but ViewModel data is gone because the process died. Fix it by storing small UI state in SavedStateHandle or rememberSaveable, which survive process death, and persisting drafts to Room or DataStore. Test with Don't keep activities or adb shell am kill.
03

A Room query on a large table is slow and causes jank. How do you fix it?

Save to ▾
Show answer
Make sure the query runs off the main thread using suspend or Flow. Use EXPLAIN QUERY PLAN to check for full table scans, and add an @Index on columns used in WHERE, JOIN or ORDER BY. Select only needed columns into a smaller data class instead of SELECT *, page results with Paging 3, and avoid loading large blobs into lists. Wrap bulk inserts in a single transaction.
04

How do you refresh an expired access token automatically?

Save to ▾
Show answer
Use an OkHttp Authenticator, which is called when the server returns 401. Inside it, synchronise so only one refresh runs at a time, call the refresh endpoint with the refresh token, save the new tokens and return the original request with the new header. If the request already carried the latest token and still failed, or refresh fails, return null and log the user out. Limit retries to avoid loops.
05

How do you build an adaptive layout for phones, foldables and tablets in Compose?

Save to ▾
Show answer
Use WindowSizeClass from the Material 3 adaptive library to choose layouts by width class, not device type. On compact width show a bottom navigation bar; on medium use a navigation rail; on expanded use a list-detail layout with ListDetailPaneScaffold or NavigationSuiteScaffold. Avoid locking orientation, since Android 16 ignores orientation restrictions on large screens. Test with resizable emulators and foldable postures.
06

How would you roll out a risky new feature to millions of users safely?

Save to ▾
Show answer
Ship it behind a remote feature flag defaulted off, release the build with a staged rollout and monitor crash-free and ANR rates. Then enable the flag for internal users, then 1, 5, 25 and 100 percent, watching business metrics and errors at each step. Keep a kill switch ready, define rollback criteria beforehand, and keep the old path until the new one is stable.
07

How would you lead an architecture decision when senior developers disagree?

Save to ▾
Show answer
I would write a short decision document stating the problem, two or three options with trade-offs, and constraints such as team skill and timeline, then build a small spike of the top options on a real screen. We review with measurable criteria like test effort and build time, decide, and record it as an architecture decision record. Once decided, everyone commits, and we revisit only if new facts appear.
08

What does the inline keyword do and when should you use reified?

Save to ▾
Show answer
inline tells the compiler to copy the function body and lambda bodies into the call site, avoiding the object allocation for lambdas and enabling non-local returns. It suits small higher-order functions called often. reified can only be used in inline functions and keeps the generic type available at runtime, so you can write inline fun <reified T> Gson.fromJson(json: String) and use T::class. Avoid inlining large functions since it increases bytecode size.
09

Explain backpressure handling in Flow with buffer, conflate and collectLatest.

Save to ▾
Show answer
Flow is sequential by default: the producer suspends until the collector processes each value. buffer() runs producer and collector in separate coroutines with a queue between them. conflate() keeps only the latest value when the collector is slow, dropping intermediate ones, good for sensor or progress updates. collectLatest cancels processing of the previous value when a new one arrives. Choose based on whether every value matters.
10

Your banking app must pass a security audit. What would you check on the Android side?

Save to ▾
Show answer
Check secure storage with Keystore and no secrets in code, TLS only with pinning where justified, no sensitive data in logs, FLAG_SECURE on sensitive screens, root and tamper checks using Play Integrity, exported components reviewed, WebView with JavaScript bridges restricted, R8 obfuscation, session timeout, and biometric authentication with BiometricPrompt and CryptoObject. Use the OWASP MASVS as the checklist and fix findings by severity.
11

How do you structure a large Android app into modules?

Save to ▾
Show answer
Common practice is feature modules (feature:cart, feature:profile), core modules (core:network, core:database, core:designsystem, core:model) and an app module that wires them together. Feature modules depend on core modules but not on each other; navigation is connected through the app module or route contracts. Benefits are faster incremental builds, clear ownership and enforced boundaries. Gradle convention plugins keep module build files consistent.
12

Explain how you would use Room with Kotlin Multiplatform.

Save to ▾
Show answer
Since Room 2.7, Room supports Kotlin Multiplatform for Android, iOS and desktop. You define entities, DAOs and the database in commonMain, use the bundled SQLite driver, and create the database builder in platform-specific source sets with expect and actual. DAO functions must be suspend or return Flow in common code. This lets teams share the data layer while keeping native UIs, which some Indian product companies are adopting.
13

How do you design an Android client to support API versioning and forced updates?

Save to ▾
Show answer
Send the app version in a header on every request, have the backend support older versions for a defined period, and use versioned endpoints for breaking changes. Add a remote config value for minimum supported version and use the Play In-App Updates API with immediate flow for critical updates and flexible flow otherwise. Show a clear message rather than failing silently when the app is too old.
14

Describe a project where you improved code quality for the whole team.

Save to ▾
Show answer
Situation: our app had no shared conventions and reviews took days. Task: speed up reviews and reduce bugs. Action: I proposed ktlint and detekt in CI, created a module template with a convention plugin, and wrote a one-page guide on ViewModel and repository patterns with examples. Result: review time dropped by about half over two months, and new joiners shipped their first feature faster.
15

What do flatMapLatest, flatMapConcat and flatMapMerge do?

Save to ▾
Show answer
All map each value to a new flow and flatten the results. flatMapLatest cancels the previous inner flow when a new value arrives, perfect for search. flatMapConcat waits for each inner flow to finish before starting the next, preserving order. flatMapMerge runs inner flows concurrently up to a concurrency limit, useful for parallel downloads where order does not matter. Choosing wrongly can cause stale results or wasted network calls.
16

You need to sync 500 images to a server without overloading the network. How would you design it with coroutines?

Save to ▾
Show answer
Limit concurrency. Use a Semaphore with withPermit around each upload, or flatMapMerge(concurrency = 4) over a flow of files, or Dispatchers.IO.limitedParallelism(4). Use supervisorScope so one failed upload does not cancel the rest, collect failures for retry with backoff, and report progress through a StateFlow. If the sync must survive app exit, run it inside a CoroutineWorker with WorkManager constraints such as network connected.
17

Write a suspend function that wraps a callback-based API.

Save to ▾
Show answer
suspend fun FusedLocationProviderClient.awaitLastLocation(): Location? = suspendCancellableCoroutine { cont -> lastLocation .addOnSuccessListener { cont.resume(it) } .addOnFailureListener { cont.resumeWithException(it) } cont.invokeOnCancellation { /* cancel request if supported */ } } // For streams of callbacks, use callbackFlow { } with awaitClose { }.
18

A Compose list scrolls with jank on low-end phones. How do you investigate and fix it?

Save to ▾
Show answer
Test a release build with R8, since debug builds are much slower. Use Layout Inspector recomposition counts and a system trace or Macrobenchmark to find hot spots. Common fixes: add keys and contentType, avoid heavy work or sorting inside composables, move computation to the ViewModel, use derivedStateOf for scroll-based state, defer state reads with lambda modifiers like offset { }, load images at the right size with Coil, and add a Baseline Profile.
19

A WorkManager job is not running on some phones from certain manufacturers. How do you investigate?

Save to ▾
Show answer
Some manufacturers apply aggressive battery optimisations that delay or kill background work. Check the job state with WorkManager's getWorkInfosForUniqueWorkFlow and the background task inspector in Android Studio. Verify constraints are not too strict. Guide users to allow unrestricted battery for the app only where the feature truly needs it, use expedited work for urgent tasks, and use FCM to trigger sync when timely delivery matters.
20

How do you mentor junior Android developers?

Save to ▾
Show answer
I pair on their first tasks, explain the why behind patterns rather than only giving fixes, and review pull requests with specific, kind comments plus links to docs. I give them small features end to end so they see the full flow from API to UI, and I ask them to present one learning in our weekly tech sync. I check in regularly so they feel safe asking questions early.
21

How does certificate pinning work and what are its risks?

Save to ▾
Show answer
Certificate pinning makes the app trust only specific public key hashes for your domain, using OkHttp CertificatePinner or the Network Security Config pin-set. It protects against attackers with a rogue or user-installed CA intercepting traffic. The risk is that if the server certificate changes and the pin does not match, all users lose connectivity until they update. Always pin a backup key and set an expiration for config-based pins.
22

Users report battery drain after the latest update. How do you investigate?

Save to ▾
Show answer
Check Android vitals for excessive wake locks and wakeups, then use Battery Historian or the Energy Profiler to look at wake locks, alarms, location requests, jobs and network activity. Common causes are frequent location updates, a foreground service left running, polling instead of push, and WorkManager jobs scheduled too often. Fix by batching work, using lower location priority, stopping services promptly and adding proper constraints.
23

How do you measure app quality after release?

Save to ▾
Show answer
Track crash-free users and ANR rate in Play vitals and Crashlytics, keeping them below Play's bad behaviour thresholds of 1.09 percent user-perceived crash rate and 0.47 percent ANR rate. Monitor startup time, slow and frozen frames, network error rates and key funnel metrics like login success. Read Play reviews and ratings by version. Set alerts and review these numbers in every release meeting.
24

A ViewModel has grown to 1500 lines handling many responsibilities. How would you refactor it?

Save to ▾
Show answer
First add tests around current behaviour so refactoring is safe. Then extract business logic into use cases or domain classes, move data mapping into repositories or mappers, and split UI state into smaller, focused data classes. If the screen truly has separate areas, consider separate state holders or child ViewModels per section. Refactor in small pull requests so reviewers can follow and regressions are easy to locate.
25

Explain generics variance with in and out in Kotlin.

Save to ▾
Show answer
out marks a type parameter as covariant: the class only produces T, so List<String> can be used as List<out Any>. in marks it contravariant: the class only consumes T, like Comparator<in T>. This is declaration-site variance, replacing Java wildcards such as ? extends and ? super. Use-site projections like Array<out Number> are also possible. Getting variance right lets APIs accept more types safely without unchecked casts.
26

How would you design an offline-first notes app?

Save to ▾
Show answer
Room is the single source of truth: the UI observes DAO flows and writes go to Room immediately with a sync status column like pending. A WorkManager job uploads pending changes when the network is available and pulls server changes, updating Room. Handle conflicts with timestamps or server versions, use unique work to avoid duplicate syncs, and show a small sync indicator. The app works fully without network.
27

Compare kotlinx.serialization, Moshi and Gson for JSON parsing.

Save to ▾
Show answer
kotlinx.serialization is Kotlin-first, uses a compiler plugin with no reflection, respects default values and nullability, and works in Kotlin Multiplatform. Moshi supports Kotlin through codegen and is also reliable. Gson uses reflection, ignores Kotlin nullability and default values, and can put null into non-null fields, causing crashes later; it is in maintenance mode. For new Android projects, kotlinx.serialization is the common choice.
28

What are value classes and why use them?

Save to ▾
Show answer
A value class, declared with @JvmInline value class UserId(val value: String), wraps a single value to give it a distinct type without the runtime cost of an object in most cases, because the compiler unboxes it. It prevents mistakes like passing an OrderId where a UserId is expected. It may get boxed when used as a nullable type, in generics or through interfaces, so the zero-cost benefit is not guaranteed everywhere.
29

Write code to request camera permission using the Activity Result API.

Save to ▾
Show answer
private val cameraPermission = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { granted -> if (granted) openCamera() else showPermissionDenied() } fun onScanClicked() { when { ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> openCamera() shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> showRationale { cameraPermission.launch(Manifest.permission.CAMERA) } else -> cameraPermission.launch(Manifest.permission.CAMERA) } }
30

What are stable and unstable types in Compose?

Save to ▾
Show answer
Compose skips recomposing a composable when all its parameters are stable and equal to before. Primitives, String, functions and data classes with val stable properties are stable. Classes with var properties, standard List or types from modules without the Compose compiler may be unstable, preventing skipping. Since strong skipping mode became default in Kotlin 2.0.20, unstable parameters are compared by instance, reducing the problem, but immutable models still help.
31

Product wants a feature flag to turn a new checkout on or off without releasing an update. How do you design it?

Save to ▾
Show answer
Use a remote config service with defaults bundled in the app, wrapped in a FeatureFlags interface injected via Hilt. Fetch and cache values at startup with a sensible timeout, and read the flag at navigation decision points rather than deep inside UI code. Keep both checkout paths tested, log which variant users see for analytics, and plan to remove the old path and the flag after rollout.
32

The app's cold start takes 4 seconds. How do you improve it?

Save to ▾
Show answer
Measure first with Macrobenchmark StartupTimingMetric on a release build. Then reduce work in Application.onCreate by deferring SDK initialisation, using App Startup or lazy injection, and moving disk I/O off the main thread. Simplify the first screen, avoid blocking on network before showing UI, use the SplashScreen API properly, and add a Baseline Profile, which often improves startup by about 20 to 30 percent.
33

Describe a time you improved app performance with measurable results.

Save to ▾
Show answer
Situation: our home screen had many frozen frames on budget phones. Task: improve scroll smoothness. Action: I captured a system trace, found image decoding on the main thread and unstable list parameters causing recomposition, fixed image sizing with Coil, added keys and immutable models, and created a Baseline Profile. Result: frozen frames dropped by about 60 percent and startup improved by 25 percent in Macrobenchmark.
34

How should a Fragment or Activity collect a Flow safely?

Save to ▾
Show answer
Use lifecycleScope.launch with repeatOnLifecycle(Lifecycle.State.STARTED) so collection starts when the UI is visible and stops in the background, avoiding wasted work and crashes from updating views that are not ready. In a Fragment, use viewLifecycleOwner.lifecycleScope because the fragment view can be destroyed while the fragment lives. In Compose, use collectAsStateWithLifecycle(), which does the same lifecycle-aware collection.
35

Explain the three phases of a Compose frame.

Save to ▾
Show answer
Each frame goes through composition, which decides what UI to show by running composables; layout, which measures and places each element; and drawing, which renders pixels. State read in a phase only invalidates that phase and later ones. Reading scroll state inside Modifier.offset { } or drawBehind defers the read to layout or draw, skipping recomposition entirely, which is a key optimisation for animations and scrolling effects.
36

What is the predictive back gesture and how do you support it?

Save to ▾
Show answer
Predictive back, introduced in Android 13 and on by default for apps targeting Android 15, shows a preview of the destination while the user swipes back. Support it by setting android:enableOnBackInvokedCallback="true" and handling back with OnBackPressedDispatcher or BackHandler in Compose instead of overriding onBackPressed, which is deprecated. Navigation libraries and Material components provide animations when you use the supported APIs.
37

What conflict strategies does Room offer for inserts?

Save to ▾
Show answer
@Insert(onConflict = ...) supports REPLACE, which deletes the old row and inserts the new one; IGNORE, which skips the insert; ABORT, the default, which rolls back the transaction; and others. REPLACE can trigger cascading deletes on foreign keys because it deletes first. @Upsert, added in Room 2.5, inserts or updates without deleting, making it safer for syncing server data into local tables.
38

What are Baseline Profiles?

Save to ▾
Show answer
A Baseline Profile is a list of classes and methods used in critical journeys like startup and scrolling, shipped with the app. The Android Runtime uses it to compile that code ahead of time on install, avoiding slow interpretation and JIT on first runs. You generate it with the Baseline Profile Gradle plugin and Macrobenchmark tests. Compose and many Jetpack libraries ship their own profiles, but an app-specific one gives larger gains.
39

A crash says IllegalStateException: Can not perform this action after onSaveInstanceState. What is happening?

Save to ▾
Show answer
A fragment transaction or dialog show was committed after the Activity saved its state, usually because a network callback finished while the app was in background. Committing then would lose state. Fix by triggering navigation only when the lifecycle is at least STARTED, collecting events with repeatOnLifecycle, or deferring the action. commitAllowingStateLoss hides the crash but can lose the transaction, so use it only when that is acceptable.
40

The API team wants to switch to GraphQL. What changes on the Android side?

Save to ▾
Show answer
You would use a client like Apollo Kotlin, which generates type-safe models from the schema and queries at build time, and supports normalised caching and coroutines. Benefits are fetching exactly the fields a screen needs and fewer round trips. Costs include learning the tooling, more complex caching and error handling since errors can come with partial data. I would pilot it on one feature before migrating everything.

Frequently asked questions

What is asked in Android App Development interviews for 10+ years of experience?

At ten years, you are considered for principal engineer, mobile architect or engineering manager roles. Interviews focus on organisation-wide mobile platform decisions, developer productivity, build infrastructure, security and compliance, and aligning engineering with business goals. You should still be technically sharp on modern Android, but the emphasis is on judgement, communication and building strong teams.

How many questions should I practise before a Android App Development interview?

Work through all 40 questions here, then the company-wise sets for the employers you are targeting. Quality matters more than count: be able to explain why each answer is right.

Which topics matter most for 10+ years of experience?

Focus first on Mobile platform architecture, Engineering productivity at scale, Business and technology alignment, Leadership and organisation building.