Jetpack Compose Intro

Android Development โ€” Architecture & Data
Course 2 ยท Chapter 1 ยท Jetpack Compose Intro

๐Ÿ–Œ๏ธ Jetpack Compose Intro

Course 1 built UI the traditional way: XML layouts plus imperative Kotlin code that finds Views and mutates them. Jetpack Compose replaces both halves of that with a single idea โ€” UI described entirely as Kotlin functions, automatically redrawn when the data behind them changes. This chapter covers composables, state, recomposition, and how the mental model actually differs from everything in Course 1.

๐Ÿงฑ Composable Functions

@Composable fun Greeting(name: String) { Text(text = "Hello, $name!") }

A @Composable function describes a piece of UI โ€” calling Text(...) doesn't create and configure a View object the way binding.textView.text = "..." did in Course 1; it declares "there should be text here, with this content." Composables are Kotlin functions in every technical sense โ€” they take parameters, can call other composables, and can be as small or as large as any function โ€” but by convention they're named with a capital letter, like a class, to visually mark them as UI-producing.

@Composable fun ProfileCard(name: String, title: String) { Column(modifier = Modifier.padding(16.dp)) { Text(text = name, fontSize = 20.sp) Text(text = title, color = Color.Gray) } }

Column and Row are Compose's layout composables โ€” the direct replacements for Course 1's LinearLayout (vertical/horizontal orientation), just as Kotlin function calls instead of XML tags. Modifier is Compose's mechanism for spacing, sizing, and other per-element styling โ€” the composable-world equivalent of an XML View's layout_* attributes, but chainable: Modifier.padding(16.dp).fillMaxWidth().

๐Ÿ”„ State & Recomposition โ€” The Core Idea

A composable function re-runs โ€” recomposes โ€” automatically whenever the state it reads changes, redrawing only what actually needs to change:

@Composable fun Counter() { var count by remember { mutableStateOf(0) } Column { Text(text = "Count: $count") Button(onClick = { count++ }) { Text("Increment") } } }

remember { mutableStateOf(0) } creates a piece of state that survives recomposition (though not, by default, an Activity being recreated โ€” that's rememberSaveable, a small variant covered later). by is Kotlin Intermediate Chapter 4's property delegation again โ€” mutableStateOf provides getValue/setValue, letting count be read and written like a plain var, while every read is secretly tracked by Compose.

โš  This Is the Whole Trick: Compose Tracks Reads, Not Writes

When count++ runs inside the button's onClick, Compose doesn't manually push a new value into the Text โ€” it re-runs (recomposes) exactly the composable functions that read count, because it tracked that read the last time they ran. Text(text = "Count: $count") reads count, so it recomposes; if Counter had other composables that never touched count, those would be skipped entirely โ€” an automatic, fine-grained optimization with no equivalent manual work required.

Compose vs XML/View System (Course 1)

XML + Views (Course 1)Jetpack Compose
UI defined inSeparate XML filesKotlin functions
Updating the UIbinding.textView.text = "..." (imperative mutation)Change state; recomposition updates the UI automatically
Finding a ViewfindViewById / view bindingN/A โ€” no View objects to "find"
ReusabilityA custom View class, or a <include> layoutJust a function โ€” call it anywhere

Compose vs React โ€” A Very Similar Shape

ReactJetpack Compose
Component unitA function componentA @Composable function
Local stateuseState()remember { mutableStateOf(...) }
Re-render triggerState change โ†’ re-renderState change โ†’ recomposition
OptimizationVirtual DOM diffingSkips composables whose inputs didn't change

If React (from the JavaScript courses) feels familiar, that's not a coincidence โ€” both are declarative, state-driven UI systems built around the same core insight: describe what the UI should look like given the current state, and let the framework figure out the minimal work to get there, rather than hand-writing the update steps yourself.

๐Ÿ‘๏ธ @Preview โ€” Seeing UI Without Running the App

A @Preview-annotated composable renders directly inside Android Studio's editor, without building, installing, or launching anything on an emulator:

@Preview(showBackground = true) @Composable fun ProfileCardPreview() { ProfileCard(name = "Philip", title = "Android Developer") }

This is a genuinely fast feedback loop compared to Course 1's edit-build-run cycle for checking a layout change โ€” a dedicated, no-argument preview function calling the real composable with sample data shows up right in the code editor's split view, updating live as the code changes.

๐Ÿ—๏ธ Wiring Compose Into an Activity

class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ProfileCard(name = "Philip", title = "Android Developer") } } }

Note two changes from Course 1: the base class is ComponentActivity, not AppCompatActivity, and setContent { } replaces setContentView(R.layout.activity_main) โ€” there's no XML layout file at all for a Compose screen. Everything else from Course 1's Activity lifecycle (Chapter 2) still applies unchanged; Compose is a different way of building the content of a screen, not a different kind of Activity.

๐Ÿ’ป Coding Challenges

Challenge 1: A Composable with Parameters

Write a composable fun ProductCard(name: String, price: Double) using a Column to display both values as separate Text elements, and a @Preview function calling it with sample data. Wire it into MainActivity via setContent { }.

Goal: Practice a basic parameterized composable and the Preview workflow.

โ†’ Solution

Challenge 2: State and Recomposition

Write a composable Counter() with a remembered mutableStateOf Int starting at 0, a Text showing the current value, and two Buttons ("+" and "-") that increment/decrement it. Confirm the displayed count updates correctly when either button is tapped.

Goal: Practice remember/mutableStateOf and see recomposition happen for real.

โ†’ Solution

Challenge 3: Composing Composables Together

Using Challenge 1's ProductCard, write a composable ProductList() that calls ProductCard three times (with different sample data) inside a Column, separated by some vertical spacing (Modifier or a Spacer). Add a @Preview for ProductList.

Goal: Practice composing smaller composables into a larger screen, the way small functions combine into larger ones.

โ†’ Solution

๐Ÿ’ก Course 1's XML Skills Aren't Wasted

Many real, existing Android codebases still use the View system from Course 1, and Compose screens frequently need to interoperate with legacy View-based code (via AndroidView or ComposeView) โ€” understanding both isn't redundant, it's genuinely necessary for working on real production Android apps today. This course focuses on Compose going forward because it's what new code is built with, not because Course 1 was a detour.

๐ŸŽฏ What's Next

Next chapter: ViewModel & State Management โ€” ViewModel lifecycle, LiveData, StateFlow, and UI state patterns.