Memperbaiki masalah stabilitas

Saat dihadapkan dengan class tidak stabil yang menyebabkan performa terjadi, Anda harus membuatnya stabil. Dokumen ini menguraikan beberapa teknik yang dapat untuk melakukannya.

Aktifkan pengabaian yang kuat

Pertama-tama, Anda harus mencoba mengaktifkan mode lewati yang kuat. Mode melewati yang ketat memungkinkan composable dengan parameter yang tidak stabil untuk dilewati dan merupakan cara termudah untuk memperbaiki masalah performa yang disebabkan oleh stabilitas.

Lihat Pelewatan yang ketat untuk informasi selengkapnya.

Membuat class tidak dapat diubah

Anda juga dapat mencoba membuat class yang tidak stabil sepenuhnya tidak dapat diubah.

  • Tidak dapat diubah: Menunjukkan jenis nilai properti yang tidak dapat diubah berubah setelah instance dari jenis tersebut dibuat, dan semua metode transparan secara referensial.
    • Pastikan semua properti class adalah val dan bukan var, dan jenis yang tidak dapat diubah.
    • Jenis primitif seperti String, Int, dan Float selalu tidak dapat diubah.
    • Jika tidak memungkinkan, Anda harus menggunakan status Compose untuk properti yang dapat berubah.
  • Stabil: Menunjukkan jenis yang dapat diubah. Runtime Compose tidak mengetahui jika dan kapan salah satu properti atau metode publik jenis tersebut akan memberikan hasil yang berbeda dari pemanggilan sebelumnya.

Koleksi yang tidak dapat diubah

Alasan umum mengapa Compose menganggap class tidak stabil adalah koleksi. Seperti yang disebutkan di halaman Diagnosis masalah stabilitas, compiler Compose tidak dapat sepenuhnya yakin bahwa koleksi seperti List, Map, dan Set benar-benar tidak dapat diubah dan karena itu menandainya sebagai tidak stabil.

Untuk mengatasi hal ini, Anda dapat menggunakan koleksi yang tidak dapat diubah. Compiler Compose mencakup dukungan untuk Koleksi yang Tidak Dapat Diubah Kotlinx. Ini koleksi dijamin tidak dapat diubah, dan compiler Compose akan memperlakukannya dengan demikian. Library ini masih dalam versi alfa, jadi kemungkinan akan ada perubahan pada API-nya.

Pertimbangkan lagi class yang tidak stabil ini dari kursus Diagnostik stabilitas panduan masalah:

unstable class Snack {
  
  unstable val tags: Set<String>
  
}

Anda dapat membuat tags stabil menggunakan koleksi yang tidak dapat diubah. Di kelas, ubah jenis tags hingga ImmutableSet<String>:

data class Snack{
    
    val tags: ImmutableSet<String> = persistentSetOf()
    
}

Setelahnya, semua parameter class tidak dapat diubah, dan Compose compiler menandai class sebagai stabil.

Anotasi dengan Stable atau Immutable

Jalur yang mungkin untuk menyelesaikan masalah stabilitas adalah dengan menganotasi class yang tidak stabil dengan @Stable atau @Immutable.

Menganotasi class menggantikan apa yang akan dilakukan compiler simpulkan kelas Anda. Hal ini mirip dengan Operator !! di Kotlin. Anda harus sangat berhati-hati tentang cara Anda menggunakan anotasi tersebut. Mengganti perilaku compiler dapat menyebabkan bug yang tidak terduga, seperti composable Anda yang tidak merekomposisi saat yang Anda harapkan.

Jika memungkinkan untuk membuat class Anda stabil tanpa anotasi, Anda harus berusaha mencapai stabilitas dengan cara itu.

Cuplikan berikut memberikan contoh minimal dari class data yang dianotasi sebagai tidak dapat diubah:

@Immutable
data class Snack(

)

Baik Anda menggunakan anotasi @Immutable atau @Stable, compiler Compose menandai class Snack sebagai stabil.

Class 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 dengan class dalam hal jenis koleksi, Compiler Compose selalu menandai parameter jenis List sebagai tidak stabil, bahkan jika itu adalah kumpulan jenis stabil.

Anda tidak dapat menandai tiap parameter sebagai stabil, dan Anda juga tidak dapat menganotasikan dapat selalu dilewati. Ada beberapa jalur ke depan.

Ada beberapa cara untuk mengatasi masalah koleksi yang tidak stabil. Subbagian berikut menguraikan berbagai pendekatan tersebut.

File konfigurasi

Jika Anda bersedia mematuhi kontrak stabilitas di codebase Anda, maka Anda dapat memilih untuk mempertimbangkan koleksi Kotlin sebagai stabil dengan menambahkan kotlin.collections.* ke file konfigurasi stabilitas.

Koleksi yang tidak dapat diubah

Untuk keamanan waktu kompilasi dari ketetapan, Anda dapat menggunakan koleksi yang tidak dapat diubah 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, menggabungkan List dalam class stabil yang dianotasi. Wrapper umum kemungkinan adalah pilihan terbaik untuk ini, bergantung pada kebutuhan Anda.

@Immutable
data class SnackCollection(
   val snacks: List<Snack>
)

Anda kemudian dapat menggunakannya sebagai jenis parameter dalam composable.

@Composable
private fun HighlightedSnacks(
    index: Int,
    snacks: SnackCollection,
    onSnackClick: (Long) -> Unit,
    modifier: Modifier = Modifier
)

Solusi

Setelah melakukan salah satu pendekatan ini, compiler Compose kini menandai HighlightedSnacks Composable 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 sekarang dapat melewati HighlightedSnacks jika tidak ada input telah berubah.

File konfigurasi stabilitas

Mulai dari Compose Compiler 1.5.5, file konfigurasi class untuk stabil dapat diberikan 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 juga didukung. Contoh konfigurasi ditunjukkan di bawah ini:

// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider kotlin collections stable
kotlin.collections.*
// 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 kolom Compose opsi compiler.

Groovy

kotlinOptions {
    freeCompilerArgs += [
            "-P",
            "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
                    project.absolutePath + "/compose_compiler_config.conf"
    ]
}

Kotlin

kotlinOptions {
  freeCompilerArgs += listOf(
      "-P",
      "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
      "${project.absolutePath}/compose_compiler_config.conf"
  )
}

Karena compiler Compose berjalan pada setiap modul dalam project secara terpisah, Anda dapat menyediakan konfigurasi yang berbeda untuk modul yang berbeda jika diperlukan. Atau, miliki satu di level root project Anda dan teruskan jalur tersebut ke ruang lingkup modul ini.

Beberapa modul

Masalah umum lainnya melibatkan arsitektur multi-modul. Compiler Compose hanya bisa menyimpulkan apakah suatu class stabil jika semua jenis non-primitif yang referensinya ditandai secara eksplisit sebagai stabil atau dalam modul yang juga dibuat dengan compiler Compose.

Jika lapisan data Anda berada dalam modul terpisah dari lapisan UI, yang merupakan pendekatan yang disarankan, ini mungkin menjadi masalah yang Anda temui.

Solusi

Untuk mengatasi masalah ini, Anda dapat melakukan salah satu pendekatan berikut:

  1. Tambahkan class ke file konfigurasi Compiler Anda.
  2. Mengaktifkan compiler Compose di modul lapisan data atau memberi tag pada class dengan @Stable atau @Immutable, jika sesuai.
    • Hal ini melibatkan penambahan dependensi Compose ke lapisan data Anda. Namun, hanya dependensi untuk runtime Compose dan bukan untuk Compose-UI.
  3. Dalam modul UI, gabungkan class lapisan data dalam wrapper khusus UI Google Cloud Platform.

Masalah yang sama juga terjadi saat menggunakan {i>library<i} eksternal jika mereka tidak menggunakan Compiler Compose.

Tidak semua composable harus dapat dilewati

Saat berupaya memperbaiki masalah stabilitas, Anda tidak boleh mencoba setiap dan dapat dilewati. Mencoba melakukan hal itu dapat menyebabkan pengoptimalan dini yang menimbulkan lebih banyak masalah daripada perbaikannya.

Ada banyak situasi ketika iklan yang dapat dilewati tidak memiliki manfaat nyata dan dapat menyebabkan kode yang sulit dikelola. Contoh:

  • Composable yang tidak sering direkomposisi, atau sama sekali.
  • Composable yang hanya memanggil composable yang dapat dilewati.
  • Composable dengan sejumlah besar parameter dengan persamaan yang mahal implementasi yang tepat. Dalam hal ini, biaya untuk memeriksa apakah parameter memiliki dapat lebih besar dibandingkan biaya rekomposisi yang murah.

Jika composable dapat dilewati, composable tersebut akan menambahkan overhead kecil yang mungkin tidak berharga anotasi. Anda bahkan dapat menganotasi composable menjadi tidak dapat dimulai ulang jika terjadi di mana Anda menentukan bahwa dapat dilakukan {i>restart<i} membutuhkan lebih banyak {i>overhead<i} daripada manfaatnya.