iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Jetpack Compose

Jetpack Compose is the modern Android UI toolkit: declarative, Kotlin-only, replacing XML layouts. Functions annotated @Composable describe UI as a function of state, and the compiler-plugin tracks which composables to re-execute when state changes. Pair it with ViewModel and Kotlin Flows for clean, testable screens.

A Compose screen with state, ViewModel, animations, and lazy lists

EXAMPLE
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

// 1) Plain @Composable — no inheritance, no lifecycle, just functions
@Composable
fun Counter(label: String) {
    var n by remember { mutableIntStateOf(0) }
    Column(Modifier.padding(16.dp)) {
        Text("$label: $n", style = MaterialTheme.typography.headlineSmall)
        Spacer(Modifier.height(8.dp))
        Row {
            Button(onClick = { n-- }) { Text("-") }
            Spacer(Modifier.width(8.dp))
            Button(onClick = { n++ }) { Text("+") }
        }
    }
}

// 2) Hoist state to a ViewModel for survival across configuration changes
data class UiState(val orders: List<String> = emptyList(), val loading: Boolean = false)

class OrdersViewModel : ViewModel() {
    private val _ui = MutableStateFlow(UiState())
    val ui: StateFlow<UiState> = _ui

    suspend fun refresh() {
        _ui.value = _ui.value.copy(loading = true)
        delay(400)
        _ui.value = UiState(orders = List(20) { "Order ${it + 1}" }, loading = false)
    }
}

// 3) Screen pieces compose by being called — no XML, no findViewById
@Composable
fun OrdersScreen(vm: OrdersViewModel = viewModel()) {
    val state by vm.ui.collectAsState()

    // Side effect: run once on first composition
    LaunchedEffect(Unit) { vm.refresh() }

    Scaffold(topBar = {
        TopAppBar(title = { Text("Orders") }, actions = {
            IconButton(onClick = {
                // Use rememberCoroutineScope() for user-triggered suspend calls
            }) { Text("↻") }
        })
    }) { padding ->
        AnimatedVisibility(visible = state.loading,
            enter = fadeIn(), exit = fadeOut(tween(200))) {
            LinearProgressIndicator(Modifier.fillMaxWidth())
        }

        LazyColumn(
            contentPadding = padding,
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            items(state.orders, key = { it }) { order ->
                ElevatedCard(Modifier.fillMaxWidth().padding(horizontal = 16.dp)) {
                    Text(order, Modifier.padding(16.dp))
                }
            }
        }
    }
}

// 4) Preview — render in Android Studio without an emulator
@Preview
@Composable
fun OrdersPreview() {
    MaterialTheme { OrdersScreen() }
}

// 5) Activity hosts the Compose root
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: android.os.Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { MaterialTheme { OrdersScreen() } }
    }
}

Why it matters

Use LazyColumn for any list past about 30 items. It only composes the rows currently on screen, so scrolling stays smooth and memory stays flat regardless of list size — the same property RecyclerView used to give you, but without the adapter/holder boilerplate.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
@Composable
fun Counter() {
    var n by remember { mutableStateOf(0) }
    Button(onClick = { n++ }) { Text("Count: $n") }
}
Try it Yourself »

Exercise

Mark a Composable function.

fun Greeting() { Text("hi") }

Discussion

Loading…