← All courses

Interview questionsMobile DevelopmentIntermediate

Top 10 Android and Flutter interview questions

Activity lifecycle, ViewModel, coroutines, ANRs and memory leaks on Android; widgets, state management and performance in Flutter; and the cross-platform trade-offs every mobile interview explores.

10 min · 10 questions

1Explain the Android activity lifecycle.

onCreate() (set up the UI and ViewModel) → onStart() (becoming visible) → onResume() (in the foreground, interactive) → onPause() (losing focus, e.g. a dialog or multi-window) → onStop() (no longer visible) → onDestroy() (finishing or being recreated). onRestart() runs when coming back from stopped.

Practical points: start camera, sensors or location updates in onStart/onResume and release them in onPause/onStop; save small UI state for process death; never assume onDestroy will be called (the OS can kill the process). On rotation, the activity is destroyed and recreated, which is why state goes in a ViewModel.

2What is a ViewModel and why is it used?

A ViewModel (Android Architecture Components) holds and manages UI-related data in a lifecycle-aware way. It survives configuration changes like rotation, so data isn't reloaded and in-flight work isn't lost. It's cleared when the screen is finished for good (onCleared).

It separates UI logic from the Activity/Fragment/Composable, exposes state (StateFlow/LiveData) for the UI to observe, launches coroutines in viewModelScope (automatically cancelled when cleared), and is easy to unit test. It does not survive process death; combine it with SavedStateHandle for small, important state like a search query. Never hold a reference to an Activity or View in a ViewModel (memory leak).

3What are Kotlin coroutines, and how do they differ from threads?

Coroutines are lightweight, suspendable computations for asynchronous code written in a sequential style. A suspend function can pause without blocking its thread, which then does other work.

  • Lightweight: thousands of coroutines can run on a few threads; threads are expensive (memory, context switches).
  • Dispatchers choose where work runs: Main (UI), IO (network/disk), Default (CPU work).
  • Structured concurrency: coroutines live in scopes (viewModelScope, lifecycleScope); cancelling the scope cancels its children, preventing leaks.
kotlin
viewModelScope.launch {
    _state.value = Loading
    _state.value = try { Ready(withContext(Dispatchers.IO) { repo.jobs() }) }
                   catch (e: IOException) { Error("No connection") }
}

Flows (Flow, StateFlow, SharedFlow) model streams of values over time.

4What causes an ANR and how do you prevent it?

An ANR (Application Not Responding) happens when the main thread is blocked: no response to input for about 5 seconds, or a broadcast receiver running too long. Causes: network or database calls on the main thread, heavy computation, large file I/O, lock contention, or a deadlock.

Prevention: move I/O and CPU work off the main thread (coroutines with Dispatchers.IO/Default, WorkManager for deferrable background work), keep onCreate light, avoid synchronous waits, paginate large data, and use StrictMode in debug builds to catch disk/network access on the main thread. Investigate ANRs with Play Console vitals and trace files.

5How do memory leaks happen in Android, and how do you find them?

A leak happens when an object that should be garbage-collected is still referenced, typically an Activity or Fragment view after it's destroyed. Common causes:

  • Static fields or singletons holding an Activity context (use the application context).
  • Non-static inner classes, anonymous listeners or callbacks that outlive the screen.
  • Registering listeners or broadcast receivers and never unregistering them.
  • Long-running tasks referencing the UI after it's gone (use lifecycle-aware scopes).
  • Fragments holding view bindings after onDestroyView (null them out).

Find them with LeakCanary (automatic leak detection in debug builds) and the Android Studio Memory Profiler (heap dumps).

6What is the difference between StatelessWidget and StatefulWidget in Flutter?

  • A StatelessWidget has no mutable state; it's rebuilt only when its parent passes new configuration. Examples: icons, labels, a job card that only displays data.
  • A StatefulWidget is paired with a State object that persists across rebuilds and can call setState() to trigger a rebuild. Examples: forms, animations, toggles, counters.

The widget itself is still immutable; the State object holds what changes. Lifecycle methods on State: initState, didChangeDependencies, build, didUpdateWidget, dispose (cancel controllers, subscriptions and timers here). Use const constructors for stateless subtrees to skip unnecessary rebuilds.

7How do you manage state in Flutter? Compare approaches.

  • setState: local, simple UI state within one widget.
  • InheritedWidget / Provider: share state down the tree; Provider is a simpler wrapper over InheritedWidget.
  • Riverpod: compile-safe, testable providers independent of the widget tree; handles async state (AsyncValue) well. A popular modern default.
  • BLoC/Cubit: business logic components that take events and emit states via streams; very predictable and testable; more boilerplate; popular in larger teams.
  • GetX/MobX: less boilerplate; mixed opinions on architecture discipline.

A good answer: use local state for ephemeral UI (a text field, an animation), and a dedicated solution for app state (auth, cart, cached data), choosing based on team size and testability. Keep business logic out of widgets.

8How does Flutter render UI, and how do you optimise performance?

Flutter has three trees: widgets (immutable configuration), elements (instances managing lifecycle and linking widgets to render objects) and render objects (layout and painting). Flutter's engine (Skia, now Impeller) draws every pixel itself, so the UI looks identical on every platform.

Optimisation:

  • Use const widgets and split large build methods into smaller widgets so less rebuilds.
  • Use ListView.builder/GridView.builder for long lists.
  • Avoid expensive work in build; move it to state or isolates (compute) for CPU-heavy tasks.
  • Cache and size images properly; avoid unnecessary Opacity, clipping and saveLayer operations.
  • Use RepaintBoundary for frequently changing parts.
  • Profile in profile mode with Flutter DevTools (the frame chart: aim for 16 ms per frame at 60 fps).

9Native vs cross-platform development: how would you choose?

Native (Kotlin/Swift): best performance, immediate access to new platform features, the most natural platform look and feel; costs two codebases and two teams.

Cross-platform (Flutter, React Native, KMP): one codebase (often 80–95% shared), faster development, consistent features on both platforms; costs a dependency on the framework and plugins, some extra app size, and native work for advanced device features.

My decision factors: team skills, budget and timeline, performance needs (games, heavy media, AR → native), depth of device integration, design consistency needs, and long-term maintenance. Many companies use cross-platform for most of the app with native modules for specific features.

10How would you implement push notifications and offline support in an app?

Push notifications: integrate Firebase Cloud Messaging; on first launch, request permission (required on Android 13+ and iOS) at a meaningful moment, not immediately; send the device token to your backend linked to the user; the backend sends notifications through FCM; handle foreground, background and terminated states; deep-link taps to the right screen; use channels/categories so users can control what they receive; refresh tokens when they change.

Offline support: store data locally (Room/Drift/SQLite) as the single source of truth; the UI observes the local database; sync with the server in the background (WorkManager) when online; queue user actions made offline and retry with conflict handling (last-write-wins or server rules); show clear connectivity status; cache images. This "offline-first" pattern makes apps feel fast even on slow networks.

Keep going