PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep
|Home/System Design/OpenAI

Design Android MVVM API Architecture

Last updated: Jun 17, 2026

Quick Overview

This question evaluates a candidate's skill in designing Android client-side MVVM architecture, testing competencies in layered decomposition, HTTP request lifecycle, threading and cancellation, ViewModel lifecycle across Java/Kotlin/Compose, UI state modeling, and navigation; the domain is system design for Android application architecture.

  • medium
  • OpenAI
  • System Design
  • Android Engineer

Design Android MVVM API Architecture

Company: OpenAI

Role: Android Engineer

Category: System Design

Difficulty: medium

Interview Round: Technical Screen

Design the **client-side architecture** for a single Android screen that loads data from a remote HTTP API and renders it in a Jetpack Compose UI, using an **MVVM-style** architecture. Walk through the full request-to-render path and be ready to defend each decision — the interviewer cares as much about *why* you make a choice as *what* you choose. Lead with a layered MVVM decomposition, then drill into the rest. Your design must address: - **HTTP request construction and execution** — how the request is built, sent, parsed, and how transport errors are surfaced to upper layers. - **Threading, concurrency, cancellation, and race conditions** — what scope work runs in, how stale work is cancelled, and how out-of-order responses are prevented from corrupting state. - **UI states** — loading, success, empty, and error, including retry behavior. - **Navigation** between screens, and where navigation logic should live. - **ViewModel lifecycle management** across three setups: (a) Java-based Android, (b) Kotlin with coroutines/`Flow`, and (c) Kotlin with Jetpack Compose. For each, explain the lifecycle, how state is exposed, and the pitfalls to watch for. - **Alternative designs, trade-offs, and possible optimizations.** ```hint Where to start — the layering Settle the layering before anything else: how many layers are there, and which single layer is allowed to know HTTP exists? Ask yourself whether the Compose UI should ever be able to reach the network client — if not, what does that imply about the direction of dependencies between UI, presentation, and data? Also pin down the one invariant about *which way data moves vs. which way user actions move*. Getting that contract right organizes every later decision. ``` ```hint Concurrency & race conditions First decide which scope the fetch runs in so that leaving the screen cleans up in-flight work for free (and why a process-wide scope is the wrong answer). Then sit with the nasty case: the user taps retry several times and a *slower, older* request finishes last. What guarantees only the newest result reaches the UI? There's a declarative answer built from flow operators and a manual-bookkeeping answer — try to reach both and reason about which you'd default to. ``` ```hint Modeling UI state The ViewModel should expose **one immutable source of truth** — but its *shape* is a real decision. Compare a closed set of mutually-exclusive states against a single bag of fields, and ask which one lets you keep showing old data while a refresh runs (think pull-to-refresh) and which one makes illegal combinations impossible. Then ask a modeling question: is "the request succeeded but returned nothing" the *same* outcome as "the request failed"? Compose should render as a pure function of whatever you pick. ``` ```hint The three lifecycle setups Resist describing three different *lifecycles* — first convince yourself whether the `ViewModel` lifecycle even changes across Java, Kotlin+Flow, and Compose. If it doesn't, then what actually differs between the three? Frame it as: *how is async work observed, and how does state reach the view* in each setup. For each of the three, name the single pitfall most likely to bite (e.g. what does the VM hold that leaks, what gets collected wrong, where does a side effect get misplaced). ``` ```hint Navigation & one-time events Decide where the navigation API lives — should the ViewModel know about the navigator at all, or should the screen receive actions to perform? Then handle the subtler case: navigation that must happen *because* async logic succeeded. Ask what category of thing that is — is it part of the render state, or something else? — and what goes wrong if you model it as state and a config change or recomposition replays it. That failure mode points you at the fix. ``` ### Constraints & Assumptions - One screen that fetches a list (or detail) over HTTPS from a backend you do not control. Assume a typical JSON REST endpoint. - Compose is the rendering layer; assume modern AndroidX (`ViewModel`, `viewModelScope`, `StateFlow`, Navigation-Compose available) and a modern HTTP stack (Retrofit + OkHttp, or Ktor). - The main thread must never block; the UI must stay responsive during the network call. - Production concerns matter: configuration changes (rotation), process death/restoration, flaky networks, auth via bearer token, leak-freedom, and testability. - You are not asked to write a full app — focus on the layering, the data/state flow, and the lifecycle reasoning. Pseudocode and interface sketches are fine. ### Clarifying Questions to Ask - Is this a list screen or a detail screen, and does it paginate? Does it need pull-to-refresh? - Is the data cached/persisted (offline support, single-source-of-truth from a DB), or is it network-only? - How is auth handled — bearer token, refresh-on-401, anything the client must inject per request? - What is the existing codebase: Java/XML, Kotlin/Views, or Compose? Any team conventions or DI framework in place? - Are there strict latency/error-rate targets, or analytics/observability requirements? - Should multiple sections of the screen load independently (partial loading), or is it one atomic fetch? ### What a Strong Answer Covers - A clean layered MVVM split (UI / ViewModel / Repository / data source) with a clear rationale for each boundary and what crosses it. - HTTP details (method, headers/auth, serialization, timeouts) confined to the data layer; the ViewModel sees only a domain result type, not raw HTTP. - Structured concurrency: correct scope choice, automatic cancellation, and an explicit strategy for stale/out-of-order responses. - An exhaustive, single-source-of-truth UI state model with loading/success/empty/error and retry, and a justification of sealed-class vs data-class. - Correct, *differentiated* lifecycle reasoning for Java, Kotlin+Flow, and Compose — including the common pitfalls of each (Activity refs in the VM, duplicate jobs, lifecycle-unaware collection, side effects in the composable body). - Navigation kept out of the ViewModel, with a deliberate one-time-event story. - Error taxonomy + retry policy (manual vs auto-backoff, idempotency awareness) and concrete optimizations (caching, paging, recomposition stability, request dedup, instrumentation). - Alternatives (MVC/MVP/MVI/Clean Architecture, LiveData vs StateFlow) compared on trade-offs, with no claim that one is universally best. - A testing strategy spanning the layers. ### Follow-up Questions - Process death restores the Activity but your `viewModelScope` job was killed mid-flight. How do you restore state and avoid showing a permanent spinner? Where does `SavedStateHandle` fit? - The screen makes three independent API calls and one fails. Walk through how you'd represent and render a partial-failure state. - A user double-taps a non-idempotent "submit" that triggers a POST. How does your design prevent a duplicate write, both client-side and end-to-end? - Compare `LiveData`, `StateFlow`, and `SharedFlow` for exposing UI state vs one-time events. When does each leak or misbehave, and which would you default to?

Quick Answer: This question evaluates a candidate's skill in designing Android client-side MVVM architecture, testing competencies in layered decomposition, HTTP request lifecycle, threading and cancellation, ViewModel lifecycle across Java/Kotlin/Compose, UI state modeling, and navigation; the domain is system design for Android application architecture.

Related Interview Questions

  • Design Video Generation Orchestration - OpenAI (medium)
  • Design CI/CD Build Caching - OpenAI
  • Design an Instagram-like Feed System - OpenAI (medium)
  • Design Online Chess Matchmaking - OpenAI (hard)
  • Design a Distributed Crossword Solver - OpenAI (hard)
OpenAI logo
OpenAI
May 23, 2026, 12:00 AM
Android Engineer
Technical Screen
System Design
2
0

Design the client-side architecture for a single Android screen that loads data from a remote HTTP API and renders it in a Jetpack Compose UI, using an MVVM-style architecture.

Walk through the full request-to-render path and be ready to defend each decision — the interviewer cares as much about why you make a choice as what you choose. Lead with a layered MVVM decomposition, then drill into the rest. Your design must address:

  • HTTP request construction and execution — how the request is built, sent, parsed, and how transport errors are surfaced to upper layers.
  • Threading, concurrency, cancellation, and race conditions — what scope work runs in, how stale work is cancelled, and how out-of-order responses are prevented from corrupting state.
  • UI states — loading, success, empty, and error, including retry behavior.
  • Navigation between screens, and where navigation logic should live.
  • ViewModel lifecycle management across three setups: (a) Java-based Android, (b) Kotlin with coroutines/ Flow , and (c) Kotlin with Jetpack Compose. For each, explain the lifecycle, how state is exposed, and the pitfalls to watch for.
  • Alternative designs, trade-offs, and possible optimizations.

Constraints & Assumptions

  • One screen that fetches a list (or detail) over HTTPS from a backend you do not control. Assume a typical JSON REST endpoint.
  • Compose is the rendering layer; assume modern AndroidX ( ViewModel , viewModelScope , StateFlow , Navigation-Compose available) and a modern HTTP stack (Retrofit + OkHttp, or Ktor).
  • The main thread must never block; the UI must stay responsive during the network call.
  • Production concerns matter: configuration changes (rotation), process death/restoration, flaky networks, auth via bearer token, leak-freedom, and testability.
  • You are not asked to write a full app — focus on the layering, the data/state flow, and the lifecycle reasoning. Pseudocode and interface sketches are fine.

Clarifying Questions to Ask

  • Is this a list screen or a detail screen, and does it paginate? Does it need pull-to-refresh?
  • Is the data cached/persisted (offline support, single-source-of-truth from a DB), or is it network-only?
  • How is auth handled — bearer token, refresh-on-401, anything the client must inject per request?
  • What is the existing codebase: Java/XML, Kotlin/Views, or Compose? Any team conventions or DI framework in place?
  • Are there strict latency/error-rate targets, or analytics/observability requirements?
  • Should multiple sections of the screen load independently (partial loading), or is it one atomic fetch?

What a Strong Answer Covers

  • A clean layered MVVM split (UI / ViewModel / Repository / data source) with a clear rationale for each boundary and what crosses it.
  • HTTP details (method, headers/auth, serialization, timeouts) confined to the data layer; the ViewModel sees only a domain result type, not raw HTTP.
  • Structured concurrency: correct scope choice, automatic cancellation, and an explicit strategy for stale/out-of-order responses.
  • An exhaustive, single-source-of-truth UI state model with loading/success/empty/error and retry, and a justification of sealed-class vs data-class.
  • Correct, differentiated lifecycle reasoning for Java, Kotlin+Flow, and Compose — including the common pitfalls of each (Activity refs in the VM, duplicate jobs, lifecycle-unaware collection, side effects in the composable body).
  • Navigation kept out of the ViewModel, with a deliberate one-time-event story.
  • Error taxonomy + retry policy (manual vs auto-backoff, idempotency awareness) and concrete optimizations (caching, paging, recomposition stability, request dedup, instrumentation).
  • Alternatives (MVC/MVP/MVI/Clean Architecture, LiveData vs StateFlow) compared on trade-offs, with no claim that one is universally best.
  • A testing strategy spanning the layers.

Follow-up Questions

  • Process death restores the Activity but your viewModelScope job was killed mid-flight. How do you restore state and avoid showing a permanent spinner? Where does SavedStateHandle fit?
  • The screen makes three independent API calls and one fails. Walk through how you'd represent and render a partial-failure state.
  • A user double-taps a non-idempotent "submit" that triggers a POST. How does your design prevent a duplicate write, both client-side and end-to-end?
  • Compare LiveData , StateFlow , and SharedFlow for exposing UI state vs one-time events. When does each leak or misbehave, and which would you default to?

Solution

Show

Submit Your Answer to Earn 20XP

Sign in to leave a comment

Loading comments...

Browse More Questions

More System Design•More OpenAI•More Android Engineer•OpenAI Android Engineer•OpenAI System Design•Android Engineer System Design
PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.