All articles

Jetpack Compose vs XML Views: How to Migrate an Android App

Why Android teams are moving from XML layouts to Jetpack Compose, what changes in the way you think about UI, how to migrate an existing app screen by screen, and the state, performance, and testing habits that make Compose work well.

Mobile Development|Published |9 min read
Terminal output from installing Android SDK packages

For more than a decade, Android screens were built from XML layouts and Views updated by hand from Kotlin or Java. Jetpack Compose replaces that with UI written as Kotlin functions that describe what the screen should look like for a given state. Google recommends Compose for new Android UI, and most new libraries and samples assume it. For teams with an existing app, the real question is how to move without stopping feature work. Here is what changes and how to migrate safely.

What Changes With Compose

TopicXML ViewsJetpack Compose
Defining UIXML layout files inflated into View objectsKotlin functions annotated with @Composable
Updating UIFind the view and call setText, setVisibility, and similar methodsChange the state, and Compose redraws the affected parts
ListsRecyclerView with an adapter and ViewHolderLazyColumn and LazyRow with a few lines of code
ThemingStyles and themes in XML resourcesMaterialTheme with colours, typography, and shapes in Kotlin
PreviewsLayout editor, limited for dynamic content@Preview functions with sample data, several states side by side

The biggest shift is mental. In the View system you change the UI step by step. In Compose you describe the UI for the current state, and a whole class of bugs disappears, such as a loading spinner that stays visible because one code path forgot to hide it.

Should You Migrate?

  • New screens are the easiest win. Building them in Compose costs nothing extra and the team learns on real work.
  • Screens that change often, with complex lists or many states, benefit most from a rewrite.
  • Stable screens that nobody touches can stay in XML for a long time. Interop is well supported.
  • Custom Views with heavy drawing code are the last to move, and can be wrapped in AndroidView inside Compose in the meantime.

Migrate Screen by Screen

  1. 1Add the Compose dependencies through the Compose BOM, which keeps library versions compatible, and enable the Compose compiler plugin that ships with Kotlin 2.0 and later.
  2. 2Create a MaterialTheme that matches your current colours and fonts, so Compose screens look the same as XML ones.
  3. 3Build reusable components first, such as buttons, text fields, and list items, as a small design system.
  4. 4Write new screens in Compose. Host them with ComposeView inside an existing Fragment or with setContent in an Activity.
  5. 5Move a ViewModel-backed screen by keeping the ViewModel and replacing only the layout, then collecting its StateFlow with collectAsStateWithLifecycle.
  6. 6Once most screens are migrated, consider Navigation Compose to replace Fragment-based navigation.

Handle State the Compose Way

Keep screen state in a ViewModel that exposes one UI state object through StateFlow, and pass plain data and event callbacks down to composables. This is called state hoisting. A composable that receives its data as parameters is easy to preview with sample data and easy to test. Use remember for small UI details such as whether a menu is expanded, and rememberSaveable for values that must survive rotation, like text being typed.

Performance Habits

  • Judge performance in release builds only. Debug builds of Compose are much slower and give a false picture.
  • Add Baseline Profiles so key code paths are compiled ahead of time, which improves startup and scrolling.
  • Give items in LazyColumn a stable key so Compose can reuse them correctly when the list changes.
  • Avoid expensive work directly in composables. Compute it in the ViewModel or wrap it in remember with the right keys.
  • Use the Layout Inspector to see recomposition counts and find composables that redraw too often.

Testing

Compose UI tests use semantics, the same information accessibility services read. createComposeRule lets you set content, find nodes by text or test tag, perform clicks, and assert what is shown. Because composables take state as parameters, many tests can render one screen in each state without starting the whole app. Screenshot tests based on previews are a good addition for catching visual regressions.

The safest migration is the one that never stops feature work. Build new things in Compose and move old screens when you would touch them anyway.

Our Android Kotlin training teaches Compose from the start, including interop with existing XML screens, so teams with older apps can apply it to their own codebase in the first week.

Key takeaways

  • Compose describes UI as a function of state, which removes many bugs caused by updating Views by hand.
  • Start with new screens and frequently changed screens, and leave stable ones in XML until there is a reason to move them.
  • Use the Compose BOM, a shared MaterialTheme, and reusable components before migrating screens.
  • Hoist state into a ViewModel and pass data and callbacks down to composables.
  • Measure performance in release builds, add Baseline Profiles, and give list items stable keys.

Related articles

More articles on software development, AI, cloud, and infrastructure.

Hands sorting printed tax forms and receipts next to a calculator
AI Development|

Automating Document Data Entry With AI: Invoices, Receipts, and Forms

How AI reads invoices, receipts, ID cards, and forms and turns them into structured data, how OCR and large language models fit together, why validation and human review still matter, how to measure accuracy, and what to watch for with personal data.

Aerial view of a busy container port with cranes and stacked shipping containers
DevOps|

Deploying Applications to Kubernetes With Helm: A Practical Guide

What Helm charts are, how values and templates work, how to structure a chart for several environments, upgrade and rollback safely, keep secrets out of Git, test charts in CI, and decide between Helm and Kustomize.

Looking for a software development partner?

Tell us about your project, what you need to build, and the challenges you are facing. We can discuss the technical approach, scope, timeline, and estimated cost.

Start a conversation