Skip to content

Android Developer interview questions

100 real questions with model answers and explanations for Senior candidates.

See a Android Developer resume example

Practice with flashcards

Spaced repetition · Hunter Pass

Questions

build-tools

I would use a layered feature architecture with ownership enforced in the build:

  • Split each large feature into :feature:<name>:api and :feature:<name>:impl, while keeping small cohesive features in one module until build data justifies a split.
  • Put reusable UI in :core:designsystem, Android services in :core:platform, and pure Kotlin rules in :core:domain; feature modules may depend inward on core, never sideways on another implementation.
  • Enforce module owners with CODEOWNERS and dependency rules with a custom Gradle convention plugin plus Dependency Analysis Gradle Plugin.
  • Accept the extra Gradle configuration and API boilerplate only if median incremental build stays under 30 seconds and no team must edit another team's implementation for a normal feature change.

Why interviewers ask this: This structure balances team autonomy and build isolation against the real maintenance cost of 40 modules.

dependencies

I would make dependencies point from Android details toward stable Kotlin contracts:

  • presentation depends on domain use cases and models, domain contains no android.* imports, and data implements domain repository interfaces.
  • Wire implementations only in the app composition root with Hilt, using @Binds in data modules rather than exposing concrete repositories.
  • Add a Gradle task backed by ArchUnit or Konsist that fails on reverse edges, Android imports in domain, or a graph path deeper than 4 modules.
  • The acceptance criterion is zero dependency cycles in the Gradle build scan; the tradeoff is extra mapping between DTO, domain, and UI models to preserve boundaries.

Why interviewers ask this: Stable inward dependencies keep business rules testable while automated graph checks prevent architectural drift.

roomapinetworking

I would keep each feature contract minimal and make :app the only implementation-aware module:

  • Put routes, input and result value objects, and a small FeatureEntry interface in :feature:<name>:api using only Kotlin and Parcelable when process transport is required.
  • Keep ViewModels, Compose screens, Room DAOs, Retrofit services, and Hilt bindings in :feature:<name>:impl.
  • Let :app depend on all 8 impl modules and register FeatureEntry implementations into a Hilt multibinding map, while feature consumers compile only against api modules.
  • Accept one explicit composition layer and some duplicated boundary models in exchange for an API check that Metalava reports no Room, Retrofit, or impl package in any public signature.

Why interviewers ask this: A narrow contract prevents transitive technology leakage and allows feature implementations to change independently.

architecture-patternsasyncconcurrency

I would use MVI for this workflow because the checkout is a finite state transition problem:

  • Represent all 5 steps in one immutable CheckoutState and send typed CheckoutIntent values to a ViewModel reducer backed by Kotlin StateFlow.
  • Model the 3 validations as tagged async results so stale responses cannot overwrite state after the user moves back or edits input.
  • Persist the minimal fields, current step, and pending payment effect ID in SavedStateHandle; use one idempotency key so restoration cannot submit the same payment twice.
  • The tradeoff is more reducer and event code than MVVM bindings, accepted only if reducer tests cover every legal transition and process recreation restores all 5 steps without duplicate payment submission.

Why interviewers ask this: MVI makes the checkout transition history deterministic, which directly satisfies exact restoration and concurrency requirements.

roomendpointsarchitecture

I would keep search policy in the domain boundary and all I/O behind repository contracts:

  • Define SearchRepository and SearchUseCase in a pure Kotlin :search:domain module with domain Query and Result models and no Android, Room, or Retrofit types.
  • Implement endpoint selection, DTO mapping, and Room cache coordination in :search:data using Retrofit, Room, and kotlinx.coroutines.
  • Keep Compose state, debounce timing, and user events in :search:presentation, calling only SearchUseCase from a Hilt-injected ViewModel.
  • Accept three model representations as the isolation tradeoff; the acceptance criterion is that :search:domain tests run with the Gradle JVM test task and both endpoint or cache implementations can be replaced without changing presentation.

Why interviewers ask this: The boundaries separate search policy from transport and storage while preserving fast JVM verification.

monolith

I would decompose by measured dependency seams rather than moving all packages at once:

  • Use Android Studio dependency analysis and Dependency Analysis Gradle Plugin to map cycles, then rank the 24 features by coupling, build cost, and change frequency.
  • In releases 1 and 2 extract shared Kotlin domain and design-system modules, then move 4 low-coupling features per release behind explicit interfaces.
  • In releases 3 through 6 migrate the remaining features with a branch-by-abstraction adapter so old and extracted code can coexist without parallel product behavior.
  • Accept temporary adapters and duplicate models, but require each release to reduce :app source lines, introduce no new cycles in Gradle build scans, and pass the existing Android instrumentation suite.

Why interviewers ask this: Incremental extraction limits release risk while measurable graph and source targets prove that the monolith is actually shrinking.

I would use an on-demand dynamic feature only after validating delivery latency against the 5-second requirement:

  • Put scanner UI and native libraries in a Play Feature Delivery module with dist:onDemand=true, while its small navigation contract remains in the base app.
  • Trigger SplitInstallManager prefetch after a scanner intent signal, show byte progress, and handle cancellation, insufficient storage, and Play Store delivery errors.
  • Measure p95 install-to-open time and native library size through Play Console and Firebase Performance on representative 4G devices.
  • The tradeoff is a smaller base download for 92 percent of users versus network-dependent entry; ship dynamically only if p95 first use is at most 5 seconds, otherwise bundle or reduce the scanner assets.

Why interviewers ask this: The decision is tied to measured delivery behavior rather than assuming that a large rarely used feature always belongs on demand.

composemigrationsjetpack

I would migrate one feature boundary at a time and keep navigation contracts UI-toolkit neutral:

  • Host new Compose feature roots in Fragment containers with ComposeView, using ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed during the mixed period.
  • Expose only typed destination and result contracts from feature API modules; XML Fragments and Compose NavHost adapters translate those contracts locally.
  • Move shared colors, typography, spacing, and test tags into a Compose design system while retaining XML resource aliases until all 90 legacy screens leave them.
  • Accept temporary Fragment and theme interop for 4 releases, with acceptance requiring no route change, no saved-state regression, and baseline profile startup within 5 percent after each migrated feature.

Why interviewers ask this: A feature-level seam contains interoperability code and avoids coupling public navigation to either XML or Compose.

I would publish typed navigation contracts from feature API modules and resolve them in the app shell:

  • Give each destination a Kotlin @Serializable route and explicit input and result types in its :api module, without exposing Fragment, NavController, or Compose screen classes.
  • Register route handlers from all 14 implementations through Hilt multibindings, and let the app-level Navigation Compose graph own concrete destination wiring.
  • Map the 6 verified App Links to the same typed routes in one parser, validating hosts with assetlinks.json and testing links through adb am start.
  • Accept centralized graph assembly as the tradeoff for isolation; the Gradle graph must contain zero impl-to-impl edges and contract tests must resolve all 14 registrations plus all 6 links.

Why interviewers ask this: Typed API-level routes decouple feature implementations while preserving one auditable entry path for internal and external navigation.

configbuild-tools

I would codify the allowed graph first, then optimize configuration and task selection against measured build scans:

  • Define module types and allowed edges in Kotlin Gradle convention plugins, failing CI when Tarjan cycle detection finds any of the current 9 cycles or a forbidden feature-to-feature edge.
  • Remove cycles by extracting the smallest stable contracts into api or pure Kotlin modules, never by adding compileOnly or runtime reflection to hide an edge.
  • Enable configuration cache, parallel execution, and type-safe project accessors, then use Gradle Enterprise build scans and Dependency Analysis Gradle Plugin to remove unnecessary api dependencies.
  • Accept extra convention-plugin maintenance in exchange for zero cycles, configuration at or below 25 seconds, and an affected-module CI path below 12 minutes on 95 percent of builds.

Why interviewers ask this: Executable graph rules prevent regressions while separate timing criteria show whether modularity improves rather than merely rearranges the build.

validationarchitecture-components

I would keep one owner for durable screen state and give each child only the data and events it needs:

  • Define an immutable ProfileEditorState at the screen boundary with the 6 values, 6 nullable field errors, and the save status, then expose it from the ViewModel as StateFlow.
  • Pass each section a small immutable slice plus typed callbacks such as onNameChanged, rather than the ViewModel or setters for MutableState.
  • Compute the banner and saveEnabled from the canonical field values in the owner so the children cannot create conflicting validation state.
  • Keep only ephemeral UI details such as focus and an open keyboard locally, while edits and save progress remain hoisted and survive configuration changes.

Why interviewers ask this: This split gives the screen a single source of truth while preserving reusable, stateless child composables.

resilience

I would make state flow down through one stream and route every user action back through one event entry point:

  • Model the 4 render states as an exhaustive sealed hierarchy and expose one StateFlow<CheckoutUiState> from the ViewModel.
  • Send all 5 event types to onEvent, then serialize repository work and state reduction inside the ViewModel instead of mutating state in composables.
  • Render the state with collectAsStateWithLifecycle and an exhaustive when, giving the 12 cart lines immutable models and callbacks only.
  • Represent successful payment as durable PaymentCompleted(transactionId) state that drives the receipt destination, while only drop-tolerant toasts use a separate SharedFlow.

Why interviewers ask this: Durable payment completion preserves required navigation after collection restarts, while disposable feedback stays outside screen state.

I would establish a repeatable measurement before changing annotations or data structures:

  • Enable Compose compiler metrics and reports for the release-like variant, then inspect the actual stability and skippability of the feed and card parameters under the project's compiler settings.
  • Use Layout Inspector recomposition counts with a fixed script of 10 favorite updates and 3 toolbar changes, repeating the run 3 times from the same initial state.
  • Fix only the measured cause by using immutable card models, preserving unchanged item instances, and passing stable event callbacks, adding @Immutable only when every property satisfies its contract.
  • Repeat the same 3 runs and record the delta, expecting the changed card and toolbar to update while unchanged visible cards remain skippable according to both the report and counters.

Why interviewers ask this: Compiler evidence and controlled recomposition counts distinguish real instability from harmless parent execution.

snapshotoop

I would serialize writes at one state owner and make each published node value immutable:

  • Store 40 immutable NodeUi values in a SnapshotStateList and keep selectedNodeId as separate snapshot state, exposing read-only data and event functions to children.
  • Send background updates through a channel to a Main-thread reducer, then replace the affected NodeUi once with all 3 changed fields inside one Snapshot.withMutableSnapshot block.
  • Route drag events through the same reducer so location and gesture writes have a defined order instead of modifying the list from two threads.
  • Never mutate properties inside a NodeUi or alter the list while iterating it, because replacing one indexed element gives Compose a precise snapshot invalidation boundary.

Why interviewers ask this: Immutable elements plus serialized atomic writes let every composition read a coherent snapshot without broad list replacement.

lifecyclecallbacks

I would key each effect by the resources whose identity requires cancellation or cleanup:

  • Use LaunchedEffect(itemId) for the current item's flow so changing 101 to 102 cancels the old collection before the new keyed effect starts.
  • Use DisposableEffect(lifecycleOwner, itemId) to register the single observer and remove that exact observer in onDispose whenever either identity changes or the composable leaves composition.
  • Wrap onExpired with rememberUpdatedState and call that state from the observer, so a new callback is visible without restarting either effect.
  • Test the 101 to 102 to 103 sequence by asserting at most 1 active collector and 1 observer after each change, then 0 of both after disposal.

Why interviewers ask this: Identity keys control resource lifetime while rememberUpdatedState refreshes behavior without unnecessary restarts.

indexessnapshot

I would use derived state for rendering and a snapshot flow for the suspend side effect:

  • Create one remembered LazyListState and remember a derivedStateOf that evaluates listState.firstVisibleItemIndex > 5 for the button's visible state.
  • Read only that Boolean in composition so scrolling among indices on the same side of the threshold does not invalidate the button.
  • In LaunchedEffect(listState), collect snapshotFlow { listState.firstVisibleItemIndex > 5 }.distinctUntilChanged().drop(1).filter { it } and send analytics from the collector.
  • Keep analytics out of derivedStateOf and composition, because the false to true transition in the flow already produces exactly 1 event for each upward crossing.

Why interviewers ask this: The derived value limits UI invalidation while snapshotFlow converts snapshot reads into a deduplicated event stream.

uischema

I would keep composition free of size decisions and perform the adaptive algorithm entirely in Layout:

  • During composition, emit the same 6 card children in semantic order without reading parent size or storing measured dimensions in state.
  • During measurement, derive 1 or 2 columns from maxWidth, subtract the 16 dp gap for 2 columns, measure each child once with a fixed column width, and compute each row height from its tallest child.
  • Constrain the summed row heights and vertical gaps to the parent's bounds, then return that final width and height from layout.
  • During placement, use placeRelative with the computed row offsets for RTL support, and put any separators in drawWithContent so drawing neither remeasures children nor mutates state.

Why interviewers ask this: Separating composition, single-pass measurement, relative placement, and drawing satisfies both adaptive geometry and phase constraints.

css

I would make item identity independent of position and keep reuse boundaries aligned with the 3 layouts:

  • Call items with a globally unique stable key such as type plus backend ID, never the index, so prepending 20 messages preserves identity and the visible anchor.
  • Return exactly header, message, or ad from contentType so LazyColumn reuses composition slots only between structurally compatible rows.
  • Hoist one nullable expandedMessageId to the screen state and derive each row's expanded Boolean from its stable ID instead of remembering expansion by position.
  • Verify with a test that prepends 20 messages while a middle row is visible and expanded, then assert the same ID stays anchored and remains the only expanded item.

Why interviewers ask this: Stable identity preserves row state across insertion while content types prevent incompatible slot reuse.

designconcurrency

I would share one durable screen state across both adaptive arrangements and save only compact user input:

  • Derive the 1-pane or 2-pane arrangement from current window width on every layout pass, while both variants consume the same selectedConversationId, filter, and draft state.
  • Store those 3 saveable values in the ViewModel's SavedStateHandle and reload the 60 conversations from the repository instead of putting row models in saved state.
  • In compact mode, navigate between list and detail from selectedConversationId; in expanded mode, render both panes and the same selection without copying state between composables.
  • Test widths of 412 dp and 1,200 dp, then recreate the activity and reconstruct the ViewModel from saved state to assert all 3 values return and the repository supplies the rows.

Why interviewers ask this: A shared durable state preserves user intent across size changes and process recreation without exceeding saved-state limits.

formsuicompose

I would replace the 2 selected regions behind clear boundaries while retaining one state owner for all 4 regions:

  • Put a ComposeView at each migrated XML location and set DisposeOnViewTreeLifecycleDestroyed so both compositions are disposed with the Fragment view lifecycle.
  • Collect the existing ViewModel state with lifecycle awareness inside Compose and send promo and payment events back to that same ViewModel, avoiding a second source of truth.
  • Keep the toolbar and 12-row RecyclerView unchanged for release 1; if the outer shell later moves to Compose, host the RecyclerView with AndroidView using factory once, idempotent update, and onRelease cleanup.
  • Preserve shared insets, focus order, accessibility labels, and stable test IDs across the View and Compose boundaries, then test recreation with exactly 1 active collector per migrated region.

Why interviewers ask this: Lifecycle-bound composition and shared state allow two regions to migrate without forcing navigation or list rewrites.

Locked questions

  • 21

    An image feed runs in a 256 MB heap. Android Studio Memory Profiler shows 118 MB after launch and 232 MB after five open-close cycles, while LeakCanary retains one FeedActivity through an adapter callback. Design a memory plan that also covers thumbnail caching for 400 items.

    cachingmemorycallbacks
  • 22

    A tap sometimes freezes the UI for 6.2 seconds while Room reads 18,000 rows and maps them to JSON on the main thread. The trace is close to Android's 5-second input-dispatch ANR threshold. How would you diagnose and redesign this path?

    roomconcurrencyanr
  • 23

    A scrolling screen renders 12 ms frames at the median but 24 ms at p95 on a 60 Hz phone, and it feels worse on a 120 Hz phone. Explain the budgets and propose a jank investigation with a target for both displays.

    rendering
  • 24

    Cold startup is 1.45 seconds at p50 and 2.10 seconds at p95 on an API 28 reference phone, with a product requirement of p95 below 1.20 seconds. The app initializes five SDKs in Application.onCreate. How would you measure and reduce startup?

    api
  • 25

    After startup cleanup, release cold startup is still 1.30 seconds at p95 under CompilationMode.None. You may add a Baseline Profile, but the APK size increase must stay below 1.5 MB and the improvement must be proven on API 28 and API 34. What would you implement?

    api
  • 26

    A Compose LazyColumn with 1,000 mixed rows drops 14% of frames during a fling and allocates 6 MB per second. Each row builds a currency formatter and receives a mutable item whose status changes every second. How would you optimize it without stale UI?

    composeoptimization
  • 27

    A checkout screen starts price, inventory, and delivery requests that each take up to 800 ms. Inventory failure must cancel delivery, price failure may show cached data, and all work must stop when the ViewModel is cleared. How would you structure the coroutines?

    architecture-componentscachingcoroutines
  • 28

    A suspend repository method parses a 12 MB JSON response in 420 ms and writes 6,000 Room rows, and callers invoke it from Dispatchers.Main. The UI may spend at most 8 ms per frame on this operation. Where do dispatcher boundaries belong?

    coroutinesroom
  • 29

    A user can cancel a 50,000-record import. Parsing loops in batches of 2,000 records, cancellation currently takes 3.4 seconds, and a cancelled run sometimes commits the final Room transaction. Redesign cancellation with a 150 ms target.

    transactionsroombatch
  • 30

    A sensor Flow emits 200 samples per second, rendering can process 30 per second, and an upload collector needs every sample in batches of 100. The UI must show data no older than 100 ms while upload loss must remain zero. How would you handle backpressure?

    batchbackpressureconcurrency
  • 31

    A repository emits 20 price updates per second, two UI collectors need the latest value after every rotation, and analytics must receive only events emitted while it is subscribed; where would you use a cold Flow, StateFlow, and SharedFlow?

    coroutines
  • 32

    A search screen has 3 collectors, users usually leave it for 3 seconds but may return after 30 minutes, and its cold upstream takes 800 ms to restart; how would you configure stateIn or shareIn start policy, replay, and timeouts?

    resilienceconfig
  • 33

    A payment result arrives while no Fragment collector exists for 2 seconds during recreation, and navigation must happen once without being lost or repeated; how would you deliver this one-off effect?

    android-components
  • 34

    An app needs one Retrofit client per process, checkout state shared by 3 ViewModels across 2 rotations, one repository instance per ViewModel, and an Activity helper recreated on every rotation; which Hilt scopes fit?

    android-componentsarchitecture-componentsdependency-injection
  • 35

    In 4 Gradle modules named :app, :feature-checkout, :core-network-api, and :core-network-impl, the feature can see NetworkClient but Hilt reports a missing binding; how should dependencies and graph visibility be arranged?

    dependenciesbuild-toolsapi
  • 36

    Six command handlers come from 3 feature modules, while an authenticated cache must be shared across 3 activities for a 45-minute session and cleared on logout; how would you combine multibindings with a custom Hilt session component?

    componentscachingsessions
  • 37

    An app has a deferrable 2-minute sync, an immediate user-started 800 MB upload lasting about 12 minutes, and a calendar alert that must fire at 08:00; when would you use WorkManager, a foreground service, and an exact alarm?

    android-componentsjetpackalerting
  • 38

    A 15 MB backup requires unmetered network, charging, and at least 20 percent battery, but product asks for completion within 6 hours while the device may enter Doze or the app may be in the Rare standby bucket; how would you schedule it?

    backups
  • 39

    Three identical upload triggers arrive within 10 seconds, the server may commit before a client timeout, and the operation allows at most 5 retries; how would you combine unique work, backoff, and idempotency?

    resilienceidempotency
  • 40

    A dashboard requests background refresh every 5 minutes, periodic work may tolerate a 5-minute flex window, and a user-triggered refresh should start within 10 seconds even when expedited quota is exhausted; what would you implement?

  • 41

    You have a public inline reified mapper used at 18 call sites across 3 Android feature modules, and the release APK may grow by at most 24 KB; how would you control code size while preserving ABI compatibility for external callers?

  • 42

    A screen reducer handles 9 actions and 5 states, and every new action must cause a compile-time failure until explicitly handled; how would you model the sealed hierarchy and reducer without an else branch?

  • 43

    A Fragment uses 3 property delegates for ViewBinding, navigation arguments, and a 6 MB image cache; under the Fragment view lifecycle constraint, which owner should clear each value and when?

    android-componentslifecyclecaching
  • 44

    You want UserId as a Kotlin value class around String, but it crosses 2 Java APIs, Parcelable navigation arguments, and a JSON serializer that requires a stable wire string; how would you define the boundaries?

    serializationapikotlin
  • 45

    Design a Kotlin API that copies items from a read-only producer into a mutable consumer for Animal, Cat, and Dog, while accepting List<Cat> and MutableCollection<Animal>; which generic variance constraints and contract tests would you use?

    contractgenericskotlin
  • 46

    An app has 6 dynamic feature modules and 12 typed destinations, including an HTTPS deep link into a feature that may not be installed; how would you define route ownership and validate the link without sharing NavController?

    ownershiphttpsvalidation
  • 47

    A 4-step Compose checkout must survive process death, but SavedStateHandle and rememberSaveable together must stay below a 200 KB Bundle budget; what would you save if the cart contains 80 items?

    composeconcurrency
  • 48

    A Flow emits Loading immediately, Data after 5 seconds, and Error after a 2-second retry delay; how would you test all 3 emissions with runTest, a TestDispatcher, and Turbine without waiting 7 real seconds?

    resilience
  • 49

    A Compose form has 7 fields, 2 validation messages, and a submit button, and it must restore state after Activity recreation; how would you test semantics and restoration without relying on text position?

    formscomposevalidation
  • 50

    For an app with 14 Gradle modules, define a CI test pyramid with an 8-minute pull-request budget, a 25-minute nightly budget, and exactly 2 physical device models, including Macrobenchmark and a Baseline Profile gate.

    pyramidbuild-tools
  • 51

    After release 8.14, Play Console reports 1.34% user-perceived ANRs against a 0.42% peer median and a worst-8% category rank; an input-dispatch trace shows runBlocking on main for 5.48 s while Room scans 186,000 rows and checkpoints the WAL. Is this a database, coroutine, or rendering incident, and what fix and regression gate do you choose?

    databaseroomincidents
  • 52

    Play Console shows ANRs rising from 0.18% to 0.91%, a worst-15% rank, and 73% of clusters under Input dispatching timed out after a settings tap; Perfetto shows 6.24 s in FileInputStream.read and JSON parsing of a 38 MB cache on main. Do you patch the filesystem, suppress the cluster, or redesign the interaction path?

    caching
  • 53

    Version 5.6 reaches 0.76% user-perceived ANRs versus a 0.29% peer median and ranks in the worst 11%; sampled traces show main blocked for 5.87 s in a synchronous Binder call to PackageManager while opening a picker with 412 installed packages. Do you retry Binder, cache the result, or move the call?

    resiliencecaching
  • 54

    After enabling live sync, Play Console reports 1.08% ANRs against a 0.36% peer median and a worst-6% rank; the trace shows main waiting 5.63 s for synchronized(SessionStore), whose SyncWorker owner performs a 5.71 s HTTPS read while holding the monitor. Is the fix a larger timeout, a concurrent collection, or a lock-boundary change?

    sessionshttpsmonitoring
  • 55

    After an app update, a manifest BroadcastReceiver handling ACTION_MY_PACKAGE_REPLACED raises Play Console ANRs from 0.22% to 0.84%, puts the app in the worst 13%, and yields traces where onReceive performs token migration and synchronous refresh on main for 6.41 s. Since the receiver timeout may be longer, do you keep the work there, use goAsync, or schedule it elsewhere?

    resilienceandroid-componentsmigrations
  • 56

    Release 11.2 has 0.69% ANRs versus a 0.21% peer median and ranks in the worst 9%; tapping Expand all on a 9,800-item Compose screen causes a 5.36 s input timeout, with 4.72 s of markdown parsing inside composition and 0.64 s of measure and layout. Do you optimize the parser, virtualize UI, or move state production?

    composeuioptimization
  • 57

    On a 60 Hz Pixel 7, feed scroll has 18.6% janky frames against a 16.67 ms budget; Macrobenchmark FrameTimingMetric reports p95 41.2 ms, JankStats tags image-card binds, Perfetto shows 28 to 44 ms main-thread bitmap decodes, and Compose tracing shows little recomposition. Do you tune Compose, prefetch data, or change image handling?

    composeconcurrency
  • 58

    On a 120 Hz Galaxy S25, a Compose contacts list produces 31.4% janky frames with an 8.33 ms budget; FrameTimingMetric gives p95 19.6 ms, JankStats marks contact-row, Compose tracing shows all 42 visible rows recomposing for one selection, and Perfetto shows no GPU bottleneck. Do you lower refresh rate, optimize drawing, or change state and stability?

    trackingoptimizationcompose
  • 59

    A 60 Hz search list regresses from 3.1% to 12.7% janky frames after adding saved badges; FrameTimingMetric reports p95 27.8 ms, JankStats labels result-row, Perfetto shows a 10 to 22 ms Room query during each bind, and Compose tracing shows stable rows. Do you add an index, move each query off main, or eliminate per-row queries?

    indexesqueriesroom
  • 60

    On a 120 Hz device, collapsing a Compose header produces exactly 22.9% janky frames against 8.33 ms; FrameTimingMetric reports p95 17.4 ms, JankStats tags header-collapse, Perfetto shows 9 to 14 ms measure and layout per frame, and Compose tracing links it to an animated height modifier. Do you optimize the shader, cap 60 Hz, or change the animation primitive?

    composeuioptimization
  • 61

    On a Pixel 6 at 60 Hz, a 200-row RecyclerView feed showed 18.6% janky frames, a 42.3 ms P95 frame time, and 7.8 MB of allocations per fling. Perfetto showed repeated main-thread measure and bind work. How did you diagnose and fix it?

    uiconcurrency
  • 62

    On a Galaxy S22 at 120 Hz, a Compose LazyVerticalGrid had 24.9% janky frames, a 31.6 ms P95 frame time, and 11.4 MB allocated while scrolling 300 cards. Compose tracing showed broad recomposition on every scroll tick. What did you change?

    compose
  • 63

    On a Galaxy S24 at 120 Hz, scrolling a product detail screen produces 29.6% janky frames and a 21.7 ms P95 against an 8.33 ms budget. Perfetto shows GPU completion taking 14 to 23 ms, and HWUI overdraw visualization shows 5.4x overdraw where translucent scrims, rounded overlays, and shadows overlap. Main-thread composition, measure, layout, and image decode all stay below 4.1 ms. How did you diagnose and fix it?

    concurrencyoopdataviz
  • 64

    On a Pixel 4a with a 256 MB app heap limit, navigating Dashboard to Scanner and back 30 times grew the heap from 74 MB to 181 MB and PSS from 128 MB to 246 MB; the app OOMed near 224 MB heap. LeakCanary retained 30 ScannerActivity instances through a singleton callback. What did you fix?

    callbacksdata-structures
  • 65

    On a Galaxy A52 with a 256 MB heap limit, opening and closing an order detail Fragment 40 times raised heap from 61 MB to 169 MB and PSS from 116 MB to 231 MB; OOM occurred around 218 MB heap. LeakCanary retained 40 Fragment views through an adapter listener. How did you resolve it?

    uidata-structuresandroid-components
  • 66

    On a Pixel 7 with a 384 MB heap limit, entering and leaving a Compose checkout 35 times grew heap from 92 MB to 207 MB and PSS from 154 MB to 283 MB; the process OOMed near 338 MB heap after longer runs. LeakCanary retained 35 ComposeView owners through a payment callback. What was the fix?

    concurrencycallbacksdata-structures
  • 67

    On a Redmi Note 10 with a 192 MB heap limit, navigating through SearchFragment 25 times grew heap from 58 MB to 146 MB and PSS from 109 MB to 205 MB; OOM started near 171 MB heap. LeakCanary retained 25 fragments through a coroutine collecting location updates. How did you fix and prove it?

    data-structurescoroutinesandroid-components
  • 68

    On a Galaxy A34 with a 256 MB heap limit, opening and closing a CameraX document scanner 24 times grows heap from 67 MB to 196 MB and PSS from 119 MB to 258 MB; OOM starts near 228 MB heap. LeakCanary retains 24 ScannerActivity instances through an ImageAnalysis analyzer task queued on a dedicated executor, whose lambda captures the Activity and preview binding. What did you change and gate?

    data-structureslambdaandroid-components
  • 69

    On a Nokia G50 with a 256 MB heap limit, visiting a photo viewer and returning 18 times grew heap from 72 MB to 213 MB and PSS from 130 MB to 274 MB; OOM appeared around 232 MB heap. LeakCanary retained 18 PhotoFragment views through a custom image cache. How did you correct it?

    cachingdata-structures
  • 70

    On a Pixel 5 with a 256 MB heap limit, repeating LoginActivity to HomeActivity and logout 45 times raised heap from 55 MB to 174 MB and PSS from 106 MB to 238 MB; OOM occurred near 221 MB heap. LeakCanary retained 45 LoginActivity instances through an auth listener. What was your ownership fix and regression gate?

    ownershipdata-structures
  • 71

    After opening and closing ProfileFragment exactly 12 times, heap grows from 58 MB to 137 MB and PSS from 111 MB to 206 MB. LeakCanary reports exactly 12 retained ProfileFragment instances, each held by a repository LiveData observer registered with observeForever and capturing the Fragment binding. Would you block the 20% rollout, and what evidence, fix, and release gate do you require?

    android-componentsarchitecture-componentsdata-structures
  • 72

    A 512 MB device crashes after viewing 18 catalog items: heap grows from 96 MB to 318 MB, PSS reaches 466 MB, and an HPROF dump shows 13 retained 2048x2048 ARGB_8888 bitmaps totaling about 208 MiB in ProductImageRepository.previewCache. Would you tune the cache, change image loading, or roll back the release?

    cachingdata-structuresrollback
  • 73

    Six hours after version 8.3.0 reaches 25%, crash-free sessions fall from 99.72% to 98.91%; Crashlytics attributes 61% of new crashes to OutOfMemoryError at BitmapFactory.nativeDecodeStream, with 78% on Android 8-9 devices under 2 GB RAM. Do you continue, pause, or roll back, and how do you prove the patch?

    sessionsrollback
  • 74

    Version 5.9.1 at 40% lowers crash-free users from 99.88% to 99.31%; the top stack is a NullPointerException at CheckoutMapper.kt:87 when response.payment.methods is null, and Play Console shows 92% of cases on API 34 after backend experiment B exposure. Do you patch the app, disable the experiment, or continue rollout?

    experimentsapifundamentals
  • 75

    At a 15% rollout, crash-free sessions drop from 99.81% to 99.22% and 1,840 events share IllegalStateException: Can not perform this action after onSaveInstanceState at FragmentManager.checkStateLoss, called from OfferViewModel result delivery 300-900 ms after backgrounding. Do you use allowingStateLoss, postpone the transaction, or stop the release?

    transactionssessionsandroid-components
  • 76

    After native video filters reach 30%, crash-free users fall from 99.76% to 98.84%; Play Console reports 3,260 SIGSEGV crashes at pc 0x18f4 in libfilters.so, 81% on arm64 Android 14, but the uploaded symbols cover only version 2.6.0 while production contains 2.6.1. Do you roll back before symbolication, and what must the native patch prove?

    rollback
  • 77

    Version 11.2.0 reaches 50% and crash-free sessions move from 99.90% to 99.43%; Crashlytics groups 2,410 obfuscated NullPointerExceptions at a.a.b(:17), 74% only in the minified release build, while the R8 mapping file was not uploaded. Do you halt rollout, and how do you distinguish an optimizer issue from an application bug?

    sessionsoptimization
  • 78

    A messaging patch at 10% improves the original IllegalStateException from 0.42% to 0.01%, but overall crash-free sessions remain 99.34% versus a 99.82% baseline; Crashlytics now shows 690 IndexOutOfBoundsException events at MessageListAdapter.onBindViewHolder:214, 96% after reconnect with lists of 200 or more items. Do you promote, hold, or revert the patch?

    indexessessions
  • 79

    After version 7.4.0, overnight battery drain rises from 3.8% to 12.6% over 8 hours; Battery Historian shows SyncService holding a PARTIAL_WAKE_LOCK for 5 hours 47 minutes across 143 acquisitions, and Perfetto shows the worker retrying every 2 minutes with no network. Do you stop rollout or only tune WorkManager constraints?

    resiliencejetpack
  • 80

    A 20% release increases background drain from 0.55% to 1.48% per hour; Perfetto records 312 radio wakeups and 186 HTTPS requests in 60 minutes while the app is backgrounded, versus 18 and 6 before, and 84% come from three analytics workers scheduled independently. Do you disable analytics upload, batch it, or allow rollout to continue?

    batchhttps
  • 81

    After release 9.1, an eight-hour off-shift test with the screen off drains 16.8% battery instead of 3.2% and records 936 wakeups per hour. Battery Historian shows 6 hours 51 minutes of Bluetooth LE scan activity, while Perfetto and Bluetooth diagnostics show the scanner still receiving 74 callbacks per minute after the shift screen is closed. How do you lead the incident without turning it into a sync scheduling fix?

    jobsandroid-componentsincidents
  • 82

    A failed API deployment triggers 27% battery loss in six hours, 2,180 wakeups per hour, and 1.8 GB of traffic per device. Perfetto shows overlapping OkHttp retries, and Battery Historian shows WorkManager restarting the same upload chain. What remediation do you approve?

    deploymentnetworkingapi
  • 83

    A courier build loses 22% battery during a four-hour shift, causes 940 wakeups per hour, and sends 760 MB. Battery Historian attributes most drain to GPS, and Perfetto shows a location callback every 10 seconds followed by polling even when the courier is stationary. How do you change it without breaking tracking?

    callbacks
  • 84

    After media playback ends, a foreground service remains alive overnight; affected phones lose 31% battery, show 1,680 wakeups per hour, and transfer 2.4 GB in ten hours. Perfetto shows a five-second progress poll and Battery Historian shows the service process never becoming idle. What is your production plan?

    android-componentsconcurrency
  • 85

    After 20 rotations on the profile screen, production diagnostics show 146 active coroutine jobs, 12 duplicate user collectors, and 24 identical requests per minute; LeakCanary retains four destroyed ProfileActivity instances, and DebugProbes points to GlobalScope launches in the Activity. What do you change and gate?

    android-componentscoroutines
  • 86

    Leaving and reopening checkout five times produces 63 active jobs, six duplicate price collectors, and 30 quote requests per minute. LeakCanary shows two cleared CheckoutViewModel instances retained by a repository callback, while a DebugProbes dump shows jobs launched in an injected application scope. How do you fix ownership?

    ownershipcallbacks
  • 87

    Scrolling a feed for ten minutes leaves 312 active jobs, 48 duplicate item collectors, and 192 image-metadata requests per minute. DebugProbes traces jobs to RecyclerView holders, and LeakCanary retains three destroyed FeedFragment instances through the adapter. What would you approve?

    ui
  • 88

    Opening and closing the map seven times leaves 91 active jobs, seven duplicate location collectors, and 84 reverse-geocode requests per minute. LeakCanary retains three destroyed MapActivity instances, while DebugProbes and a coroutine trace stop inside callbackFlow without a cleanup frame. How do you resolve it?

    callbackscoroutines
  • 89

    After 300 recompositions of a Compose notification screen, diagnostics show 124 active coroutine jobs, 41 duplicate preference collectors, and 205 settings requests per minute. LeakCanary retains three cleared NotificationViewModel instances, while DebugProbes creation stacks point to SideEffect launching each collector in an injected application scope. Why is changing a LaunchedEffect key not the explanation, and what do you fix and gate?

    composecoroutinesandroid-components
  • 90

    Cancelling an export and leaving its screen five times results in 204 active jobs, 32 duplicate upload requests, and four retained destroyed ExportActivity instances. DebugProbes shows child uploads still running after cancellation, LeakCanary points through a progress listener, and traces show CancellationException being caught as a retryable error. How do you close the incident?

    resilienceincidents
  • 91

    A daily account refresh completed up to nine hours late on 18% of devices after the app entered Doze or App Standby. Product asks for a 30-minute guarantee. How do you investigate and redesign it?

  • 92

    Background location sessions stop after 40 to 70 minutes on some Xiaomi and Samsung devices, while Pixel sessions survive. Crash reporting shows nothing. What do you do?

    sessions
  • 93

    A reconnect storm enqueued 14 copies of the same sync, drained 11% battery, and produced conflicting writes. How would you correct the WorkManager design?

    designjetpack
  • 94

    A user taps Send, but an expedited WorkManager request sometimes starts 12 minutes later after quota is exhausted. The team currently promises delivery in 10 seconds. What would you change?

    jetpackpromises
  • 95

    After targeting Android 14, a long export started from the background throws foreground-service exceptions, and some successful runs have no visible notification. How do you fix and verify it?

    android-componentserror-handling
  • 96

    Uploads of 1.5 GB videos restart from zero whenever the process dies, and only 62% finish on unstable mobile networks. Product asks you to guarantee completion overnight. Design the recovery and define an honest guarantee.

    designconcurrency
  • 97

    A junior developer introduced three Activity leaks in two releases by storing views and callbacks in singletons. How do you coach them and prove the issue is improving?

    android-componentscallbacks
  • 98

    A junior caught `Exception` in six coroutine call sites and swallowed `CancellationException`, leaving two screens doing work after navigation. How would you mentor them?

    error-handlingcoroutinesmentoring
  • 99

    A junior reads a Perfetto trace captured on a 60 Hz device and concludes that a 240 ms frame was caused by RecyclerView layout, but the trace actually shows binder waits and image decoding. How do you correct the skill gap?

    uitracing
  • 100

    A junior shipped 18 instrumentation tests with a 14% CI failure rate, mostly from sleeps, shared state, and selectors tied to translated text. How do you coach them to make the suite reliable?

    testing