WhollySoftware
Back to blogMobile

Jetpack Compose in Production: What Changed Since Our First Android App

Wholly Software TeamMarch 11, 20256 min read
Jetpack Compose in Production: What Changed Since Our First Android App

The first production app we shipped with Jetpack Compose had a list screen that recomposed on every scroll frame because we were passing a mutable list straight into LazyColumn without a stable key. It worked, but it janked on mid-range devices, and we spent two days profiling before realizing the fix was as simple as switching to an immutable data class with a proper key lambda.

Since then, the biggest shift has been how much less we fight the recomposition system. Compose compiler reports, which barely existed when we started, are now a standard part of our CI pipeline. We flag any composable marked 'unstable' or 'restartable but not skippable' before it ships, which has cut our recomposition-related bug reports by roughly half across the four apps we've moved fully off XML layouts.

State hoisting used to be a debate on every code review. Now we default to a strict rule: ViewModels expose a single StateFlow of a UI state data class, composables are stateless below the screen level, and any local UI-only state (like a text field's cursor position) stays in rememberSaveable. This isn't novel advice, but enforcing it consistently across a team of six Android engineers took real discipline and a lint rule we wrote ourselves.

Interop with existing UIKit-style View-based code was our biggest early pain point. AndroidView wrappers around legacy custom views caused measurement bugs that took weeks to track down on one banking app migration. Compose's interop APIs are noticeably more stable now, but we still budget extra time whenever a project has more than a handful of legacy custom views to bridge.

Performance-wise, baseline profiles made the single biggest difference we've measured. Adding a baseline profile to one client's app cut cold-start jank by about 30% without touching a line of business logic. We now generate one as a standard step before every Play Store release, not just for flagship apps.

We wouldn't go back to XML layouts for new Android work at this point. The tooling gaps that made 2022 painful — unstable previews, sparse debugging tools, compiler report immaturity — have mostly closed. What's left is normal engineering discipline: know your stability annotations, profile before you guess, and hoist state deliberately.

AndroidJetpack ComposePerformanceMobile Architecture
Jetpack Compose in Production: What Changed Since Our First Android App — Wholly Software