Saat menghadapi class yang tidak stabil yang menyebabkan masalah performa, Anda harus membuatnya stabil. Dokumen ini menguraikan beberapa teknik yang dapat Anda gunakan untuk melakukannya.
Mengaktifkan skipping kuat
Anda harus mencoba mengaktifkan mode skipping kuat terlebih dahulu. Mode skipping kuat memungkinkan composable dengan parameter tidak stabil dilewati dan merupakan metode termudah untuk memperbaiki masalah performa yang disebabkan oleh stabilitas.
Lihat Lewatan kuat untuk mengetahui informasi selengkapnya.
Membuat class tidak dapat diubah
Anda juga dapat mencoba membuat class yang tidak stabil menjadi sepenuhnya tidak dapat diubah.
- Tidak dapat diubah (Immutable): Menunjukkan jenis yang nilai propertinya tidak pernah
berubah setelah instance jenis tersebut dibuat, dan semua metodenya
transparan secara referensial.
- Pastikan semua properti class adalah
val, bukanvar, dan jenis yang tidak dapat diubah. - Jenis primitif seperti
String, IntdanFloatselalu tidak dapat diubah. - Jika hal ini tidak mungkin, Anda harus menggunakan status Compose untuk properti yang dapat berubah.
- Pastikan semua properti class adalah
- Stabil: Menunjukkan jenis yang dapat diubah. Runtime Compose tidak mengetahui apakah dan kapan pun properti publik atau perilaku metode jenis akan menghasilkan hasil yang berbeda dari pemanggilan sebelumnya.
Koleksi yang tidak dapat diubah
Alasan umum Compose menganggap class tidak stabil adalah koleksi. Seperti yang disebutkan di halaman Mendiagnosis masalah stabilitas, compiler Compose tidak dapat sepenuhnya yakin bahwa koleksi seperti List, Map dan Set benar-benar tidak dapat diubah dan oleh karena itu menandainya sebagai tidak stabil.
Untuk mengatasinya, Anda dapat menggunakan koleksi yang tidak dapat diubah. Compiler Compose mencakup dukungan untuk Kotlinx Immutable Collections. Koleksi ini dijamin bersifat immutable, dan compiler Compose memperlakukannya seperti itu. Library ini masih dalam versi alfa, jadi kemungkinan ada perubahan pada API-nya.
Pertimbangkan lagi class yang tidak stabil ini dari panduan Mendiagnosis masalah stabilitas:
unstable class Snack {
…
unstable val tags: Set<String>
…
}
Anda dapat membuat tags stabil menggunakan koleksi yang tidak dapat diubah. Di class, ubah
jenis tags menjadi ImmutableSet<String>:
data class Snack{
…
val tags: ImmutableSet<String> = persistentSetOf()
…
}
Setelah melakukannya, semua parameter class bersifat immutable, dan compiler Compose menandai class sebagai stabil.
Anotasi dengan Stable atau Immutable
Kemungkinan jalur untuk menyelesaikan masalah stabilitas adalah dengan menganotasi class yang tidak stabil dengan @Stable atau @Immutable.
Menganotasi class akan menggantikan apa yang akan
disimpulkan oleh compiler tentang class Anda. Hal ini mirip dengan operator !! di Kotlin. Anda harus sangat
berhati-hati dalam menggunakan anotasi ini. Mengganti perilaku compiler
dapat menyebabkan bug yang tidak terduga, seperti composable Anda tidak merekomposisi saat
Anda mengharapkannya.
Jika memungkinkan untuk membuat class Anda stabil tanpa anotasi, Anda harus berupaya mencapai stabilitas dengan cara tersebut.
Cuplikan berikut memberikan contoh minimal class data yang dianotasikan sebagai immutable:
@Immutable
data class Snack(
…
)
Baik Anda menggunakan anotasi @Immutable maupun @Stable, compiler Compose
akan menandai class Snack sebagai stabil.
Kelas yang dianotasi dalam koleksi
Pertimbangkan composable yang menyertakan parameter jenis List<Snack>:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
…
unstable snacks: List<Snack>
…
)
Meskipun Anda menganotasi Snack dengan @Immutable, compiler Compose tetap menandai
parameter snacks di HighlightedSnacks sebagai tidak stabil.
Parameter menghadapi masalah yang sama seperti class dalam hal jenis koleksi,
compiler Compose selalu menandai parameter jenis List sebagai tidak stabil, bahkan
jika merupakan koleksi jenis stabil.
Anda tidak dapat menandai parameter individual sebagai stabil, dan Anda juga tidak dapat menganotasi composable agar selalu dapat dilewati. Ada beberapa jalur ke depan.
Ada beberapa cara untuk mengatasi masalah koleksi yang tidak stabil. Subbagian berikut menguraikan berbagai pendekatan ini.
File konfigurasi
Jika Anda bersedia mematuhi kontrak stabilitas di codebase, Anda dapat memilih untuk menganggap koleksi Kotlin sebagai stabil dengan menambahkan kotlin.collections.* ke file konfigurasi stabilitas.
Koleksi yang tidak dapat diubah
Untuk keamanan waktu kompilasi imutabilitas, Anda dapat menggunakan koleksi imutabel kotlinx, bukan List.
@Composable
private fun HighlightedSnacks(
…
snacks: ImmutableList<Snack>,
…
)
Wrapper
Jika tidak dapat menggunakan koleksi yang tidak dapat diubah, Anda dapat membuatnya sendiri. Untuk melakukannya,
bungkus List dalam class stabil yang dianotasi. Wrapper generik kemungkinan merupakan pilihan terbaik untuk hal ini, bergantung pada persyaratan Anda.
@Immutable
data class SnackCollection(
val snacks: List<Snack>
)
Kemudian, Anda dapat menggunakannya sebagai jenis parameter dalam composable.
@Composable
private fun HighlightedSnacks(
index: Int,
snacks: SnackCollection,
onSnackClick: (Long) -> Unit,
modifier: Modifier = Modifier
)
Solusi
Setelah menerapkan salah satu pendekatan ini, compiler Compose kini menandai Composable
HighlightedSnacks sebagai skippable dan restartable.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
stable snacks: ImmutableList<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)
Selama rekomposisi, Compose kini dapat melewati HighlightedSnacks jika tidak ada inputnya yang berubah.
File konfigurasi stabilitas
Mulai dari Compose Compiler 1.5.5, file konfigurasi class yang akan dianggap stabil dapat disediakan pada waktu kompilasi. Hal ini memungkinkan untuk mempertimbangkan class yang tidak Anda kontrol, seperti class library standar seperti LocalDateTime, sebagai stabil.
File konfigurasi adalah file teks biasa dengan satu class per baris. Komentar, karakter pengganti tunggal dan ganda didukung.
Contoh konfigurasi:
// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider my datalayer stable
com.datalayer.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>
Untuk mengaktifkan fitur ini, teruskan jalur file konfigurasi ke
blok opsi composeCompiler dari konfigurasi plugin Gradle compiler Compose.
composeCompiler {
stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
}
Karena compiler Compose berjalan di setiap modul dalam project Anda secara terpisah, Anda dapat memberikan konfigurasi yang berbeda ke modul yang berbeda jika diperlukan. Atau, miliki satu konfigurasi di tingkat root project Anda dan teruskan jalur tersebut ke setiap modul.
Beberapa modul
Masalah umum lainnya melibatkan arsitektur multi-modul. Compiler Compose hanya dapat menyimpulkan apakah suatu class stabil jika semua jenis non-primitif yang direferensikannya ditandai secara eksplisit sebagai stabil atau berada dalam modul yang juga dibangun dengan compiler Compose.
Jika lapisan data Anda berada di modul terpisah dari lapisan UI, yang merupakan pendekatan yang direkomendasikan, hal ini mungkin menjadi masalah yang Anda alami.
Solusi
Untuk mengatasi masalah ini, Anda dapat mengambil salah satu pendekatan berikut:
- Tambahkan class ke file konfigurasi Compiler Anda.
- Aktifkan compiler Compose di modul lapisan data Anda, atau beri tag pada class Anda dengan
@Stableatau@Immutablejika sesuai.- Hal ini melibatkan penambahan dependensi Compose ke lapisan data Anda. Namun,
dependensi ini hanya untuk runtime Compose, bukan untuk
Compose-UI.
- Hal ini melibatkan penambahan dependensi Compose ke lapisan data Anda. Namun,
dependensi ini hanya untuk runtime Compose, bukan untuk
- Dalam modul UI, bungkus class lapisan data Anda dalam class wrapper khusus UI.
Masalah yang sama juga terjadi saat menggunakan library eksternal jika library tersebut tidak menggunakan kompiler Compose.
Tidak semua composable harus dapat dilewati
Saat berupaya memperbaiki masalah stabilitas, Anda tidak boleh mencoba membuat setiap composable dapat dilewati. Mencoba melakukannya dapat menyebabkan pengoptimalan dini yang menimbulkan lebih banyak masalah daripada yang diperbaiki.
Ada banyak situasi di mana dapat dilewati tidak memberikan manfaat nyata dan dapat menyebabkan kode sulit dikelola. Contoh:
- Composable yang tidak sering direkomposisi, atau tidak direkomposisi sama sekali.
- Composable yang dengan sendirinya hanya memanggil composable yang dapat dilewati.
- Composable dengan sejumlah besar parameter dengan implementasi persamaan yang mahal. Dalam hal ini, biaya untuk memeriksa apakah ada parameter yang berubah dapat lebih besar daripada biaya rekomposisi yang murah.
Jika dapat dilewati, komponen menambahkan sedikit overhead yang mungkin tidak sebanding. Anda bahkan dapat memberi anotasi pada composable agar tidak dapat dimulai ulang dalam kasus saat Anda menentukan bahwa dapat dimulai ulang lebih banyak menimbulkan overhead daripada manfaatnya.