What Is Jetpack Compose and Why Android Moved to It
Basics3 minInnovialabs editorial team
In short
Jetpack Compose is Android's modern declarative UI toolkit in Kotlin: you describe how a screen looks for a given state, and the system redraws only the parts that changed.
What Jetpack Compose is
Jetpack Compose is Google's toolkit for building Android app interfaces in Kotlin. Instead of XML layouts and manually updating Views, you write functions that describe the UI from the current state. When the state changes, Compose updates the right parts of the screen for you.
Google promotes Compose as the recommended way to build UI for new Android apps, and new Material design system features land there first.
Imperative vs declarative
In the classic approach, a screen is described in XML, and code finds elements and changes them by hand: textView.setText(...), button.setVisibility(...). The more complex the screen, the easier it is to forget an update and end up out of sync.
In Compose, the UI is a function of state:
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Clicked: $count")
}
}
There is no View lookup and no manual text update. You change count, and Compose redraws the button.
| XML + Views | Jetpack Compose | |
|---|---|---|
| Where the UI lives | XML files and code | Kotlin only |
| Screen updates | Manual | Automatic from state |
| Lists | RecyclerView + Adapter | LazyColumn / LazyRow |
| Reuse | Custom Views, include | Plain functions |
| Preview | Layout Editor | @Preview in code |
Key concepts
- Composable function — a function annotated with
@Composablethat describes a piece of UI. Screens are assembled from small functions like building blocks. - State — the data the screen depends on. Compose tracks state reads and knows which parts depend on it.
- Recomposition — re-running composable functions when their state changes. Compose tries to re-run only the functions that read the changed data.
- remember — keeps a value across recompositions so it is not reset on every redraw.
- State hoisting — moving state up into a ViewModel or parent function and keeping components "dumb": they receive data and report events.
Interop with legacy screens
Compose does not require rewriting the whole app. There are two bridges:
- ComposeView — puts Compose UI inside an existing XML screen or fragment.
- AndroidView — embeds a classic View (a map, an old custom component) inside Compose.
This makes migration gradual: new screens are written in Compose, old ones are converted when their turn comes.
What it means for your project
New project. It is reasonable to start with Compose right away: less code, faster iterations with designers, easier to keep a consistent style. Developers with Compose experience are increasingly easy to find.
Existing XML project. Rewriting everything at once is usually not worth it. A working strategy:
- Add Compose to the project and set up a shared theme.
- Build new screens and features in Compose.
- Convert old screens when they need significant changes anyway.
- Complex, stable screens can stay in XML for a long time.
Common mistakes
- Heavy computation inside composables. They can run often; move work to a ViewModel or wrap it in
remember. - State in every component. Without hoisting, the screen is hard to test and debug.
- Ignoring data stability. Unstable types can trigger extra recompositions; Android Studio tooling shows this.
- Migrating for the sake of it. Rewriting a working screen without a business reason costs time and adds risk.