← All articles
14 min read

Android Interview Questions 2026: Kotlin, Compose and Design

The Android interview in 2026 tests Kotlin depth, coroutines and Flow, Compose state, and a mobile system design round. Here are the questions that come up and how strong candidates answer them.

Android interview questions in 2026 focus on five areas: Kotlin language depth, coroutines and Flow, Jetpack Compose state management, the Android lifecycle, and app architecture with dependency injection. Mid-level and senior candidates also face a mobile system design round, usually an offline-capable feed or messaging screen. The best preparation pairs short, precise answers to the core questions with one fully worked system design you can draw from memory.

This guide gives you both, with model answers, code, and a complete walkthrough of the most common Android design prompt.

Key Takeaways

  • Kotlin questions have moved past syntax. Expect sealed hierarchies, inline and reified functions, value classes, and variance with in and out.
  • Coroutines and Flow come up in almost every Android domain round. Know structured concurrency, cancellation, dispatchers, and StateFlow versus SharedFlow, and cold versus hot flows.
  • Compose questions test your mental model of recomposition, state hoisting, stability, and side-effect APIs, not widget trivia.
  • Lifecycle questions in 2026 are really about state survival: configuration changes, process death, and SavedStateHandle.
  • The system design round rewards a clear layered architecture, a single source of truth in a local database, and specific numbers for image memory and pagination.

What Does the Android Developer Interview Loop Look Like in 2026?

A typical Android developer interview loop has a recruiter call, a technical phone screen, and a virtual onsite with coding, an Android domain round, mobile system design, and behavioral. Large companies such as Google and Meta still run algorithms rounds; smaller companies often swap them for a practical build.

StageLengthWhat is testedHow to prepare
Phone screen45-60 minOne coding problem in Kotlin, or Android fundamentals Q&AMedium-level problems, Kotlin collections fluency
Coding round45-60 minData structures and algorithmsCore patterns, written in idiomatic Kotlin
Android domain45-60 minKotlin, coroutines, Compose, lifecycleThis guide's question sections
Practical build or take-home60-120 min or 3-6 hrsA screen that loads, caches, and displays dataBuild a paginated list app with Compose and Room
Mobile system design45-60 minClient architecture, caching, sync, performanceThe feed walkthrough below
Behavioral30-45 minOwnership, conflict, shipping under constraintsSTAR stories with mobile-specific details

For the algorithms rounds, the coding interview patterns cheat sheet covers the patterns that show up most. Kotlin is accepted for these rounds at most companies.

Kotlin Fundamentals Interview Questions

Kotlin questions check whether you write the language idiomatically or just translate Java.

What is the difference between val, var, and const val? val is a read-only reference, var is mutable, and const val is a compile-time constant for primitives and String. A val holding a MutableList still lets the list change, a frequent follow-up.

How does Kotlin null safety work? Types are non-nullable by default, and String? marks a nullable type. You handle nulls with safe calls (?.), the Elvis operator (?:), smart casts after a null check, and !! only when a null would be a genuine bug. Platform types from Java code are the gap where null safety can still fail at runtime.

When would you use a sealed class instead of an enum? Use a sealed class or sealed interface when each case carries different data. Screen state is the classic example:

sealed interface FeedUiState {
    data object Loading : FeedUiState
    data class Success(val posts: List<Post>, val isRefreshing: Boolean) : FeedUiState
    data class Error(val message: String, val cached: List<Post>) : FeedUiState
}

A when expression over a sealed type is exhaustive, so the compiler flags any unhandled state when you add a new case.

What do inline and reified do? An inline function copies its body and lambda arguments into the call site, which removes lambda allocation and allows non-local returns. reified type parameters only work on inline functions and keep the generic type available at runtime, so you can write inline fun <reified T> Gson.fromJson(json: String): T.

Also rehearse: what data classes generate (only from primary constructor properties), the five scope functions, lateinit versus by lazy, why extension functions resolve statically, out and in variance, and @JvmInline value class for type-safe IDs.

Kotlin Coroutines and Flow Interview Questions

Coroutines are among the most heavily tested Android topics because most modern data layers run on them. The official Kotlin coroutines guide is the best primary reference. For thread-level concepts underneath, see our concurrency and multithreading interview questions.

What is structured concurrency? Structured concurrency means every coroutine runs inside a scope, and a parent does not complete until its children finish. If the scope is cancelled, all children are cancelled. On Android, viewModelScope is cancelled when the ViewModel is cleared and lifecycleScope when the lifecycle is destroyed, so work cannot leak past its owner. GlobalScope breaks this model, which is why it is discouraged.

How does cancellation work, and what is the common bug? Cancellation is cooperative. Suspending functions from kotlinx.coroutines check for cancellation and throw CancellationException. Tight CPU loops must call ensureActive() or yield(). The classic bug is a broad catch (e: Exception) around a suspend call that swallows CancellationException, so the coroutine keeps running after its scope died. Rethrow it or catch narrower types.

Job versus SupervisorJob? With a regular Job, one failing child cancels the parent and all siblings. With SupervisorJob, a child failure stays isolated. viewModelScope uses a SupervisorJob, which is why one failed request does not kill other work in the same ViewModel.

Which dispatcher do you use? Main for UI, IO for blocking I/O, and Default for CPU-heavy work like parsing large lists. Good repositories stay main-safe by switching internally with withContext; Room and Retrofit suspend functions already are.

StateFlow versus SharedFlow? StateFlow always has a value, replays the latest one, and drops consecutive duplicates. It is the default for UI state. SharedFlow has configurable replay and no initial value, which suits events. For one-off events like a snackbar, Google's architecture guidance prefers modeling them as state the UI consumes and clears.

Here is the ViewModel pattern most interviewers expect you to write:

@HiltViewModel
class FeedViewModel @Inject constructor(
    private val repository: FeedRepository
) : ViewModel() {

    val uiState: StateFlow<FeedUiState> = repository.observeFeed()
        .map<List<Post>, FeedUiState> { FeedUiState.Success(it, isRefreshing = false) }
        .catch { emit(FeedUiState.Error(it.message.orEmpty(), emptyList())) }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5_000),
            initialValue = FeedUiState.Loading
        )

    fun refresh() {
        viewModelScope.launch { repository.refresh() }
    }
}

Be ready to explain WhileSubscribed(5_000): the upstream stays active for five seconds after the last collector leaves. A rotation resubscribes well within that window, so the query does not restart, but work still stops when the app is backgrounded.

Other Flow questions that come up:

  • Cold versus hot flows: a flow {} builder runs per collector; StateFlow and SharedFlow are shared.
  • flatMapLatest with debounce for search-as-you-type, and combine versus zip.
  • Lifecycle-safe collection with repeatOnLifecycle(Lifecycle.State.STARTED) in Views and collectAsStateWithLifecycle() in Compose.

Coroutine follow-ups like "what happens to that job on rotation?" can stall even experienced Android developers. TechScreen listens to the question and shows a structured answer on your screen in real time, invisible during screen share on Zoom, Meet, and Teams. Try it with 3 free tokens, no credit card needed.

Get started free →

Jetpack Compose Interview Questions

Compose questions test your mental model of how the runtime decides what to redraw.

What is recomposition? Recomposition is Compose re-running composable functions whose inputs changed so the UI matches the new state. Compose tracks reads of State objects and only re-runs the scopes that read the changed value. A frame goes through three phases: composition (what to show), layout (where to put it), and drawing (how to render it). A state read in a later phase skips the earlier ones.

What is state hoisting? State hoisting means moving state out of a composable to its caller, so the composable takes a value and an event callback. This makes it stateless, reusable, previewable, and testable, and it creates unidirectional data flow: state flows down, events flow up.

@Composable
fun FeedRoute(viewModel: FeedViewModel = hiltViewModel()) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    FeedScreen(state = state, onRefresh = viewModel::refresh)
}

@Composable
fun FeedScreen(state: FeedUiState, onRefresh: () -> Unit) {
    when (state) {
        FeedUiState.Loading -> LoadingIndicator()
        is FeedUiState.Success -> PostList(state.posts, onRefresh)
        is FeedUiState.Error -> ErrorView(state.message, onRetry = onRefresh)
    }
}

remember versus rememberSaveable? remember keeps a value across recompositions but loses it on configuration change. rememberSaveable stores it in the saved instance state Bundle, so it survives rotation and process death, as long as the type is saveable or has a custom Saver.

When do you use derivedStateOf? Use it when a value derived from state changes less often than the state itself. The textbook case is showing a "scroll to top" button only when listState.firstVisibleItemIndex > 0. Without derivedStateOf, every scroll pixel would trigger recomposition.

Explain the side-effect APIs. LaunchedEffect(key) runs a suspend block on entering composition and restarts when the key changes. DisposableEffect registers and cleans up listeners. rememberUpdatedState lets a long-running effect see the latest lambda without restarting.

What is stability, and why does it matter? Compose can skip a composable when all its parameters are stable and unchanged. Since Kotlin 2.0.20, strong skipping mode is enabled by default in the Compose compiler, which lets composables with unstable parameters skip when those instances are equal by reference. Still mention immutable UI models and stable keys in LazyColumn.

How do you defer state reads for performance? Pass a lambda instead of a value to lambda-based modifiers, such as Modifier.offset { IntOffset(0, scroll.value) } instead of Modifier.offset(y = ...). The read moves to the layout phase and skips recomposition entirely for scroll-driven animations.

Activity and Fragment Lifecycle Questions

Lifecycle questions in 2026 are less about reciting onCreate through onDestroy and more about where state survives.

What happens on rotation? By default, a configuration change destroys and recreates the Activity. A ViewModel survives because it is scoped to the ViewModelStoreOwner, not to the Activity instance. UI element state survives through saved instance state or rememberSaveable.

What is process death, and how do you handle it? When the app is in the background, the system can kill the process to reclaim memory. When the user returns, Android recreates the Activity and restores the saved state Bundle, but the ViewModel is gone. You handle this with SavedStateHandle in the ViewModel for small, critical state such as a search query or selected ID, and you reload everything else from the repository. Test it by killing the backgrounded process with adb.

What is the difference between a Fragment's lifecycle and its view lifecycle? A Fragment can outlive its view, for example on the back stack. Observing LiveData or collecting flows with this instead of viewLifecycleOwner leaks the old view and creates duplicate observers when the view is recreated.

Interviewers also probe TransactionTooLargeException from oversized Bundles and predictive back, where you use OnBackPressedCallback or Compose's BackHandler instead of overriding onBackPressed.

Architecture: MVVM, MVI, and Dependency Injection

Architecture questions check whether you can explain why the layers exist. Google's guide to app architecture recommends a UI layer, an optional domain layer, and a data layer, with unidirectional data flow and a single source of truth for each type of data.

MVVM versus MVI: which do you use? MVVM exposes observable state from a ViewModel and handles events through its functions. MVI adds a single immutable state, a sealed set of intents, and a reducer. Most Compose apps sit between the two.

QuestionMVVMMVI
State shapeOne or several observable fieldsOne immutable state object
EventsViewModel functionsSealed Intent or Action class
BoilerplateLowerHigher
DebuggabilityGoodVery good: every state change is traceable
Best fitMost screensComplex screens with many interacting inputs

A strong answer picks MVVM with a single UI state for most screens, and reaches for a reducer when a screen has many inputs that interact, such as a checkout or editor.

Why use dependency injection, and why Hilt? DI makes classes testable by passing in dependencies instead of creating them, and it controls object lifetimes. Hilt, built on Dagger, generates the graph at compile time with standard Android components and scopes (@Singleton, @ActivityRetainedScoped, @ViewModelScoped). Koin is a popular runtime alternative with less setup and no annotation processing, at the cost of errors appearing at runtime. Know the trade-off rather than claiming one is always right.

Do you need a domain layer? Only when business logic is reused across ViewModels or is complex enough to test alone. Use cases that just forward a repository call signal over-engineering. Our design patterns interview guide covers the repository and observer patterns behind these layers.

Android System Design Walkthrough: An Image-Heavy Feed with Caching

The mobile system design round asks you to design the client side of a feature, not the backend. The most common prompt is some version of "design the Instagram or Pinterest home feed for Android." The backend version of this problem is covered in our news feed system design guide; here is the client walkthrough interviewers expect.

Step 1: Clarify requirements (5 minutes)

Pin down scope with questions, then state your assumptions:

  • Functional: infinite scroll of posts with one or more images, pull to refresh, like a post, works offline with cached content.
  • Non-functional: smooth scrolling at the device's refresh rate, fast cold start to first content, bounded memory and disk, low data usage on metered networks.
  • Out of scope unless asked: video autoplay, post creation, real-time updates.

Step 2: Draw the layers (10 minutes)

FeedScreen reads StateFlow<FeedUiState> from FeedViewModel, which calls FeedRepository, which coordinates a remote source (Retrofit or Ktor) and Room. Say the key decision out loud: Room is the single source of truth. The network only writes to the database and the UI only reads from it, which gives you offline support, consistency after process death, and simple optimistic updates.

Step 3: Define the API and pagination (5 minutes)

Use cursor-based pagination, such as GET /feed?cursor=abc&limit=20, returning posts plus a nextCursor. Explain why cursors beat offsets for feeds: new posts arriving at the top shift offset pages and cause duplicates or gaps. Each post should include image URLs at several sizes, width and height (so the layout can reserve space and avoid jumps), and a small placeholder such as a blurhash or dominant color.

On the client, Paging 3 with a RemoteMediator maps directly onto this design. The mediator fetches pages from the network, writes them to Room in a transaction along with remote keys, and the PagingSource from Room feeds LazyColumn through collectAsLazyPagingItems().

Step 4: Image loading and caching (10 minutes)

This is where you win or lose an image-heavy feed. Use an image library such as Coil or Glide rather than writing your own, but explain what it does for you:

LayerWhat it storesTypical sizingWhy it matters
Memory cacheDecoded bitmaps keyed by URL plus sizeA fraction of the app's available heapInstant rebinding while scrolling back
Disk cacheEncoded image bytesTens to a few hundred MB, LRU evictionOffline display and fewer downloads
HTTP cacheResponses honoring cache headersShared with OkHttpRevalidation without full downloads

Then cover the details that show real experience:

  • Downsample to the view size. A 4000x3000 image decoded at ARGB_8888 takes about 48 MB (4 bytes per pixel). At a 1080x810 display size, it takes about 3.5 MB. Request the server size closest to the slot width.
  • Prefetch and cancel. Load the next page and its images early, and cancel requests for items that scroll off screen.
  • Reserve space. Use the API's aspect ratio so the layout does not shift when images arrive.

Step 5: Offline, sync, and writes (5 minutes)

For likes, apply an optimistic update in Room immediately, queue the request, and send it with WorkManager using a network constraint so it survives app restarts. Make the server endpoint idempotent so retries cannot double-count. On refresh, replace the first page in a single Room transaction to avoid flicker, and prune old pages to cap disk use.

Step 6: Performance and observability (5 minutes)

Close with measurement: Macrobenchmark for startup and scroll jank, Baseline Profiles for cold start, Android vitals in Play Console for production frame metrics, and LeakCanary for leaks. For a general framework, see how to ace the system design interview.

Performance and Testing Questions

Performance and testing questions separate candidates who have shipped apps from those who have only built tutorials.

  • How do you diagnose jank? Reproduce in a release build, record a trace with Perfetto or the Android Studio profiler, and look for long main-thread work, excess recomposition, or bitmap decodes on the main thread.
  • How do you improve cold start? Defer non-critical initialization, keep disk and network out of Application.onCreate, and ship Baseline Profiles.
  • What causes memory leaks? Activity or View references held by longer-lived objects: singletons, unremoved listeners, or coroutines in the wrong scope.
  • How do you test a ViewModel and Compose UI? Inject fakes, swap the main dispatcher for a test dispatcher, use runTest, and assert on UiState. For UI, use createComposeRule() against stateless screen composables with fixed state.

How to Prepare in the Final Two Weeks

  1. Days 1-4: Build a paginated, image-heavy list app with Compose, Hilt, Room, and Paging 3. It covers the practical round and gives you real stories.
  2. Days 5-8: Write the ViewModel above from memory, then explain cancellation, stability, and side effects aloud.
  3. Days 9-11: Rehearse the feed design twice, timed at 45 minutes, then a chat screen.
  4. Days 12-14: Kotlin algorithms if your loop has them, three to five behavioral stories, and mocks.

If you are also targeting Apple platforms, the iOS developer interview guide mirrors this structure for Swift and SwiftUI. When an offer arrives, our salary negotiation guide shows how to push on base, equity, and sign-on without risking the offer.

Walking into an Android loop with coroutines, Compose, and a feed design to cover? TechScreen gives you real-time answers and design outlines during the interview, invisible on screen share. Start with 3 free tokens and test it on a mock round first.

Get started free →

Frequently Asked Questions

What are the most common Android interview questions in 2026?

Most Android loops in 2026 cover five areas: Kotlin language features such as null safety, sealed classes, and inline functions; coroutines and Flow, especially structured concurrency and StateFlow versus SharedFlow; Jetpack Compose state, recomposition, and side effects; the Activity and Fragment lifecycle, including configuration changes and process death; and architecture with MVVM or MVI plus dependency injection with Hilt. Mid-level and senior candidates also get a mobile system design round, often an offline-capable feed or chat screen.

Do Android developer interviews still include LeetCode questions?

Usually yes, but less than backend loops. Large companies such as Google, Meta, and Amazon typically include one or two data structures and algorithms rounds at medium difficulty, often solvable in Kotlin. Many mid-size companies and startups replace them with a practical round, such as building a small Compose screen that loads paginated data from an API or debugging an existing app. Ask your recruiter for the exact loop so you split your preparation correctly.

Should I learn XML Views or only Jetpack Compose for interviews?

Lead with Compose, since Google recommends it for new Android UI and most 2026 interview exercises assume it. You should still understand the View system at a conceptual level: the measure, layout, and draw passes, RecyclerView with DiffUtil, and Fragment view lifecycles. Many production codebases are hybrid, so interviewers at established companies often ask how you would interoperate with ComposeView or AndroidView during a gradual migration.

What is the difference between StateFlow and SharedFlow?

StateFlow is a hot flow that always holds exactly one current value, replays that value to new collectors, and skips emissions equal to the previous value. It fits UI state. SharedFlow is a more general hot flow with configurable replay and buffering and no required initial value, which makes it a better fit for events that should not be deduplicated. A common answer pattern is StateFlow for screen state and a channel or SharedFlow only for true one-off effects.

How do I prepare for an Android system design interview?

Practice three or four mobile-specific prompts end to end: an offline-first feed, a chat screen, an image gallery, and a background sync feature. For each, cover requirements, the layer diagram from UI to repository to data sources, the API contract with cursor pagination, local caching with Room, image loading and memory limits, background work with WorkManager, and how you would measure performance. Interviewers care more about client-side trade-offs than about designing the backend in depth.

What Kotlin coroutines questions do senior Android interviews ask?

Senior rounds go past launch and async. Expect questions on structured concurrency and why GlobalScope is discouraged, how cancellation propagates and why catching CancellationException is a bug, the difference between Job and SupervisorJob, choosing dispatchers, making blocking code main-safe with withContext, flow operators such as flatMapLatest and debounce, cold versus hot flows, and how stateIn with WhileSubscribed avoids wasted work during configuration changes.

Ready to use AI assistance in your next interview?

TechScreen is the invisible AI assistant trusted by engineers interviewing at Google, Meta, Amazon, and hundreds of other companies. Start with 3 free tokens — no credit card required.

Ace your next interview →