PostShare
AndroidFebruary 15, 2026·9 min

Android Architecture in 2026: What We Ship at Scale

RC

Rashad Cureton

Founder, Cure Consulting Group

Android Architecture in 2026: What We Ship at Scale
Back to Blog

The Android Stack Has Matured — Your Architecture Should Too

Five years ago, Android architecture meant picking between MVP and MVVM and fighting with Fragment lifecycles. In 2026, the platform has converged around a clear set of opinions:

  • Jetpack Compose for UI (XML layouts are legacy now)
  • Kotlin Coroutines + Flow for async and reactive data
  • Hilt for dependency injection
  • Room for local persistence
  • Retrofit + kotlinx.serialization for networking

But having the right libraries isn't architecture. Architecture is how you organize code so that a team of 5-15 engineers can ship features without stepping on each other.

The Architecture We Ship

After building the Ford Connected Vehicle Platform and multiple enterprise Android apps, we've converged on a layered architecture that balances purity with pragmatism:

Layer 1: UI (Compose)

  • Screens are stateless composables that receive state and emit events
  • ViewModels hold UI state as StateFlow — never expose LiveData in new code
  • UI state is a single sealed class per screen — no scattered mutable fields
  • Navigation uses type-safe routes with compose-navigation 2.8+
kotlin
// UI State as a single sealed hierarchy
sealed interface DashboardState {
    data object Loading : DashboardState
    data class Success(
        val metrics: List<Metric>,
        val lastSync: Instant
    ) : DashboardState
    data class Error(val message: String) : DashboardState
}

Layer 2: Domain

  • Use cases encapsulate single business operations
  • Each use case has one public methodoperator fun invoke()
  • Use cases can depend on other use cases but never on Android framework classes
  • This layer has zero Android imports — it's pure Kotlin

Layer 3: Data

  • Repositories are the single source of truth
  • Offline-first by default: Room is the primary data source, network is a sync mechanism
  • Repository pattern abstracts data sources so the domain layer doesn't know (or care) where data comes from

Offline-First Isn't Optional Anymore

In connected vehicle systems, we learned this the hard way: cellular connections in parking garages, tunnels, and rural areas are unreliable. Your app needs to work without the network.

The pattern:

  • Room database is the source of truth for all displayed data
  • WorkManager handles background sync — retry policies, constraints, and exponential backoff
  • Conflict resolution uses last-writer-wins with server timestamps for simple models, CRDTs for collaborative data
  • Sync status is exposed in the UI — users should always know if they're seeing fresh or cached data
kotlin

Get insights like this in your inbox

Practical tips on AI, mobile & cloud — no spam.

// Repository with offline-first pattern
class VehicleRepository(
    private val dao: VehicleDao,
    private val api: VehicleApi,
    private val syncManager: SyncManager
) {
    fun getVehicles(): Flow<List<Vehicle>> = dao.observeAll()
    
    suspend fun refresh() {
        val remote = api.fetchVehicles()
        dao.upsertAll(remote.map { it.toEntity() })
        syncManager.markSynced("vehicles")
    }
}

Compose Performance: The Things Nobody Tells You

Compose is powerful, but it has performance traps that bite at scale:

  • Stability matters. If your data classes aren't stable (containing List, Map, or mutable fields), Compose will recompose unnecessarily. Use @Immutable or @Stable annotations deliberately.
  • LazyColumn is not RecyclerView. It doesn't recycle views — it recomposes. For lists over 500 items, you need to think about key parameters and content type optimization.
  • State hoisting isn't free. Hoisting state too high causes unnecessary recompositions of parent composables. Use derivedStateOf for computed values.
  • Image loading needs care. Coil 3's AsyncImage with proper ContentScale and placeholder handling is the standard. Pre-size images server-side when possible.

Testing Strategy

Our testing pyramid for Android:

  • Unit tests (70%): Domain layer use cases, repository logic, ViewModel state machines. All use cases are tested with fake repositories — not mocks.
  • Integration tests (20%): Room database operations, API serialization (using MockWebServer), WorkManager chains.
  • UI tests (10%): Critical user flows only — login, checkout, core feature paths. Use Compose testing APIs, not Espresso.

The key insight: ViewModels become trivially testable when they depend on use cases (pure Kotlin) instead of repositories directly. Your ViewModel test becomes: "given this use case returns X, assert the state is Y."

Shipping Reliably

At Ford, we shipped to devices with Android 8 through 14, across hundreds of hardware variants. Here's what keeps your release pipeline sane:

  • Feature flags for every new feature — Firebase Remote Config or your own
  • Staged rollouts — 1% → 10% → 50% → 100%, with crash rate monitoring between each stage
  • Baseline profiles — pre-compile critical paths for faster cold starts
  • R8 full mode — aggressive code shrinking and optimization
  • App Bundle — not APK, for optimal download sizes per device

When to Go Native vs. Cross-Platform

We're frequently asked about Flutter or KMP. Our answer:

Go native when:

  • You need deep platform integration (camera pipelines, Bluetooth LE, background services)
  • Performance is non-negotiable (financial transactions, real-time data)
  • Your team already knows Kotlin

Consider KMP when:

  • You have both iOS and Android targets with significant shared business logic
  • Your shared logic is data transformation, networking, and business rules — not UI
  • You can accept a 3-6 month learning curve for the team

We rarely recommend Flutter for enterprise apps. The abstraction layer creates debugging complexity that becomes expensive at scale.


Building an Android app that needs to work at scale? Book a free architecture review — we've shipped Android to millions of devices and know where the pitfalls are.

AndroidKotlinJetpack ComposeArchitectureMobile
RC

Written by

Rashad Cureton

Founder & Principal Engineer

Rashad is the founder of Cure Consulting Group. Previously an engineer at JP Morgan, Ford, Clear, NYT, Kickstarter, and Big Nerd Ranch. He builds full-stack web and mobile apps for startups and companies of every size.

Found this useful?

Book a free 30-minute architecture review to discuss your project.

Book a Review

Related Articles