Irbisa · Cheatsheet

Jetpack Compose Fundamentals

Composable functions, modifiers, layout, recomposition, Material 3

Junior Developer · 23 questions

  1. 01

    What is Jetpack Compose, and how is it different from the View system?

    Jetpack Compose is Android's declarative UI toolkit: you write @Composable Kotlin functions that describe the UI for the current state, and Compose calls them again when that state changes.

    @Composablefun Greeting(name: String, onClick: () -> Unit) {  Column(Modifier.padding(16.dp)) {    Text("Hello, $name", style = MaterialTheme.typography.headlineSmall)    Button(onClick = onClick) { Text("Say hi") }  }…
  2. 02

    What is a composable function, and why can a @Composable function only be called from another composable?

    A composable is a Kotlin function marked @Composable that emits UI into the composition instead of returning it.

  3. 03

    What is recomposition, when does it happen, and how does Compose decide what to re-run?

    Recomposition is Compose calling composable functions again when state they read has changed, so the UI matches the new state.

  4. 04

    What is a Modifier in Compose, and why does the order of modifiers matter?

    A Modifier is an ordered, immutable chain of decorations (size, padding, background, click handling, semantics) applied to a composable.

    // Red covers only the inner area; the 16dp padding stays transparentText("A", Modifier.padding(16.dp).background(Color.Red)) // Red covers the padding as wellText("B", Modifier.background(Color.Red).padding(16.dp))…
  5. 05

    How do Row, Column and Box lay out their children, and how do you control spacing, alignment and weight?

    Column stacks children vertically, Row horizontally, and Box places them on top of each other.

    @Composablefun ProductRow(p: Product, modifier: Modifier = Modifier) {  Row(    modifier = modifier.fillMaxWidth().padding(12.dp),    verticalAlignment = Alignment.CenterVertically,    horizontalArrangement = Arrangement.spacedBy(12.dp),…
  6. 06

    What is the difference between LazyColumn and Column, and how does LazyColumn compare to RecyclerView?

    Column composes and measures every child at once, while LazyColumn composes only the items that are visible plus a few ahead.

    @Composablefun MessageList(messages: List<Message>, modifier: Modifier = Modifier) {  val state = rememberLazyListState()  LazyColumn(    modifier = modifier.fillMaxSize(),    state = state,…
  7. 07

    How do you write a reusable composable that lets the caller decide what goes inside it?

    Use a slot: a parameter of type @Composable () -> Unit that the component calls wherever the caller's content belongs.

    @Composablefun SettingRow(  title: String,  modifier: Modifier = Modifier,  leading: (@Composable () -> Unit)? = null,       // optional slot  trailing: @Composable RowScope.() -> Unit = {},  // scoped slot…
  8. 08

    How does theming work with Material 3 in Compose?

    A Material 3 theme is one composable, MaterialTheme, that holds a color scheme, typography and shapes; every Material component below it reads them through MaterialTheme.colorScheme, .typography and .shapes.

    private val LightColors = lightColorScheme(primary = Color(0xFF1565C0), onPrimary = Color.White)private val DarkColors = darkColorScheme(primary = Color(0xFF90CAF9), onPrimary = Color(0xFF003258)) @Composablefun AppTheme(  dark: Boolean = isSystemInDarkTheme(),…
  9. 09

    What is Scaffold, which slots does it offer, and why does showing a snackbar need a coroutine?

    Scaffold lays out a Material 3 screen with named slots (topBar, bottomBar, floatingActionButton, snackbarHost) and passes the remaining content area as PaddingValues.

    @Composablefun InboxScreen(messages: List<Message>, onArchive: (Message) -> Unit) {  val hostState = remember { SnackbarHostState() }  val scope = rememberCoroutineScope()   Scaffold(…
  10. 10

    How do you build a login form in Compose: TextField state, KeyboardOptions, the IME action, and moving focus to the next field?

    Each field is an OutlinedTextField whose text lives in state you own.

    @Composablefun LoginForm(onSubmit: (email: String, password: String) -> Unit) {  var email by rememberSaveable { mutableStateOf("") }  var password by rememberSaveable { mutableStateOf("") }  val focusManager = LocalFocusManager.current  val submit = {…
  11. 11

    How do @Preview functions work, and how do you keep a screen previewable?

    A @Preview is a composable that Android Studio renders without running the app: no Activity, no ViewModel, no DI graph.

    @Composablefun HomeRoute(viewModel: HomeViewModel = hiltViewModel()) {  val state by viewModel.state.collectAsStateWithLifecycle()  HomeScreen(state = state, onRefresh = viewModel::refresh)}…
  12. 12

    Would you build a new feature in Compose or in XML, and what are Compose's real limitations in production?

    For a new feature in 2026 Compose is the default: less code, UI driven by state, and Google ships new UI APIs (Material 3, adaptive layouts) for Compose first.

  13. 13

    What are the three phases of a Compose frame (composition, layout, drawing), and why can a state change skip composition entirely?

    A frame runs up to three phases in order: composition decides what to show, layout measures and places each node, and drawing paints it.

    // read in composition: every animation frame recomposes DotSlow before it is redrawn@Composablefun DotSlow(selected: Boolean) {  val color by animateColorAsState(if (selected) Color.Red else Color.Gray, label = "dot")  Box(Modifier.size(24.dp).background(color))}…
  14. 14

    Each Box below differs only in its modifier chain. How big is each one, and how much of it is coloured?

    Column {  // A  Box(Modifier.size(100.dp).size(50.dp).background(Color.Red))  // B  Box(Modifier.size(50.dp).padding(10.dp).background(Color.Green))  // C  Box(Modifier.padding(10.dp).size(50.dp).background(Color.Blue))  // D  Box(    Modifier.width(200.dp).requiredWidth(80.dp)      .height(40.dp).background(Color.Gray)  )}

    A is 100×100 dp all red; B is 50×50 with a 30×30 green centre; C is 70×70 with a 50×50 blue square inset by 10 dp; D takes a 200 dp wide slot with an 80×40 grey box centred in it.

  15. 15

    Find the bug: a user expands one message, a new message arrives at the top, and now a different message is shown expanded.

    @Composablefun InboxList(messages: List<Message>, onOpen: (Message) -> Unit) {  LazyColumn {    items(messages) { message ->      var expanded by remember { mutableStateOf(false) }      MessageRow(        message = message,        expanded = expanded,        onToggle = { expanded = !expanded },        onOpen = { onOpen(message) },      )    }  }}

    items(messages) has no key, so each row's remember state is tied to its position, not to the message.

  16. 16

    What is the lifecycle of a composable, and how do you react to the Activity's lifecycle events from Compose?

    A composable enters the composition, recomposes zero or more times, and leaves it.

    @Composablefun MapScreen(viewModel: MapViewModel) {  // Stops collecting when the app goes below STARTED  val state by viewModel.state.collectAsStateWithLifecycle()   // Start on ON_START, stop on ON_STOP or when leaving the composition…
  17. 17

    Find the bug: backend logs show this screen still calling the scores API every 10 seconds after users press Home.

    @Composablefun LiveScoresScreen(viewModel: ScoresViewModel) {  val scores by viewModel.scores.collectAsStateWithLifecycle()   LaunchedEffect(Unit) {    while (true) {      viewModel.refresh()      delay(10.seconds)    }  }   ScoreList(scores)}

    LaunchedEffect is tied to the composition, not to the Activity's lifecycle.

  18. 18

    How do you handle edge-to-edge and window insets in Compose, and what changed for apps targeting Android 15 and 16?

    Apps targeting Android 15 (API 35) are drawn edge to edge, so content sits under the status and navigation bars until you apply window insets, through Scaffold's innerPadding or inset modifiers such as safeDrawingPadding().

    class MainActivity : ComponentActivity() {  override fun onCreate(savedInstanceState: Bundle?) {    enableEdgeToEdge()    super.onCreate(savedInstanceState)    setContent { AppTheme { InboxRoute() } }  }…
  19. 19

    How do you adapt a Compose screen to tablets, foldables and resizable windows, and what does Android 16 change for apps that lock orientation?

    Branch on the window size class, not on the device: read currentWindowAdaptiveInfoV2().windowSizeClass and switch layouts at the 600 dp and 840 dp width breakpoints.

    @Composablefun MailApp(tabs: List<Tab>, mails: List<Mail>) {  var current by rememberSaveable { mutableIntStateOf(0) }  val listState = rememberLazyListState()   // above the branch: an unfold keeps the scroll  val wide = currentWindowAdaptiveInfoV2().windowSizeClass    .isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND)…
  20. 20

    How does Navigation Compose work, and how do you pass arguments between screens?

    Navigation Compose keeps a back stack of composable destinations inside a NavHost, driven by a NavController.

    @Serializable data object Home@Serializable data class Profile(val id: Long) @Composablefun AppNavHost() {  val navController = rememberNavController()…
  21. 21

    How do you show an Android View inside Compose, and a composable inside an existing XML screen?

    AndroidView hosts a View inside a composable, and ComposeView hosts composables inside a View hierarchy.

    @Composablefun WebPage(url: String, modifier: Modifier = Modifier) {  AndroidView(    modifier = modifier,    factory = { context -> WebView(context) },   // runs once    update = { view -> view.loadUrl(url) },      // re-runs when url changes…
  22. 22

    What is the semantics tree in Compose, and how do accessibility services and UI tests use it?

    Compose builds a semantics tree next to the UI tree that describes what each element means: text, role, state, available actions.

    @Composablefun ProductRow(p: Product, onOpen: () -> Unit) {  Row(    Modifier      .clickable(onClick = onOpen)          // one node with a click action      .testTag("product-${p.id}")…
  23. 23

    Row, Column and Box cannot express the layout you need. How do you write your own, and what rule must you respect?

    The Layout composable gives you the children as measurables plus the incoming constraints; you measure each child, choose your own size and place the children.

    @Composablefun TwoColumnGrid(modifier: Modifier = Modifier, content: @Composable () -> Unit) {  Layout(content = content, modifier = modifier) { measurables, constraints ->    val columnWidth = constraints.maxWidth / 2    val childConstraints = constraints.copy(minWidth = 0, maxWidth = columnWidth)    val placeables = measurables.map { it.measure(childConstraints) }   // once each…