What Is Jetpack Compose?
Jetpack Compose is Google's modern toolkit for building native Android UI. Instead of writing XML layout files and imperatively mutating widget objects, you write Kotlin functions annotated with @Composable that describe what the UI should look like for a given piece of state. When that state changes, Compose automatically re-executes ('recomposes') only the functions whose inputs changed, and efficiently updates the underlying UI. This declarative model — inspired by React and Flutter — dramatically reduces the boilerplate and bug surface of manually keeping UI in sync with data.
Cricket analogy: Compose describing UI for a given state is like a scoreboard operator who doesn't manually flip each digit but instead states 'display the current score,' and the board automatically recomposes itself the instant a run is added, rather than someone chasing every widget by hand.
Declarative vs. Imperative UI
In the imperative View system, you write code like textView.text = user.name every time the underlying data changes — and it's easy to forget one of these updates, leaving the UI stale. In Compose, you instead write a function that reads user.name directly: Text(text = user.name). Compose observes the state the function reads, and when that state changes, it automatically re-invokes the function to produce updated UI. You never manually push updates to widgets; you just describe the current truth.
Cricket analogy: The old imperative View system is like a scorer manually rubbing out and rewriting the total on a chalkboard after every run, risking a forgotten update after a quick single, whereas Compose is like a digital board that just reads 'display current total' and updates itself automatically whenever the total changes.
Compose Compiler and Runtime
Compose is powered by a Kotlin compiler plugin that transforms composable functions to track which state they read, and a runtime that manages a tree of UI nodes (the 'slot table') to perform efficient recomposition. This is why @Composable functions have special rules: they can be called only from other composables, they may execute in any order or be skipped entirely, and they should avoid side effects unless wrapped in dedicated APIs like LaunchedEffect.
Cricket analogy: The slot table tracking recomposition is like a scoring app's internal ledger that only updates the specific batsman's tally that changed rather than recalculating the whole scorecard, and the rule that composables may be skipped is like an umpire not re-signaling a boundary that was already confirmed.
@Composable
fun GreetingCard(name: String, onGreetClick: () -> Unit) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = "Hello, $name!",
style = MaterialTheme.typography.headlineSmall
)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = onGreetClick) {
Text("Say hi back")
}
}
}Think of a composable function like a spreadsheet cell formula: it doesn't 'push' a value anywhere — it just recalculates automatically whenever an input cell it references changes. Compose's recomposition works the same way with state.
Why Google Built Compose
The View system accumulated over a decade of complexity: deeply nested XML, fragile fragment transactions, and constant manual synchronization between UI and state. Compose was designed alongside Kotlin's language features (lambdas, extension functions, coroutines) to make UI code more concise, testable, and less error-prone, while remaining fully interoperable with existing View-based code so teams can migrate incrementally.
Cricket analogy: The old View system's decade of accumulated complexity is like a stadium's tangled legacy wiring from decades of ad-hoc scoreboard upgrades, whereas Compose was designed alongside modern tools the way a new stadium is built with integrated digital systems from day one, while still letting the old manual scoreboard operate during the transition.
Composable functions can be recomposed in any order, multiple times, or skipped — so they must be idempotent and free of side effects like network calls or mutable variable writes outside of remember/state holders. Putting business logic directly in a composable body is a common and costly mistake.
- Compose is a declarative UI toolkit: functions describe UI as a function of state.
- Recomposition automatically re-runs only the composables affected by a state change.
- @Composable functions must be side-effect-free and can be skipped or reordered by the runtime.
- A Kotlin compiler plugin instruments composables to track state reads for efficient recomposition.
- Compose interoperates with the existing View system, enabling incremental migration.
- The mental model resembles spreadsheet formulas: outputs auto-update when inputs change.
Practice what you learned
1. What does it mean that Compose is a 'declarative' UI toolkit?
2. What triggers a recomposition in Jetpack Compose?
3. Why must @Composable functions avoid side effects in their body?
4. What component instruments composable functions to enable recomposition tracking?
5. Can Jetpack Compose UI coexist with legacy View-based UI in the same app?
Was this page helpful?
You May Also Like
What Is Android Development?
An overview of building apps for Android: the platform, the tools, and how modern Android development has shifted from imperative XML layouts to declarative Kotlin UI.
Composable Functions Basics
Composable functions are the fundamental building block of Jetpack Compose UI — Kotlin functions marked @Composable that emit UI elements and can be freely composed together.
State and remember
Understand how Compose tracks mutable values across recompositions using the remember function, and why state that isn't remembered gets lost.
mutableStateOf and Recomposition
Dive into how mutableStateOf creates observable state that triggers recomposition, and how Compose determines which composables need to redraw.