Recomposition adalah mekanisme Jetpack Compose yang secara otomatis membangun ulang bagian-bagian antarmuka pengguna saat data berubah, tanpa pembaruan manual elemen View. Ketika variabel status yang bergantung pada fungsi Composable mengubah nilainya, Compose hanya menjalankan ulang fungsi tersebut, membiarkan sisa pohon UI tidak tersentuh. Menurut data Google Android Developers, 2026, pemahaman yang benar tentang Recomposition memungkinkan pengurangan jumlah penggambaran ulang yang tidak perlu sebesar 40–60%.
Poin utama
Recomposition adalah eksekusi ulang fungsi Composable yang sudah berpartisipasi dalam Composition, dengan nilai baru parameter atau status. Tujuan utama rekomposisi adalah menyinkronkan pohon UI dengan data terkini tanpa membangun ulang seluruh antarmuka dari awal. Tidak seperti Composition yang terjadi sekali, Recomposition dapat dijalankan ratusan kali selama masa pakai layar.
Recomposition bekerja berdasarkan prinsip smart invalidation: Compose melacak objek State mana yang dibaca oleh setiap fungsi Composable dan menandai untuk dijalankan ulang hanya fungsi-fungsi yang dependensinya berubah. Ini dicapai melalui sistem snapshot, yang mencatat semua operasi pembacaan State selama eksekusi, dan Composer, yang memetakan dependensi ini ke fungsi-fungsi tertentu.
Penting untuk dipahami: rekomposisi tidak berarti penggambaran ulang layar secara instan. Compose bekerja dalam tiga fase: Composition (membangun deskripsi UI), Layout (menghitung ukuran dan posisi) dan Drawing (menggambar di kanvas). Jika setelah rekomposisi ukuran dan posisi elemen tidak berubah, fase Layout dapat dilewati. Jika tampilan tidak berubah — Drawing dilewati. Arsitektur tiga fase ini memastikan biaya minimal setiap pembaruan UI.
Ada tiga pemicu utama rekomposisi. Pertama — perubahan objek State yang dibaca di dalam tubuh fungsi Composable. Ketika mutableStateOf atau derivedStateOf mengubah nilainya, semua fungsi yang mencatat pembacaan State ini dalam komposisi sebelumnya ditandai untuk dijalankan ulang.
Pemicu kedua — perubahan parameter fungsi Composable saat dipanggil dari fungsi induk. Jika fungsi induk memberikan nilai baru (misalnya teks atau angka berubah), fungsi anak akan dijalankan ulang, meskipun tidak membaca State di dalamnya. Compose membandingkan nilai baru dan lama parameter melalui equals, dan jika sama — fungsi dapat dilewati.
Pemicu ketiga — perubahan CompositionLocal melalui CompositionLocalProvider. Semua fungsi yang membaca CompositionLocal melalui .current dijalankan ulang saat provider berubah. Mekanisme ini digunakan oleh MaterialTheme: perubahan tema (terang/gelap) menyebabkan rekomposisi semua komponen yang membaca MaterialTheme.colorScheme.
@Composable
fun RecompositionDemo() {
var counter by remember { mutableStateOf(0) }
var text by remember { mutableStateOf("Hello") }
Column {
Text("Penghitung: $counter") // rekomposisi saat penghitung berubah
Text("Pesan: $text") // rekomposisi saat teks berubah
Button(onClick = { counter++ }) {
Text("+1")
}
Button(onClick = { text = "Dunia" }) {
Text("Ubah teks")
}
}
}
Menekan tombol +1 mengubah counter, yang menyebabkan rekomposisi hanya pada baris Text pertama dan Column itu sendiri. Baris Text kedua, yang menampilkan text, tidak dijalankan ulang. Isolasi semacam itu — hasil dari sistem snapshot: setiap fungsi Composable hanya tahu tentang objek State yang telah dibacanya.
Optimasi rekomposisi dimulai dengan pemilihan struktur data yang tepat. Gunakan koleksi tak-terubah (listOf, mapOf) alih-alih koleksi yang dapat diubah (mutableListOf). Compose membandingkan parameter melalui equals, dan jika koleksi berubah tetapi equals mengembalikan true — fungsi tidak akan dijalankan ulang. Untuk koleksi yang dapat diubah, gunakan SnapshotStateList, yang mengimplementasikan pelacakan perubahan yang benar di tingkat elemen.
Teknik kedua — memisahkan bagian stabil UI ke dalam fungsi Composable terpisah. Jika bagian layar tidak bergantung pada status yang sering berubah, pisahkan ke dalam fungsi terpisah dengan parameter. Ketika rekomposisi datang, fungsi stabil menerima parameter yang sama, Compose membandingkannya dan melewatkan eksekusi. Ini lebih menguntungkan daripada menjalankan ulang bagian ini dalam fungsi besar di mana sebagian parameternya berubah.
Teknik ketiga — kunci di LazyColumn. Selalu berikan key untuk item di LazyColumn, LazyGrid, dan wadah malas lainnya. Kunci memungkinkan Compose mengidentifikasi elemen saat daftar berubah: penambahan, penghapusan, atau penataan ulang. Tanpa kunci, Compose menjalankan ulang semua elemen daftar pada setiap perubahan, yang pada daftar besar memberikan penurunan kinerja yang signifikan.
// Struktur yang dioptimalkan: bagian stabil dipisahkan secara terpisah
@Composable
fun OptimizedScreen(items: List<Item>) {
Column {
Header() // tidak tergantung pada item — tidak ada rekomposisi
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(items, key = { it.id }) { item ->
ItemRow(item = item) // rekomposisi hanya untuk item yang berubah
}
}
}
}
@Composable
fun Header() {
Text("Daftar item", style = MaterialTheme.typography.headlineMedium)
}
@Composable
fun ItemRow(item: Item) {
Text(item.title)
}
Skipping adalah mekanisme di mana Compose melewatkan eksekusi fungsi Composable jika semua parameternya tidak berubah. Agar skipping berfungsi dengan benar, tipe parameter harus stabil (stable). Kompiler Kotlin menandai sebagai stabil: tipe primitif (Int, Float, Boolean), String, fungsi lambda, serta kelas yang semua bidangnya stabil dan val.
Stability adalah anotasi @Stable atau @Immutable yang dapat ditambahkan ke kelas data kustom. Jika kelas berisi bidang yang dapat diubah (var), kompiler menganggapnya tidak stabil dan Compose tidak dapat melewatkan fungsi dengan parameter semacam itu. Untuk kelas dengan var, gunakan @Stable jika Anda menjamin bahwa pemberitahuan tentang perubahan akan dikirim melalui sistem snapshot.
Stability dapat diperiksa melalui flag kompiler -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports". Ini menghasilkan laporan dengan daftar semua fungsi Composable dan parameternya dengan indikasi stability. Jika parameter tidak stabil — skipping untuk fungsi itu tidak mungkin dan akan dijalankan ulang pada setiap rekomposisi induk.
| Tipe | Stabilitas | Skipping |
|---|---|---|
| Int, Float, Boolean | Stabil | Ya |
| String | Stabil | Ya |
| Lambda | Stabil | Ya |
| data class dengan bidang val | Stabil | Ya |
| data class dengan bidang var | Tidak stabil | Tidak |
| List<String> | Tidak stabil | Tidak |
Perhatikan: List<String> dianggap tidak stabil karena ini adalah antarmuka, bukan implementasi konkret. Gunakan immutableListOf() dari pustaka Kotlin Collections Immutable atau bungkus daftar dalam kelas @Stable. Lambda selalu stabil, karena equals-nya hanya membandingkan referensi, dan saat membuat lambda baru di lokasi pemanggilan, fungsi induk juga dijalankan ulang.
Untuk pemantauan rekomposisi, Android Studio menyediakan Layout Inspector dengan mode Compose Recomposition Counts. Dalam mode ini, setiap fungsi Composable menampilkan jumlah rekomposisi dan alasan menjalankan ulang. Ini memungkinkan dengan cepat menemukan fungsi yang terlalu sering direkomposisi dan menentukan akar penyebab — parameter tidak stabil atau dependensi State yang tidak perlu.
Alat tambahan: Compose Metrics (mengumpulkan statistik melalui tes instrumentation) dan Recomposition Timer (mengukur waktu eksekusi setiap fungsi). Google merekomendasikan mengaktifkan alat-alat ini pada tahap profiling dan menonaktifkannya di rilis produksi, karena mereka menambahkan overhead hingga 20% pada setiap rekomposisi.
Saat menganalisis rekomposisi, cari pola unnecessary recomposition: fungsi dijalankan ulang meskipun UI keluarannya seharusnya tidak berubah. Penyebab umum adalah penggunaan lambda tanpa remember, ketika setiap kali objek lambda baru dibuat dan Compose menganggap parameter berubah. Solusi: membungkus lambda dalam remember { } dengan tangkapan tetap.
// Buruk: lambda baru pada setiap rekomposisi induk
@Composable
fun Parent() {
Child(onClick = { doSomething() }) // lambda baru setiap kali
}
// Baik: remember menstabilkan lambda
@Composable
fun Parent() {
val onClick = remember { { doSomething() } }
Child(onClick = onClick) // referensi yang sama
}
Pertanyaan yang sering diajukan
Tidak, rekomposisi hanya fase Composition. Setelahnya Layout dan Drawing dijalankan. Jika setelah rekomposisi ukuran dan posisi elemen tidak berubah, Layout dan Drawing dapat sepenuhnya dilewati, yang menghemat sumber daya GPU.
Pada animasi, rekomposisi dapat dijalankan hingga 120 kali per detik (120fps). Untuk interaksi biasa — 10–60 kali per detik. Penting agar setiap rekomposisi masuk dalam anggaran bingkai (8–16 ms), jika tidak aplikasi akan melambat.
Penyebabnya — perubahan parameter dari fungsi induk. Induk dijalankan ulang (karena alasannya sendiri) dan memberikan nilai baru. Untuk menghindari ini, periksa stability parameter dan gunakan remember untuk stabilisasi lambda dan nilai yang dihitung.
Tidak ada penonaktifan langsung, tetapi ada skipping paksa melalui readInComposition — State dibaca di luar tubuh fungsi, yang tidak mendaftarkan dependensi. Gunakan ini dengan hati-hati: fungsi tidak akan merespons perubahan, yang dapat menyebabkan UI usang.
Composition lebih mahal karena membuat semua slot dan simpul pohon dari awal. Recomposition menggunakan kembali slot yang ada dan hanya memperbarui nilainya. Dalam praktiknya, Composition layar membutuhkan waktu 2–10 ms, dan rekomposisi satu elemen — 0.1–1 ms.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga