Android Academy · Pelajaran

Menjinakkan Gubahan Semula

Parameter stabil dan lebih sedikit gubahan semula.

Pelajaran 2 daripada 413 langkah

Menjinakkan Gubahan Semula ialah pelajaran Android Academy percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Android Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Android Academy merangkumi sejumlah 4 pelajaran.

Penggubahan Semula: Kawalan Prestasi Compose

Dalam Jetpack Compose, UI diterangkan oleh fungsi. Apabila keadaan berubah, Compose melakukan penggubahan semula: ia menjalankan semula composable yang membaca keadaan tersebut untuk mengemas kini skrin.

Penggubahan semula adalah perkara biasa dan murah apabila skopnya baik. Namun, apabila ia berlaku terlalu kerap atau meliputi terlalu banyak bahagian pepohon, ia menjadi punca nombor 1 kegagapan Compose. Pelajaran ini mengajar anda mengecilkan dan mengurangkan kekerapan penggubahan semula.

Melihat Kiraan Penggubahan Semula

Sebelum membaiki, ukur dahulu. Layout Inspector dalam Android Studio menunjukkan kiraan penggubahan semula bagi setiap composable dalam masa nyata. Anda juga boleh menggunakan metrik penyusun Compose atau pembilang nyahpepijatan ringkas.

Satu helah mudah: SideEffect menambah nilai rujukan setiap kali composable melakukan penggubahan semula, supaya anda boleh mencatat perkara yang tidak dijangka semasa pembangunan.

@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 Keadaan Selewat yang Mungkin

Compose hanya melakukan penggubahan semula pada composable yang membaca nilai keadaan. Jika induk membaca keadaan itu, seluruh induk akan digubah semula; jika hanya anak kecil membacanya, hanya anak itu yang digubah semula.

Jadi, turunkan pembacaan keadaan ke bawah pepohon. Di sini, versi buruk menggubah semula seluruh Column pada setiap detik; versi baik mengehadkannya kepada 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()}")
    }
}

Tangguhkan Pembacaan dengan Lambda

Satu corak yang berkuasa: daripada menghantar nilai yang kerap berubah, hantarkan lambda yang mengembalikannya. Composable yang akhirnya memanggil lambda itu sahaja yang akan digubah semula.

Inilah sebabnya Modifier.offset { ... } dan graphicsLayer { ... } menerima lambda: nilai penatalan/animasi berubah setiap bingkai, dan lambda menghalang penggubahan semula daripada berlaku dalam fasa reka letak.

// 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() }
)

Kestabilan: Sebab Compose Melangkau

Compose boleh melangkau penggubahan semula composable jika semua parameternya stabil dan tidak berubah. Sesuatu jenis adalah stabil apabila Compose boleh mempercayai bahawa equals mencerminkan perubahan sebenar dan medan awamnya tidak berubah tanpa dikesan.

  • Stabil: primitif, String, kelas data tidak boleh ubah, State.
  • Tidak stabil: antara muka List/Map, kelas dengan medan var, jenis daripada modul tanpa penyusun.

Parameter yang tidak stabil memaksa penggubahan semula walaupun tiada apa-apa 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 vals

Jadikan Parameter Stabil

Dua pembaikan biasa untuk parameter yang tidak stabil:

  • Gunakan koleksi tidak boleh ubah daripada kotlinx.collections.immutable (contohnya ImmutableList), yang dianggap stabil oleh Compose.
  • Anotasikan kelas yang anda kawal dengan @Immutable atau @Stable untuk menjanjikan kepada Compose bahawa kelas itu tidak akan berubah.

Kini Compose boleh melangkau penggubahan semula dengan selamat apabila tika yang sama dihantar semula.

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 Kira Semula Setiap Bingkai

Composable boleh dijalankan berkali-kali. Sebarang pengiraan bukan remeh yang dilakukan terus dalam isi fungsi akan dijalankan pada setiap penggubahan semula. Bungkusnya dalam remember supaya ia hanya dikira semula apabila kuncinya berubah.

Untuk nilai yang diperoleh daripada keadaan lain, utamakan derivedStateOf, yang hanya mengeluarkan semula nilai apabila hasil yang dikira 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 Senarai Lazy

Dalam LazyColumn/LazyRow, berikan setiap item kunci yang stabil. Tanpa kunci, memasukkan atau menyusun semula item memaksa Compose menggubah semula dan mengukur semula item yang sebenarnya tidak berubah, kerana Compose menjejakinya berdasarkan kedudukan.

Dengan kunci yang stabil, Compose boleh memadankan item merentasi kemas kini dan melangkau 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 Keadaan, Hantar Peristiwa ke Atas

Parameter lambda yang tidak stabil juga boleh menghalang lompatan jika tika lambda baharu dicipta pada setiap penggubahan semula. Stabilkan panggilan balik dengan mengingatinya atau merujuk fungsi yang stabil.

Digabungkan dengan penaikan keadaan (keadaan berada dalam pemanggil, peristiwa mengalir ke atas), pendekatan ini memastikan composable daun kekal murah dan boleh dilangkau.

@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)

Elakkan Membaca Keadaan Penatalan/Animasi Terlalu Tinggi

Satu kesilapan klasik: membaca keadaan yang berubah pantas (anjakan penatalan, kemajuan animasi) dalam composable peringkat tinggi. Ini memaksa keseluruhan subpepohon digubah semula pada setiap bingkai.

Kekalkan pembacaan sedemikian dalam lambda Modifier (offset {}, graphicsLayer {}, drawBehind {}) supaya kerja berlaku dalam fasa reka letak atau lukisan, bukan penggubahan semula. Inilah perbezaan antara penatalan 60fps yang lancar dengan penatalan yang tersekat-sekat.

// Animated color used only for drawing -> stay in the draw phase
Box(
    Modifier.drawBehind {
        drawRect(color = animatedColor())  // lambda read, no recomposition
    }
)

Senarai Semak Penggubahan Semula

Apabila skrin terasa tersekat-sekat semasa interaksi, semak senarai ini:

  • Adakah parameter stabil (data tidak boleh ubah, ImmutableList)?
  • Adakah anda membaca keadaan yang berubah pantas serendah mungkin, sebaik-baiknya dalam lambda pengubah suai?
  • Adakah senarai lazy mempunyai kunci stabil?
  • Adakah pengiraan mahal diletakkan di sebalik remember / derivedStateOf?
  • Adakah Layout Inspector mengesahkan bahawa kiraan benar-benar berkurang?

Setiap kotak yang ditanda membuang kerja yang terbazir daripada setiap bingkai.

Semakan Pantas

Anda menghantar List<User> kepada composable dan mendapati ia melakukan penggubahan semula walaupun data tidak berubah. Apakah pembaikan yang paling langsung?

Ulang Kaji: Penggubahan Semula yang Lebih Kecil dan Kurang Kerap

Anda telah belajar mengawal penggubahan semula, iaitu isu prestasi utama Compose:

  • Ukur kiraan dengan Layout Inspector atau pembilang nyahpepijatan.
  • Baca keadaan serendah mungkin; tangguhkan pembacaan dengan lambda.
  • Jadikan parameter stabil dengan data tidak boleh ubah dan @Immutable/ImmutableList.
  • Gunakan remember dan derivedStateOf untuk mengelakkan pengiraan semula pada setiap bingkai.
  • Berikan item lazy kunci stabil; kekalkan pembacaan keadaan pantas dalam lambda pengubah suai.

Seterusnya kita beralih daripada CPU/penggubahan semula kepada memori: mencari dan membaiki kebocoran.

Percuma untuk bermula

Pelajari Kotlin dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
36
Pelajaran
152

Soalan Lazim

Adakah pelajaran “Menjinakkan Gubahan Semula” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Android Academy, termasuk “Menjinakkan Gubahan Semula”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Android Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Menjinakkan Gubahan Semula”?

Parameter stabil dan lebih sedikit gubahan semula. Anda berlatih Android Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Android Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Android Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “Menjinakkan Gubahan Semula” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Android Academy ini?

Ya. Setiap pelajaran Android Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Mengukur Prestasi
  2. Menjinakkan Gubahan Semula
  3. Kebocoran Memori dan Pembetulan
  4. Profil Permulaan dan Asas
← Kembali ke Android Academy