Android with Jetpack Compose
Prerequisites: Lambdas and higher-order functions, Sealed classes and interfaces
Jetpack Compose is Android's modern toolkit for building user interfaces, written entirely in Kotlin. It's declarative: you describe what the UI should look like for the current state, and Compose updates the screen when the state changes.
Create a project in Android Studio with the Empty Activity template — it's set up for Compose.
Composable functions
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Composable
fun Counter(modifier: Modifier = Modifier) {
var count by rememberSaveable { mutableIntStateOf(0) }
Column(modifier = modifier.padding(16.dp)) {
Text("Count: $count", style = MaterialTheme.typography.headlineMedium)
Button(onClick = { count++ }) {
Text("Add one")
}
}
}
@Preview(showBackground = true)
@Composable
fun CounterPreview() {
Counter()
}
- A composable is a function marked
@Composablethat emits UI. It returns nothing — it describes what to show. Columnstacks children vertically;Rowhorizontally;Boxlayers them.- Modifiers (
padding,fillMaxWidth,clickable...) decorate a composable. Accept amodifierparameter so callers can adjust your component's layout. rememberSaveable { mutableIntStateOf(0) }stores state that survives recomposition and screen rotation. Changingcountmakes Compose recompose — re-run — the functions that read it.@Previewrenders the composable in Android Studio's design pane.
Notice that everything here is plain Kotlin: trailing lambdas for
content, default arguments, and delegated properties (by).
Lists
@Composable
fun LanguageList(languages: List<String>, onSelect: (String) -> Unit) {
LazyColumn {
items(languages) { language ->
Text(
text = language,
modifier = Modifier
.fillMaxWidth()
.clickable { onSelect(language) }
.padding(16.dp),
)
}
}
}
LazyColumn only composes the rows currently on screen, so it handles
long lists efficiently.
State hoisting
Notice that LanguageList doesn't store the selection itself — it
receives data and reports events through onSelect. Moving state up to
the caller is called state hoisting. It makes composables reusable,
easy to preview, and easy to test; the next lesson shows where that state
ultimately lives.
Accessibility
Material components support TalkBack, font scaling, and dark theme. Add
contentDescription to icons and images, and keep touch targets at
least 48dp.