Mendalami Android native dengan Kotlin & Jetpack Compose: struktur proyek Gradle, composable functions, state & recomposition, navigasi antar layar, dan Material 3 — sambil membangun halaman utama aplikasi Fitku sebagai praktik nyata

Setelah memahami arsitektur platform mobile di episode 2, kini saatnya membangun aplikasi Android native dengan stack modern 2026: Kotlin + Jetpack Compose. Compose mengubah cara menulis UI Android dari XML+View imperatif menjadi deklaratif — kalian mendeskripsikan UI sebagai fungsi dari state, dan Compose yang mengurus render-nya. Ini filosofi yang sama dengan React di web, jadi terasa familier.
Mengapa penting menguasai Android native dulu? Karena sebagian besar fitur yang akan kalian pelajari di episode berikutnya (lifecycle, networking, storage, performa) paling mudah dieksplorasi penuh di platform native. Pemahaman ini juga jadi pijakan untuk KMP di episode 7.
Proyek Android modern terstruktur seperti ini:
Fitku/
├── app/
│ ├── src/main/
│ │ ├── java/com/fitku/
│ │ │ ├── MainActivity.kt
│ │ │ ├── ui/theme/ → warna, type, shape
│ │ │ └── ui/screens/ → layar aplikasi
│ │ └── AndroidManifest.xml
│ └── build.gradle.kts
├── build.gradle.kts → config di level proyek
├── settings.gradle.kts → daftar module
└── gradle/libs.versions.toml → version catalogAndroidManifest.xml mendeklarasikan aplikasi: activity, permission, dan entry point:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:label="Fitku">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>Di Compose, UI dibangun dari composable functions — fungsi Kotlin beranotasi @Composable:
@Composable
fun HomeScreen(userName: String) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(text = "Halo, $userName!", style = MaterialTheme.typography.headlineMedium)
Text(text = "Siap workout hari ini?", style = MaterialTheme.typography.bodyMedium)
Button(onClick = { /* mulai workout */ }) {
Text("Mulai Workout")
}
}
}Perhatikan: tidak ada XML, tidak ada findViewById. UI hanyalah fungsi biasa yang menerima data dan merender berdasarkan state.
Kekuatan Compose ada di recomposition: ketika state berubah, hanya composable yang membaca state itu yang di-render ulang. remember menyimpan nilai antar recomposition, dan mutableStateOf membuat perubahan state memicu recomposition:
@Composable
fun StepCounter() {
var steps by remember { mutableStateOf(0) }
Column {
Text("Langkah hari ini: $steps")
Button(onClick = { steps++ }) {
Text("Tambah langkah")
}
}
}Important
Aturan emas Compose: jangan mutasi state di luar komposisi, dan jangan panggil fungsi berat di dalam composable. Compose bisa me-render ulang berkali-kali — kode di dalam composable harus murni dan cepat. Detail manajemen state skala besar akan dibahas di episode 9.
Navigasi antar layar memakai library Navigation Compose. Layar utama Fitku memakai struktur tab:
@Composable
fun FitkuApp() {
val navController = rememberNavController()
Scaffold(
bottomBar = {
NavigationBar {
NavigationBarItem(
selected = currentRoute == "home",
onClick = { navController.navigate("home") },
icon = { Icon(Icons.Default.Home, null) },
label = { Text("Beranda") }
)
NavigationBarItem(
selected = currentRoute == "progress",
onClick = { navController.navigate("progress") },
icon = { Icon(Icons.Default.Info, null) },
label = { Text("Progres") }
)
}
}
) { innerPadding ->
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen() }
composable("progress") { ProgressScreen() }
}
}
}Material 3 adalah design system resmi Android dengan konsep color scheme, dynamic color, dan komponen modern. Tema Fitku dibungkus lewat FitkuTheme yang memakai skema warna kustom — kalian sudah melihatnya di MainActivity episode 2.
Mari rangkai semua: halaman beranda yang menampilkan langkah hari ini dan tombol mulai workout:
@Composable
fun HomeScreen(viewModel: HomeViewModel = viewModel()) {
val state by viewModel.uiState.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
text = "Halo, ${state.userName}!",
style = MaterialTheme.typography.headlineMedium
)
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
)
) {
Column(Modifier.padding(16.dp)) {
Text("Langkah hari ini", style = MaterialTheme.typography.labelLarge)
Text(
text = "${state.steps}",
style = MaterialTheme.typography.displayMedium
)
}
}
Button(
onClick = { viewModel.startWorkout() },
modifier = Modifier.fillMaxWidth()
) {
Text("Mulai Workout")
}
}
}viewModel() mengambil ViewModel yang mengelola state — pola arsitektur MVVM akan dibedah tuntas di episode 8.
rememberSaveable atau ViewModel.strings.xml (mendukung i18n dan aksesibilitas).LazyColumn: render daftar panjang dengan Column → jank parah (episode 15).Tip
Jangan takut membuka dokumentasi resmi di developer.android.com. Pedoman Android di 2026 jelas: Kotlin-first, Compose-first, dan Material 3. Ikuti pola resmi sejak awal jauh lebih murah daripada mengoreksi kustom arsitektur sendiri.
Pada episode 3 ini, kalian telah membangun fondasi Android modern:
AndroidManifest, dan version catalog.Di episode 4 selanjutnya kita lompat ke iOS dengan Swift & SwiftUI — memahami struktur App, View, state (@State, @Binding), dan Human Interface Guidelines, lalu membangun halaman yang setara untuk Fitku di sisi iOS. Sampai jumpa!