Menjinakkan Rekomposisi
Parameter stabil dan lebih sedikit rekomposisi.
Menjinakkan Rekomposisi adalah pelajaran Android Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Android Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Android Academy mencakup 4 pelajaran total.
Rekomposisi: Pengatur Performa Compose
Dalam Jetpack Compose, UI dijelaskan oleh fungsi. Saat status berubah, Compose melakukan rekomposisi: Compose menjalankan ulang composable yang membaca status tersebut untuk memperbarui layar.
Rekomposisi adalah hal yang normal dan ringan jika cakupannya ditentukan dengan baik. Namun, jika terjadi terlalu sering atau mencakup terlalu banyak bagian hierarki, rekomposisi menjadi penyebab nomor 1 jank Compose. Pelajaran ini mengajarkan Anda untuk menjaga rekomposisi tetap kecil dan jarang.
Melihat Jumlah Rekomposisi
Sebelum memperbaiki, lakukan pengukuran. Layout Inspector di Android Studio menampilkan jumlah rekomposisi setiap composable secara waktu nyata. Anda juga dapat menggunakan metrik compiler Compose atau penghitung debug sederhana.
Trik sederhana: SideEffect menaikkan nilai referensi setiap kali composable melakukan rekomposisi, sehingga Anda dapat mencatat hal-hal yang tidak terduga selama pengembangan.
@Composable
fun RecompositionCounter(tag: String) {
val count = remember { mutableStateOf(0) }
SideEffect { count.value++ }
Log.d("Recompose", "$tag recomposed ${count.value} times")
}
// Drop RecompositionCounter("PriceLabel") inside a composable
// to watch how often it re-runs while you interact.Baca Status Selambat Mungkin
Compose hanya melakukan rekomposisi pada composable yang membaca nilai status. Jika induk membaca status, seluruh induk melakukan rekomposisi; jika hanya anak kecil yang membacanya, hanya anak tersebut yang melakukan rekomposisi.
Jadi, turunkan pembacaan status ke bawah dalam hierarki. Di sini, versi yang buruk melakukan rekomposisi pada seluruh Column di setiap detak; versi yang baik membatasinya hanya pada label.
// BAD: Column reads `seconds`, so everything recomposes each second
@Composable
fun TimerBad(seconds: Int) {
Column {
ExpensiveHeader()
Text("Elapsed: $seconds")
}
}
// GOOD: only the Text reads the value via a lambda
@Composable
fun TimerGood(seconds: () -> Int) {
Column {
ExpensiveHeader()
Text("Elapsed: ${seconds()}")
}
}Tunda Pembacaan dengan Lambda
Pola yang ampuh: alih-alih meneruskan nilai yang sering berubah, teruskan lambda yang mengembalikan nilai tersebut. Composable yang akhirnya memanggil lambda tersebut adalah satu-satunya yang melakukan rekomposisi.
Inilah alasan Modifier.offset { ... } dan graphicsLayer { ... } menerima lambda: nilai pengguliran/animasi berubah di setiap frame, dan lambda menjaga agar rekomposisi tidak masuk ke fase tata letak sama sekali.
// Passing the value: parent recomposes every frame of scroll
Box(Modifier.offset(y = scrollOffset.dp))
// Passing a lambda: skips recomposition, updates in the layout phase
Box(Modifier.offset { IntOffset(x = 0, y = scrollOffset.roundToInt()) })
// Same idea for alpha/scale during animation:
Image(
painter = painter,
contentDescription = null,
modifier = Modifier.graphicsLayer { alpha = animatedAlpha() }
)Stabilitas: Alasan Compose Melewati Rekomposisi
Compose dapat melewati rekomposisi sebuah composable jika semua parameternya stabil dan tidak berubah. Suatu tipe stabil jika Compose dapat mempercayai bahwa equals mencerminkan perubahan yang sebenarnya dan kolom publiknya tidak berubah tanpa terdeteksi.
- Stabil: tipe primitif,
String, kelas data yang tidak dapat diubah,State. - Tidak stabil: antarmuka
List/Map, kelas dengan kolomvar, tipe dari modul tanpa compiler.
Parameter yang tidak stabil memaksa rekomposisi meskipun tidak ada yang berubah.
// UNSTABLE: List is an interface; Compose cannot assume immutability,
// so UserList recomposes even if the contents are identical.
@Composable
fun UserList(users: List<User>) { /* ... */ }
data class User(val id: Long, val name: String) // stable: all valsJadikan Parameter Stabil
Dua perbaikan umum untuk parameter yang tidak stabil:
- Gunakan koleksi yang tidak dapat diubah dari
kotlinx.collections.immutable(misalnyaImmutableList), yang dianggap stabil oleh Compose. - Beri anotasi
@Immutableatau@Stablepada kelas yang Anda kendalikan untuk menjanjikan kepada Compose bahwa kelas tersebut tidak akan berubah.
Sekarang Compose dapat melewati rekomposisi dengan aman saat instance yang sama diteruskan lagi.
import kotlinx.collections.immutable.ImmutableList
import androidx.compose.runtime.Immutable
@Immutable
data class UiState(
val title: String,
val users: ImmutableList<User>
)
// Stable parameter -> Compose can skip this when state is unchanged
@Composable
fun UserList(users: ImmutableList<User>) { /* ... */ }remember: Jangan Hitung Ulang di Setiap Frame
Composable dapat dijalankan berkali-kali. Perhitungan nontrivial apa pun yang dilakukan langsung di dalam isi composable akan berjalan pada setiap rekomposisi. Bungkus perhitungan tersebut dalam remember agar hanya dihitung ulang saat kunci-nya berubah.
Untuk nilai yang diturunkan dari status lain, pilih derivedStateOf, yang hanya memancarkan ulang saat hasil perhitungan benar-benar berubah.
// Recomputes the sorted list only when `items` changes
val sorted = remember(items) { items.sortedBy { it.name } }
// derivedStateOf: only triggers readers when the BOOLEAN flips,
// not on every scroll pixel
val showButton by remember {
derivedStateOf { listState.firstVisibleItemIndex > 5 }
}
if (showButton) ScrollToTopButton()Kunci Stabil dalam Daftar Lazy
Dalam LazyColumn/LazyRow, berikan setiap item kunci yang stabil. Tanpa kunci, penyisipan atau pengurutan ulang item memaksa Compose melakukan rekomposisi dan pengukuran ulang pada item yang sebenarnya tidak berubah, karena Compose melacaknya berdasarkan posisi.
Dengan kunci stabil, Compose dapat mencocokkan item di antara pembaruan dan melewati item yang tidak berubah.
LazyColumn {
items(
items = users,
key = { user -> user.id } // stable identity
) { user ->
UserRow(user)
}
}
// Now adding a user at the top reuses existing rows
// instead of recomposing the whole list.Naikkan Status, Teruskan Peristiwa ke Atas
Parameter lambda yang tidak stabil juga dapat mengganggu proses melewati rekomposisi jika instance lambda baru dibuat pada setiap rekomposisi. Stabilkan callback dengan mengingatnya atau merujuk ke fungsi yang stabil.
Jika digabungkan dengan peningkatan status ke pemanggil (status berada di pemanggil, peristiwa mengalir ke atas), hal ini membuat composable daun tetap ringan dan dapat dilewati.
@Composable
fun SearchBar(query: String, onQueryChange: (String) -> Unit) {
TextField(value = query, onValueChange = onQueryChange)
}
// In the caller, a remembered lambda keeps the reference stable:
val onChange = remember { { newValue: String -> viewModel.setQuery(newValue) } }
SearchBar(query = query, onQueryChange = onChange)Hindari Membaca Status Pengguliran/Animasi Terlalu Tinggi
Kesalahan yang umum: membaca status yang berubah cepat (offset pengguliran, progres animasi) dalam composable tingkat tinggi. Hal itu memaksa seluruh subhierarki melakukan rekomposisi di setiap frame.
Simpan pembacaan tersebut di dalam lambda Modifier (offset {}, graphicsLayer {}, drawBehind {}) agar pekerjaan berlangsung pada fase tata letak atau gambar, bukan rekomposisi. Inilah perbedaan antara pengguliran 60fps yang mulus dan pengguliran yang tersendat.
// Animated color used only for drawing -> stay in the draw phase
Box(
Modifier.drawBehind {
drawRect(color = animatedColor()) // lambda read, no recomposition
}
)Daftar Periksa Rekomposisi
Saat layar terasa mengalami jank selama interaksi, periksa daftar ini:
- Apakah parameter stabil (data yang tidak dapat diubah,
ImmutableList)? - Apakah Anda membaca status yang berubah cepat serendah mungkin, idealnya dalam lambda modifier?
- Apakah daftar lazy memiliki kunci stabil?
- Apakah perhitungan mahal berada di balik
remember/derivedStateOf? - Apakah Layout Inspector mengonfirmasi bahwa jumlahnya benar-benar berkurang?
Setiap kotak yang Anda centang menghapus pekerjaan yang terbuang dari setiap frame.
Pemeriksaan Singkat
Anda meneruskan List<User> ke composable dan melihat bahwa composable tersebut melakukan rekomposisi meskipun datanya tidak berubah. Apa perbaikan yang paling langsung?
Ringkasan: Rekomposisi yang Lebih Kecil dan Lebih Jarang
Anda belajar mengendalikan rekomposisi, masalah performa Compose yang paling utama:
- Ukur jumlahnya dengan Layout Inspector atau penghitung debug.
- Baca status serendah mungkin; tunda pembacaan dengan lambda.
- Jadikan parameter stabil dengan data yang tidak dapat diubah dan
@Immutable/ImmutableList. - Gunakan
rememberdanderivedStateOfagar tidak menghitung ulang di setiap frame. - Berikan kunci stabil pada item lazy; simpan pembacaan status yang cepat dalam lambda modifier.
Selanjutnya kita beralih dari CPU/rekomposisi ke memori: menemukan dan memperbaiki kebocoran.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Menjinakkan Rekomposisi” gratis?
Ya — teks lengkap “Menjinakkan Rekomposisi” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Android Academy, upgrade ke CoddyKit PRO. Kursus Android Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Menjinakkan Rekomposisi”?
Parameter stabil dan lebih sedikit rekomposisi. Kamu berlatih Android Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Android Academy?
Tidak diperlukan pengalaman sebelumnya. Android Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Menjinakkan Rekomposisi” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Android Academy ini?
Ya. Setiap pelajaran Android Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Mengukur Kinerja
- Menjinakkan Rekomposisi
- Kebocoran Memori dan Perbaikannya
- Profil Startup dan Baseline