Skip to content
AgileLogics
7 min read

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 @Composable that emits UI. It returns nothing — it describes what to show.
  • Column stacks children vertically; Row horizontally; Box layers them.
  • Modifiers (padding, fillMaxWidth, clickable...) decorate a composable. Accept a modifier parameter so callers can adjust your component's layout.
  • rememberSaveable { mutableIntStateOf(0) } stores state that survives recomposition and screen rotation. Changing count makes Compose recompose — re-run — the functions that read it.
  • @Preview renders 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.