Design Android MVVM API Architecture
OpenAIAndroid Engineer · Technical ScreenLast updated
Design a robust, scalable Android client architecture using MVVM and Unidirectional Data Flow (UDF) to interact with remote REST and streaming APIs, handling configuration changes, lifecycle events, and coroutine cancellation.
Scenario
You are tasked with designing the client-side architecture for an interactive AI assistant application on Android. The app allows users to view their conversation history, send prompts, stream real-time responses from an LLM service, and search past sessions.
Your goal is to define a clean, layered MVVM architecture that is resilient to network fluctuations, responsive across configuration changes, and maintainable for a large engineering team.
Requirements
Functional Requirements
- Chat & Streaming: Users can submit prompts and receive streamed text responses (Server-Sent Events or WebSockets) as well as standard paginated conversation history (REST).
- Cancellation & Retries: Users can abort an ongoing generation mid-stream. Failed network requests should support exponential backoff or user-triggered retries.
- Offline Access: Previously viewed conversations must be accessible offline.
Non-Functional Requirements
- Unidirectional Data Flow (UDF): Enforce strict separation of concerns and clear data flow between layers.
- Lifecycle Awareness: Prevent memory leaks and redundant network calls during configuration changes (e.g., screen rotation) or when backgrounded.
- Testability: Decouple business logic from Android framework dependencies to allow comprehensive unit and integration testing.
What to Cover
- Layered Architecture: Detail the responsibilities of the Presentation (Jetpack Compose / ViewModel), Domain (Use Cases), and Data (Repository, Data Sources) layers.
- UI State Modeling: Propose an immutable state model representing loading, streaming tokens, error states, and finalized output without allowing impossible UI states.
- Threading & Concurrency: Explain how you use Kotlin Coroutines and Flow (e.g.,
StateFlow,SharedFlow) to manage background work, thread dispatching, and structured cancellation. - Data Management: Show how the repository coordinates between remote network sources (e.g., Retrofit, OkHttp) and local persistent storage (e.g., Room).
- Lifecycle & Edge Cases: Address configuration changes, process death (
SavedStateHandle), and graceful handling of dropped streaming connections.
Hints
Hint 1
Model your UI state using a sealed interface or data class with discrete subtypes to guarantee impossible states (like simultaneous loading and error) cannot occur.
Hint 2
Rely on structured concurrency with `viewModelScope` so that in-flight network requests and coroutine jobs cancel automatically when the ViewModel is cleared.
Hint 3
Separate one-off side effects (e.g., showing a snackbar, navigating) from persistent UI state using a dedicated channel or event flow.
Follow-up questions
- How would you throttle or batch high-frequency token updates from an SSE stream to prevent frame drops in Jetpack Compose?
- How does your architecture handle system process death compared to a standard configuration change, and what data should be retained via `SavedStateHandle`?
- If the client needs to transition from pure offline mode to syncing local edits with the backend, how would you design conflict resolution in the repository layer?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.