All jobs / Mobile developer

Android interview questions

Android questions a Mobile developer can be asked, from first job to senior. Open one to see the strongest answer and why it works.

  1. A new Activity is created after a rotation. Where should you put “load this screen’s data”?

    The strongest answer: In a lifecycle-aware place that survives recreation — a ViewModel / equivalent — and re-bind the UI when the new view appears

    Why it works: Exactly. Recreation is normal. Own the data above the view; re-bind when the view comes back.

    • Treat recreation as the happy path.
    • Hold screen state above the view.
    • Re-bind when the new view is ready.
    • Do not hide process death behind a static.
  2. You need to finish a photo upload after the user leaves the screen. What do you use?

    The strongest answer: A platform background API that can survive process death — WorkManager, a foreground service with a visible notification where required, or BGTask / URLSession background — not a naked Thread

    Why it works: Exactly. Background work is a contract with the OS, and sometimes with a visible notification.

    • Use the platform background API.
    • Expect process death.
    • Foreground services need a real notification.
    • Say whether leave-screen cancels or continues.
  3. In Jetpack Compose, how do you make the screen show a new value?

    The strongest answer: I change the state the composable reads, and Compose re-runs the functions that read it. There is no view object to hold on to and set text on

    Why it works: Exactly — state in, UI out. The only way to change the screen is to change what it reads.

    • State in, UI out.
    • Change the state, not the view.
    • Use state Compose can track.
    • Never poke a composable directly.
  4. Why must an Android ViewModel not hold a reference to an Activity, a Fragment or a View?

    The strongest answer: It outlives them — it survives recreation on rotation — so the reference both leaks memory and points at a destroyed screen. The ViewModel exposes state and the screen observes it

    Why it works: Exactly — different lifetimes is the reason, and “expose state, let the screen observe” is the shape that follows.

    • The ViewModel outlives the screen.
    • Hold no View, Activity or Fragment.
    • Expose state; the screen observes.
    • Use an application context if needed.
  5. A new screen in an Android app — a new Activity, or a destination inside the one you have? How do you decide?

    The strongest answer: Default to one Activity hosting destinations: shared navigation, one back stack and scoped view models come free. A separate Activity is for a separate entry point, such as a share target or a launcher shortcut

    Why it works: Right — the default is the host, and the exception is an entry point the system itself launches.

    • One host, many destinations.
    • Default to a single Activity.
    • Separate Activity for separate entry points.
    • Keep one back stack.
  6. Push works on the first install and dies a month later for some users. What do you check?

    The strongest answer: Token rotation — FCM / APNs tokens refresh, users reinstall, they deny then allow — I re-register and upsert the token on the backend

    Why it works: Exactly. Tokens are ephemeral. Re-register and replace; do not append forever.

    • Listen for token refresh.
    • Upsert, do not only insert.
    • Handle reinstall and permission flips.
    • Log send failures by token age.
  7. Why use Room rather than writing SQLite helpers and cursors by hand?

    The strongest answer: Room checks the queries at compile time, maps rows to objects, gives you a migration path and observable queries, and keeps the work off the main thread — all of which you would hand-roll and get wrong

    Why it works: Exactly — the win is the compile-time check and the migration story, not only the typing you save.

    • Room is a layer, not magic.
    • Queries verified at compile time.
    • Migrations are explicit and testable.
    • You still own the SQL.
  8. LiveData or StateFlow for a screen’s state on Android — what actually differs?

    The strongest answer: StateFlow is plain Kotlin with a current value, so it is testable off-device and composes with operators. LiveData is lifecycle-aware by itself; with StateFlow you collect it in a lifecycle-aware way yourself

    Why it works: Right — the trade is Android-awareness for testability and operators, and the collection site is where you pay it back.

    • Both are observable state.
    • StateFlow: plain Kotlin, always a value.
    • LiveData: lifecycle-aware on its own.
    • Collect flows tied to the lifecycle.
  9. A receiver for a system broadcast fires on one phone and never on another, with the same build.

    What do you check?

    The strongest answer: How it is registered. Modern Android stopped delivering most implicit broadcasts to manifest-declared receivers, so register it from a running component, scoped to a lifecycle, and unregister in the matching callback

    Why it works: Right — registration style decides delivery, and a context-registered receiver must be unregistered or it leaks the screen.

    • Registration decides delivery.
    • Implicit broadcasts skip manifest receivers.
    • Register from a running component.
    • Unregister with the lifecycle.
  10. When do you split an Android app into Play feature modules?

    The strongest answer: When a large, optional surface is worth the install-time / on-demand complexity and we can measure the download — not to hide code from review, and not for a 20 KB settings screen

    Why it works: Exactly. On-demand is a product and ops feature. Review still sees what you deliver.

    • Split optional, large surfaces.
    • Measure the download.
    • Do not use modules to dodge review.
    • Keep the base able to start.
  11. A sync job is enqueued every time the user opens the sync screen. After a flaky week, support reports duplicate uploads.

    What went wrong, and what do you use instead?

    The strongest answer: Every visit enqueued another request, and a flaky week let them pile up. Enqueue it as unique work with a name and a policy, and make the worker idempotent so a retry cannot duplicate an upload

    Why it works: Exactly — unique work stops the queue growing and idempotency covers the retries the system will do anyway.

    • Name the work; keep it unique.
    • Enqueue unique work with a policy.
    • Make the worker idempotent.
    • Assume the system will retry it.
  12. Product wants the app to hold a foreground service all day so a dashboard is always up to date. How do you handle it?

    The strongest answer: I ask what the user gets for the battery and the permanent notification, then offer push or periodic work. A foreground service is for a task the user started and can see, not for freshness

    Why it works: Right — the test is whether the user is watching the task, and “always fresh” is a push or on-open problem instead.

    • Foreground service equals visible task.
    • Ask what the user gains.
    • Prefer push or periodic work.
    • Never fight background limits.