Introduction
Jetpack Compose is revolutionizing Android interface development by replacing XML with declarative Kotlin code. This approach enables better maintainability, smooth animations, and intuitive state management. In 2026, mastering Compose is essential for any Android developer looking to deliver high-performance and modern applications. This intermediate tutorial guides you through creating a complete application with state, optimized lists, and navigation.
Prerequisites
- Android Studio Hedgehog or higher
- Basic knowledge of Kotlin
- Gradle 8+ and Kotlin 1.9+
- An Android emulator or physical device
Project Configuration
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
dependencies {
implementation("androidx.compose.ui:ui:1.7.0")
implementation("androidx.compose.material3:material3:1.3.0")
implementation("androidx.navigation:navigation-compose:2.8.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0")
}Add the Compose and Navigation dependencies in the module's build.gradle. Make sure to enable Compose support in the buildFeatures options.
Simple First Composable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun GreetingScreen(name: String) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(
text = "Bonjour $name !",
style = MaterialTheme.typography.headlineMedium
)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { /* Action */ }) {
Text("Cliquez ici")
}
}
}This Composable displays text and a button. Use Column to stack elements vertically and apply modifiers for styling.
State Management with remember
import androidx.compose.runtime.*
import androidx.compose.material3.*
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Column {
Text("Compteur : $count")
Button(onClick = { count++ }) {
Text("Incrémenter")
}
}
}remember and mutableStateOf preserve state across recompositions. Avoid simple local variables that lose their value.
Performant List with LazyColumn
import androidx.compose.foundation.lazy.*
import androidx.compose.material3.*
@Composable
fun ItemListScreen(items: List<String>) {
LazyColumn {
items(items) { item ->
ListItem(
headlineContent = { Text(item) }
)
}
}
}LazyColumn recycles displayed items and only loads visible ones. Use itemsIndexed to access the index.
Navigation Between Screens
import androidx.navigation.compose.*
import androidx.compose.runtime.*
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") { GreetingScreen("Utilisateur") }
composable("list") { ItemListScreen(listOf("A", "B")) }
}
}NavHost and NavController manage the navigation stack. Pass arguments via routes for simple data.
Best Practices
- Separate business logic into ViewModels
- Use stateless Composables when possible
- Prefer reusable modifiers
- Test recompositions with previews
- Manage themes with MaterialTheme
Common Mistakes to Avoid
- Forgetting to use remember for local state
- Calling expensive functions inside Composables
- Ignoring LazyColumn performance with unique keys
- Modifying state directly without a ViewModel
Going Further
Explore advanced animations, Room integration, and UI tests. Discover our Learni courses.