Skip to content

Architecture


What is MVVM in Android architecture?

beginner architecture mvvm android
View Answer

MVVM separates UI rendering from business/data orchestration.

Typical split:

  • View: renders state and forwards user actions

  • ViewModel: exposes lifecycle-aware UI state

  • Repository: abstracts data access

Why teams use it:

  • better testability

  • cleaner separation of concerns

  • easier lifecycle-safe state handling

๐Ÿš€ See Full Deep Dive


What is the role of a ViewModel in scalable Android apps?

beginner architecture viewmodel state
View Answer

ViewModel owns screen-level state and survives configuration changes.

Key responsibilities:

  • transform domain data into UI-friendly state

  • coordinate use cases/repositories

  • expose immutable observable state

  • handle user intents/events

It should avoid direct Android UI references.

๐Ÿš€ See Full Deep Dive


When should you use SavedStateHandle in architecture design?

intermediate architecture viewmodel state
View Answer

Use SavedStateHandle for small, restorable screen state tied to process recreation.

Good candidates:

  • selected tab/index

  • filter/sort selection

  • lightweight form progress

Avoid storing large objects or domain caches in it.

๐Ÿš€ See Full Deep Dive


What is MVI architecture?

intermediate architecture mvi state
View Answer

MVI models UI as a loop: intent -> reducer -> new immutable state.

Core benefits:

  • predictable state transitions

  • easier debugging/time-travel style reasoning

  • explicit event handling contract

Tradeoff: can introduce boilerplate if over-applied.

๐Ÿš€ See Full Deep Dive


MVVM vs MVI - how do you choose?

senior architecture mvvm mvi
View Answer

Choose by complexity and team needs, not trend preference.

MVVM:

  • lower ceremony

  • common Android default

MVI:

  • stronger state/event determinism

  • better for complex interaction-heavy screens

Many teams use MVVM + UDF patterns as a middle ground.

๐Ÿš€ See Full Deep Dive


What are the key principles of Unidirectional Data Flow?

intermediate architecture udf state
View Answer

UDF means state flows down, events flow up.

Interview-ready points:

  • single source of truth for screen state

  • immutable state exposure

  • explicit intent/event handlers

  • deterministic state transitions

This reduces hidden mutation bugs.

๐Ÿš€ See Full Deep Dive


What is Clean Architecture in Android?

intermediate architecture clean-architecture layers
View Answer

Clean Architecture organizes code by responsibility and dependency direction.

Typical layers:

  • presentation

  • domain

  • data

Main rule: inner layers should not depend on outer framework details.

๐Ÿš€ See Full Deep Dive


What is the dependency rule in layered architecture?

senior architecture clean-architecture dependency-inversion
View Answer

Dependencies must point inward toward stable policy layers.

Practical implications:

  • UI depends on domain contracts

  • data implements domain abstractions

  • domain avoids Android/framework types

This improves portability and test isolation.

๐Ÿš€ See Full Deep Dive


How does dependency inversion apply to Android app architecture?

senior architecture solid dependency-inversion
View Answer

High-level policies should depend on abstractions, not concrete SDK/data details.

In Android this usually means:

  • domain uses interfaces

  • data/network/db implement those interfaces

  • DI wires concrete implementations

It keeps business logic resilient to infrastructure changes.

๐Ÿš€ See Full Deep Dive


Why use the Repository pattern?

beginner architecture repository data
View Answer

Repository abstracts data origin and provides a clean API to higher layers.

Benefits:

  • decouples UI/domain from network/db details

  • centralizes data policies

  • simplifies testing with fakes

  • enables caching/sync orchestration

๐Ÿš€ See Full Deep Dive


How does a repository support a Single Source of Truth model?

intermediate architecture repository state
View Answer

Repository enforces one authoritative read path for consumers.

Common approach:

  • local DB is canonical source

  • network refresh updates DB

  • UI observes DB-backed streams

This avoids competing data sources in UI.

๐Ÿš€ See Full Deep Dive


How should repositories orchestrate network, cache, and database sources?

senior architecture repository caching
View Answer

Define explicit policies for freshness, fallback, and write ordering.

Typical strategy:

  • read local first

  • fetch remote by staleness rules

  • merge/validate payload

  • persist then emit

Keep these rules in repository, not UI.

๐Ÿš€ See Full Deep Dive


What problem do use cases solve in architecture?

intermediate architecture use-cases domain
View Answer

Use cases encapsulate business actions independent of UI and data frameworks.

They help by:

  • isolating domain logic

  • improving reuse across screens

  • making behavior unit-testable

  • reducing ViewModel complexity

๐Ÿš€ See Full Deep Dive


How granular should use cases be?

senior architecture use-cases design
View Answer

Use cases should represent coherent business actions, not tiny wrappers.

Guidance:

  • too coarse: hard to compose/test

  • too fine: boilerplate and indirection

  • optimize for domain clarity and change boundaries

Granularity is a context-based design decision.

๐Ÿš€ See Full Deep Dive


When is a dedicated domain layer worth adding?

senior architecture domain clean-architecture
View Answer

Add domain layer when business rules are non-trivial or reused.

Signals:

  • multiple features share logic

  • policies outgrow ViewModels

  • testability/portability requirements increase

For simple apps, extra layers can be unnecessary overhead.

๐Ÿš€ See Full Deep Dive


Why is dependency injection important in Android architecture?

beginner architecture di testability
View Answer

DI manages object creation/wiring outside business logic.

Benefits:

  • loose coupling

  • easier testing with fakes/mocks

  • centralized lifecycle/scope control

  • clearer dependency graph at scale

๐Ÿš€ See Full Deep Dive


Constructor injection vs field injection - which is preferred?

intermediate architecture di design
View Answer

Constructor injection is usually preferred.

Reasons:

  • explicit required dependencies

  • easier immutable object design

  • better unit-test ergonomics

Field injection is useful in framework-controlled classes but less explicit.

๐Ÿš€ See Full Deep Dive


How do DI scopes affect memory and lifecycle behavior?

senior architecture di lifecycle
View Answer

Scopes define object lifetime and reuse boundaries.

Mis-scoping can cause:

  • leaks (too long-lived)

  • churn/perf cost (too short-lived)

  • inconsistent shared state

Align scopes with Activity/Fragment/ViewModel/app lifetimes.

๐Ÿš€ See Full Deep Dive


What architectural advantages does Hilt provide?

intermediate architecture hilt di
View Answer

Hilt standardizes DI setup for Android component lifecycles.

Key advantages:

  • less boilerplate than manual Dagger setup

  • predefined component hierarchy

  • easier onboarding and consistency

  • strong integration with ViewModel/WorkManager

๐Ÿš€ See Full Deep Dive


What Hilt component lifetimes should senior engineers know?

senior architecture hilt lifecycle
View Answer

Senior interviews expect understanding of scope boundaries.

Common lifetimes:

  • SingletonComponent: app-wide

  • ActivityRetainedComponent: across config changes

  • ViewModelComponent: ViewModel lifetime

  • Activity/Fragment components: UI-bound

Wrong scope choices create subtle bugs.

๐Ÿš€ See Full Deep Dive


Dagger vs Hilt - what is the architectural tradeoff?

senior architecture dagger hilt
View Answer

Hilt is Dagger with Android-focused conventions and generated glue code.

Tradeoff framing:

  • Hilt: faster setup, consistent patterns

  • raw Dagger: maximum graph/control flexibility

Choose based on customization needs and team productivity.

๐Ÿš€ See Full Deep Dive


What should you understand about Dagger components and subcomponents?

senior architecture dagger di
View Answer

Components define object graph roots; subcomponents model child lifecycles.

Important points:

  • parent can provide bindings to child

  • child can narrow scope/lifetime

  • graph shape affects compilation and maintainability

Avoid overly complex graph hierarchies.

๐Ÿš€ See Full Deep Dive


What are Dagger/Hilt build and runtime tradeoffs at scale?

staff architecture dagger scalability
View Answer

DI frameworks improve structure but add compile-time and graph complexity costs.

Staff-level concerns:

  • annotation processing build impact

  • module graph growth over time

  • debugging generated binding errors

  • balancing explicitness vs velocity

๐Ÿš€ See Full Deep Dive


What is a Service Locator pattern?

beginner architecture service-locator di
View Answer

Service Locator is a registry that provides dependencies on demand.

It can simplify small systems but often hides real dependencies.

Interview angle:

  • quick bootstrap option

  • weaker explicitness than constructor DI

  • can reduce testability if overused

๐Ÿš€ See Full Deep Dive


Service Locator vs DI - why does this matter in interviews?

intermediate architecture service-locator di
View Answer

DI makes dependencies explicit in constructors; Service Locator hides them at call sites.

Consequences:

  • DI is easier to reason about and test

  • Service Locator can create implicit coupling

  • hidden runtime failures are more likely

Prefer DI for medium/large apps.

๐Ÿš€ See Full Deep Dive


Why modularize Android apps?

intermediate architecture modularization scalability
View Answer

Modularization separates code by ownership and change boundaries.

Benefits:

  • faster incremental builds

  • clearer feature boundaries

  • parallel team development

  • safer refactoring and release isolation

๐Ÿš€ See Full Deep Dive


What multi-module structures are common in Android?

intermediate architecture modularization multi-module
View Answer

Common structures include layered modules and feature-first modules.

Typical options:

  • app + core + feature modules

  • domain/data/presentation split per feature

  • hybrid platform modules for shared infra

Choose structure based on team and product complexity.

๐Ÿš€ See Full Deep Dive


How do API vs implementation module boundaries improve architecture?

senior architecture modularization dependencies
View Answer

Expose only stable contracts and keep internals hidden.

Benefits:

  • reduced coupling and accidental usage

  • clearer ownership contracts

  • better compile isolation

  • safer internal refactors

Public surface area should stay intentionally small.

๐Ÿš€ See Full Deep Dive


What defines a good feature module boundary?

senior architecture feature-modules modularization
View Answer

A good boundary aligns with user-facing capabilities and team ownership.

Signs of healthy boundaries:

  • minimal cross-feature dependencies

  • explicit navigation/contracts

  • isolated tests and release paths

  • clear domain language per feature

๐Ÿš€ See Full Deep Dive


When should you use dynamic feature modules?

senior architecture feature-modules scalability
View Answer

Use dynamic delivery when features are optional, heavy, or region-specific.

Tradeoffs:

  • better install size/startup profile

  • added delivery/testing complexity

  • more runtime handling for missing modules

Evaluate product value against operational cost.

๐Ÿš€ See Full Deep Dive


How should dependency direction work between feature modules?

senior architecture modularization dependency-inversion
View Answer

Features should depend on shared contracts, not each other's internals.

Recommended pattern:

  • keep cross-feature APIs contract-driven

  • avoid cyclic feature dependencies

  • place shared infra in core/platform modules

This preserves build and team independence.

๐Ÿš€ See Full Deep Dive


What is a strong state management approach in Android architecture?

intermediate architecture state ui
View Answer

Keep state ownership explicit and state models immutable where possible.

Common approach:

  • ViewModel owns screen state

  • UI renders state + emits events

  • repository/domain updates source state

Avoid scattered mutable flags across layers.

๐Ÿš€ See Full Deep Dive


What does Single Source of Truth mean in practice?

intermediate architecture state repository
View Answer

One authoritative state source should drive reads for a given data set.

In practice:

  • define canonical owner (often DB-backed)

  • route all writes through controlled paths

  • keep projections/derived views read-only

This reduces inconsistency and race conditions.

๐Ÿš€ See Full Deep Dive


Why model UI state as immutable data classes?

intermediate architecture state testability
View Answer

Immutable state makes transitions explicit and easier to test.

Benefits:

  • predictable rendering behavior

  • simpler equality/change reasoning

  • safer concurrent/reactive usage

  • clearer reducer-style updates

๐Ÿš€ See Full Deep Dive


What is offline-first architecture?

senior architecture offline-first data
View Answer

Offline-first treats local storage as primary read path, syncing with network opportunistically.

Core principles:

  • local-first reads

  • resilient queued writes

  • explicit conflict policy

  • sync observability/telemetry

๐Ÿš€ See Full Deep Dive


Push, pull, and hybrid sync strategies - when to use each?

senior architecture sync offline-first
View Answer

Choose strategy by freshness needs, battery budget, and backend capability.

Quick framing:

  • pull: simple, periodic consistency

  • push: lower latency updates

  • hybrid: practical balance for many products

Design for retries and backoff from day one.

๐Ÿš€ See Full Deep Dive


How should architecture handle sync conflicts?

staff architecture sync data-consistency
View Answer

Conflict policy must be explicit and domain-aware.

Common strategies:

  • last write wins (simple, risky)

  • version/vector based merge

  • server-authoritative with client reconciliation

  • user-assisted conflict resolution for critical entities

Track conflict metrics to tune policy.

๐Ÿš€ See Full Deep Dive


What caching strategies are common in Android architecture?

intermediate architecture caching data
View Answer

Choose cache strategy per data volatility and UX expectations.

Common options:

  • memory cache for hot short-lived reads

  • disk/DB cache for persistence

  • TTL or staleness-based refresh

  • cache-aside or network-bound-resource style

๐Ÿš€ See Full Deep Dive


What does a robust pagination architecture look like?

senior architecture pagination data
View Answer

Robust pagination handles loading state, errors, deduplication, and persistence.

Must-have concerns:

  • stable page keys/cursors

  • append/prepend retry behavior

  • local cache coherence

  • refresh invalidation strategy

๐Ÿš€ See Full Deep Dive


How does StateFlow fit Android architecture design?

intermediate architecture stateflow reactive
View Answer

StateFlow is a lifecycle-friendly state stream for UI layers.

Architectural usage:

  • ViewModel exposes immutable StateFlow<UiState>

  • UI collects and renders

  • updates come from repository/use-case pipelines

Keep one-off events separate from persistent state.

๐Ÿš€ See Full Deep Dive


How should one-off events be handled in reactive architecture?

senior architecture events reactive
View Answer

Model state and events as different channels.

Typical pattern:

  • StateFlow for persistent UI state

  • SharedFlow/Channel for one-time events

  • consume events with lifecycle awareness

Avoid encoding transient events as sticky state flags.

๐Ÿš€ See Full Deep Dive


What is a good error handling architecture for Android apps?

senior architecture error-handling resilience
View Answer

Handle errors by layer and map them to domain/UI semantics.

Recommended approach:

  • classify technical vs business errors

  • normalize in repository/domain boundaries

  • expose user-actionable UI states

  • log structured diagnostics for operations

๐Ÿš€ See Full Deep Dive


How do retry strategies fit architecture decisions?

senior architecture retry resilience
View Answer

Retry policy should be explicit, bounded, and context-aware.

Common rules:

  • exponential backoff for transient failures

  • idempotency awareness for writes

  • user-driven retry for recoverable UI actions

  • circuit-breaker style guardrails for unstable backends

๐Ÿš€ See Full Deep Dive


How should complex UI state be modeled architecturally?

senior architecture ui-state state
View Answer

Use explicit immutable state models with clear sub-states.

Common shape:

  • loading/content/error/empty branches

  • data payload + UI metadata

  • separate ephemeral events

Prefer readability and deterministic transitions over cleverness.

๐Ÿš€ See Full Deep Dive


What are key principles of navigation architecture?

intermediate architecture navigation modularization
View Answer

Navigation should use explicit destination contracts and clear ownership.

Good practices:

  • central route definitions

  • pass IDs/contracts, not large mutable objects

  • keep navigation decisions near state owner

  • test back stack behavior for critical flows

๐Ÿš€ See Full Deep Dive


senior architecture deep-links navigation
View Answer

Treat deep links as stable external API contracts.

Architecture implications:

  • central validation and parsing

  • module-level routing boundaries

  • auth/feature-flag gating support

  • backward compatibility strategy

๐Ÿš€ See Full Deep Dive


How do you design Android architecture for high testability?

senior architecture testing testability
View Answer

Testability improves when dependencies and state transitions are explicit.

Design choices:

  • constructor-injected abstractions

  • pure use-case logic where possible

  • deterministic state reducers

  • contract tests at module boundaries

๐Ÿš€ See Full Deep Dive


How does architecture impact team scalability?

staff architecture scalability team
View Answer

Architecture defines ownership boundaries, release independence, and coordination cost.

Team-scale signals:

  • clear module ownership

  • low cross-team dependency hotspots

  • predictable integration contracts

  • standards for observability and quality gates

๐Ÿš€ See Full Deep Dive


What is architecture governance in large Android codebases?

staff architecture governance scalability
View Answer

Governance is how teams enforce architectural direction without blocking delivery.

Typical mechanisms:

  • module ownership model

  • ADRs and decision logs

  • lint/static checks for boundaries

  • review standards and architecture forums

๐Ÿš€ See Full Deep Dive


How should senior engineers discuss architecture tradeoffs in interviews?

senior architecture tradeoffs senior
View Answer

Frame tradeoffs by context, constraints, and measurable outcomes.

Strong answer structure:

  • what problem and constraints existed

  • options considered

  • decision and rationale

  • risks/mitigations

  • follow-up metrics and iteration

Avoid presenting architecture as one-size-fits-all.

๐Ÿš€ See Full Deep Dive


Compare DataStore vs SharedPreferences - consistency, migration, and threading model

intermediate android datastore sharedpreferences persistence
View Answer

DataStore replaces SharedPreferences with a fully asynchronous, coroutine-based API that uses atomic file operations to prevent partial writes and data corruption.

In interviews, cover:

  • SharedPreferences is synchronous in commit() (ANR risk on large writes) or fire-and-forget in apply() (crash on process kill before write completes); reads are synchronous and block the calling thread if the file hasn't been loaded

  • DataStore (Preferences DataStore) exposes Flow; all reads and writes are non-blocking coroutine operations on an IO-backed dispatcher; no more synchronous reads on the main thread

  • Atomic writes via an atomic rename (write to temp file then rename) prevent partial write corruption โ€” a process kill mid-write still yields the last valid file

  • Proto DataStore uses protobuf for typed key schema; Preferences DataStore uses untyped key objects; both live in a single-process single-file design (no cross-process access)

  • migration: ReplaceFileCorruptionHandler, SharedPreferencesMigration; migrate incrementally by creating DataStore with the old SP file name and letting it auto-import

Strong answer tip:

  • never mix SharedPreferences and DataStore on the same file path; DataStore acquires a FileLock and SP does not โ€” they will corrupt each other if both access the same file

๐Ÿš€ See Full Deep Dive


Explain Room + Flow invalidation - correctness problems and avoiding over-collection

intermediate android room database flow invalidation
View Answer

Room's Flow-based queries re-emit on every table write that affects the observed table, not just writes that change the result set โ€” this causes unnecessary recompositions when not handled correctly.

In interviews, cover:

  • Room Flow is backed by InvalidationTracker; any write to a table observed by a query triggers re-emission, even if the query result is identical โ€” this can cause high-frequency re-renders on write-heavy tables

  • fix: apply distinctUntilChanged() downstream to suppress equal consecutive emissions

  • collecting inside the ViewModel using stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()): shares the upstream database flow while there are active UI subscribers and caches the last value for 5 seconds after the last subscriber disconnects โ€” prevents restart on rotation

  • do NOT collect Room Flow in a simple LaunchedEffect without cancellation management; the flow continues emitting even when the composable leaves composition unless the scope is tied to the composable lifecycle

Strong answer tip:

  • benchmark with invalidation tracking disabled and enabled on a write-heavy table; the difference shows whether your architecture is over-collecting or correctly throttling

๐Ÿš€ See Full Deep Dive


Explain Room transactions, WAL mode, and concurrency correctness under load

intermediate android room database transactions wal concurrency
View Answer

Room uses SQLite under the hood; WAL mode allows concurrent reads while a write is in progress, but transaction boundaries and thread safety must still be managed explicitly.

In interviews, cover:

  • @Transaction on a @Dao method executes the body inside a single SQL transaction; required for multi-table writes that must be atomic (e.g. insert order + insert items in one atomic operation)

  • WAL (Write-Ahead Logging): readers do not block writers and writers do not block readers in WAL mode; Room enables WAL by default since version 2.4; improves throughput on read-heavy workloads

  • concurrency: Room queues writes on a single-threaded executor by default; multiple coroutines doing concurrent writes will serialize; for high write throughput, design batched inserts rather than many small single-row writes

  • never use @Transaction with very long-running operations (network calls, slow computations) โ€” this holds an exclusive write lock and starves reads

Strong answer tip:

  • test with Room's testing support: RoomDatabase.inMemoryDatabaseBuilder() combined with a custom QueryCallback to assert the SQL generated by your DAO matches expected index usage

๐Ÿš€ See Full Deep Dive


Explain sync engine design - idempotency, deduplication, and at-least-once semantics

advanced architecture sync offline idempotency
View Answer

A robust sync engine guarantees that every user action eventually reaches the server exactly once โ€” achieved through idempotent operations, at-least-once delivery with server-side deduplication.

In interviews, cover:

  • at-least-once delivery: the client retries until it receives a server acknowledgement; the server must deduplicate to prevent double application of the operation

  • idempotency key: each client-generated operation carries a UUID; the server stores processed IDs and rejects re-submissions without error (returns the original response)

  • outbox pattern: write operations go to a local outbox table first (atomic with the UI change); WorkManager drains the outbox; on 2xx response, delete the outbox row; on retryable error, backoff and retry; on permanent failure, tombstone the row and surface to UX

  • deduplication window: server must retain idempotency keys for at least the maximum expected retry window (typically 7โ€“30 days)

Strong answer tip:

  • ordering matters for operations that depend on each other (e.g. create comment requires post to exist first); tag operations with a dependency chain and ensure the drainer respects it

๐Ÿš€ See Full Deep Dive


Explain deletes and tombstones in offline sync - preventing resurrected data

intermediate architecture sync offline tombstones conflict-resolution
View Answer

In offline-first apps, deleting a record locally then syncing risks the delete being lost if another device re-syncs the same record after the delete โ€” tombstones prevent this resurrection.

In interviews, cover:

  • resurrection problem: client A deletes record; client B (offline) has the record; client B comes online and upserts the record โ€” without a tombstone, the record reappears on client A after next sync

  • tombstone: a deleted_at timestamp replaces the full delete; the sync layer treats records with deleted_at set as soft-deleted; all clients respect deleted_at and hide the record

  • garbage collection: tombstones must be retained for the maximum expected offline window (e.g. 30 days); after that, hard-delete the tombstone and the record permanently

  • conflict resolution: if both a delete and an update arrive for the same record, last-writer-wins is dangerous; prefer explicit policy โ€” e.g. update wins over delete (data preservation) or delete wins over update (GDPR compliance)

Strong answer tip:

  • for GDPR right-to-erasure compliance, hard deletion must be certain; log the deletion event, replicate it to all downstream stores, and verify through compliance audit that no copies remain in backups or caches

๐Ÿš€ See Full Deep Dive