Kararlılık sorunlarını düzeltin

Performans sorunlarına neden olan kararsız bir sınıfla karşılaştığınızda sınıfı kararlı hale getirmeniz gerekir. Bu dokümanda, bunu yapmak için kullanabileceğiniz çeşitli teknikler özetlenmektedir.

Güçlü atlama özelliğini etkinleştir

Öncelikle güçlü atlama modunu etkinleştirmeyi denemelisiniz. Güçlü atlama modu, kararsız parametrelere sahip composable'ların atlanmasına olanak tanır ve kararlılıktan kaynaklanan performans sorunlarını düzeltmenin en kolay yöntemidir.

Daha fazla bilgi için Güçlü atlama konusuna bakın.

Sınıfı sabit hale getirin

Kararsız bir sınıfı tamamen değiştirilemez hale getirmeyi de deneyebilirsiniz.

  • Sabit: İlgili türdeki bir örnek oluşturulduktan sonra herhangi bir özelliğin değerinin hiçbir zaman değiştirilemeyeceği ve tüm yöntemlerin şeffaf olduğu bir türü belirtir.
    • Sınıfın tüm özelliklerinin var yerine val ve sabit türde olduğundan emin olun.
    • String, Int ve Float gibi temel türler her zaman sabittir.
    • Bu imkansızsa değişken özellikler için Oluştur durumunu kullanmanız gerekir.
  • Kararlı: Değişebilir olan bir türü gösterir. Compose çalışma zamanı, türün herkese açık mülklerinin veya yöntem davranışının bir önceki çağrıdan farklı sonuçlar verip vermeyeceğini ve ne zaman gerçekleşeceğini bilmez.

Sabit koleksiyonlar

Compose'un bir sınıfı kararsız olarak kabul etmesinin yaygın bir nedeni koleksiyonlardır. Kararlılık sorunlarını teşhis edin sayfasında belirtildiği gibi, Compose derleyicisi List, Map ve Set gibi koleksiyonların gerçekten sabit olduğundan tam olarak emin olamaz ve bu nedenle onları kararsız olarak işaretler.

Bu sorunu çözmek için sabit koleksiyonları kullanabilirsiniz. Compose derleyicisi Kotlinx Sabit Koleksiyonları için destek içerir. Bu koleksiyonların sabit olduğu garanti edilir ve Compose derleyicisi bunları bu şekilde ele alır. Bu kitaplık hâlâ alfa sürümünde olduğundan API'sinde değişiklikler olabilir.

Kararlılık sorunlarını teşhis etme kılavuzundaki bu kararsız sınıfı tekrar inceleyin:

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

Sabit bir koleksiyon kullanarak tags ürününü kararlı hale getirebilirsiniz. Sınıfta, tags türünü ImmutableSet<String> olarak değiştirin:

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

Bunu yaptıktan sonra, sınıfın tüm parametreleri sabit kalır ve Compose derleyicisi sınıfı kararlı olarak işaretler.

Stable veya Immutable ile ek açıklama ekleyin

Kararlılık sorunlarını çözmenin olası bir yolu, kararsız sınıflara @Stable veya @Immutable ile ek açıklama eklemektir.

Bir sınıfa ek açıklama eklemek, derleyicinin normalde sınıfınızla ilgili olarak tahminde bulunacağı şeyi geçersiz kılar. Kotlin'deki !! operatörüne benzer. Bu ek açıklamaları nasıl kullandığınıza çok dikkat etmelisiniz. Derleyici davranışını geçersiz kılmak, composable'ınızın beklediğiniz zamanda yeniden oluşturmaması gibi öngörülemeyen hatalara yol açabilir.

Sınıfınızı ek açıklama olmadan kararlı hale getirmek mümkünse bu şekilde istikrarı sağlamaya çalışmalısınız.

Aşağıdaki snippet, sabit olarak ek açıklamaya sahip bir veri sınıfının minimal bir örneğini sunmaktadır:

@Immutable
data class Snack(
…
)

@Immutable veya @Stable ek açıklaması kullanmanızdan bağımsız olarak Compose derleyicisi Snack sınıfını kararlı olarak işaretler.

Koleksiyonlardaki ek açıklamalı sınıflar

List<Snack> türünde parametre içeren bir composable düşünün:

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  …
  unstable snacks: List<Snack>
  …
)

Snack öğesine @Immutable ek açıklaması ekleseniz bile Compose derleyicisi, HighlightedSnacks içindeki snacks parametresini kararsız olarak işaretler.

Parametreler, koleksiyon türleri söz konusu olduğunda sınıflarla aynı sorunla karşılaşır. Compose derleyicisi, List türündeki bir parametreyi her zaman kararsız olarak işaretler. Bu, kararlı türlerin bir koleksiyonu olsa bile geçerlidir.

Tek bir parametreyi kararlı olarak işaretleyemez veya her zaman atlanabilir olması için bir composable'a ek açıklama ekleyemezsiniz. Bu süreçte birden fazla yol mevcuttur.

Kararsız koleksiyon sorununu çözmenin birkaç yolu vardır. Aşağıdaki alt bölümlerde bu farklı yaklaşımlar özetlenmektedir.

Yapılandırma dosyası

Kod tabanınızdaki kararlılık sözleşmesine bağlı kalmak isterseniz kararlılık yapılandırma dosyanıza kotlin.collections.* ekleyerek Kotlin koleksiyonlarını kararlı olarak değerlendirebilirsiniz.

Sabit koleksiyon

Sabitliğin derleme zamanı güvenliği için List yerine bir kotlinx sabit koleksiyonu kullanabilirsiniz.

@Composable
private fun HighlightedSnacks(
    …
    snacks: ImmutableList<Snack>,
    …
)

Wrapper

Sabit bir koleksiyon kullanamıyorsanız, kendi koleksiyonunuzu oluşturabilirsiniz. Bu işlemi yapmak için List öğesini ek açıklamalı bir kararlı sınıfta sarmalayın. Gereksinimlerinize bağlı olarak bunun için en iyi seçenek büyük olasılıkla genel bir sarmalayıcıdır.

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

Daha sonra bunu composable'ınızda parametrenin türü olarak kullanabilirsiniz.

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

Çözüm

Bu yaklaşımlardan herhangi birini uyguladıktan sonra Compose derleyicisi artık HighlightedSnacks Composable'ı hem skippable hem de restartable olarak işaretler.

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
)

Yeniden oluşturma sırasında, girişlerinin hiçbiri değiştirilmemişse Compose artık HighlightedSnacks'i atlayabilir.

Kararlılık yapılandırma dosyası

Compose Derleyici 1.5.5'ten itibaren derleme sırasında kararlı olarak değerlendirilecek sınıfların yapılandırma dosyası sağlanabilir. Bu, LocalDateTime gibi standart kitaplık sınıfları gibi kontrol etmediğiniz sınıfları kararlı olarak değerlendirmenize olanak tanır.

Yapılandırma dosyası, satır başına bir sınıf içeren bir düz metin dosyasıdır. Yorumlar, tek ve çift joker karakterler desteklenir. Aşağıda örnek bir yapılandırma gösterilmektedir:

// 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<*,_>

Bu özelliği etkinleştirmek için yapılandırma dosyasının yolunu Compose derleyici seçeneklerine iletin.

Modern

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"
  )
}

Compose derleyicisi projenizdeki her modülde ayrı ayrı çalıştığından, gerekirse farklı modüller için farklı yapılandırmalar sağlayabilirsiniz. Alternatif olarak, projenizin kök düzeyinde bir yapılandırmaya sahip olabilir ve bu yolu her modüle iletebilirsiniz.

Birden çok modül

Yaygın olarak karşılaşılan diğer bir sorun da çok modüllü mimariyle ilgilidir. Compose derleyicisi, bir sınıfın kararlı olup olmadığını belirleyebilmesi için sınıfın başvurduğu tüm temel olmayan türlerin açık bir şekilde kararlı olarak veya Compose derleyicisiyle de oluşturulmuş bir modülde işaretlenmesi gerekir.

Veri katmanınız, önerilen yaklaşım olan kullanıcı arayüzü katmanından ayrı bir modülde bulunuyorsa bu, karşılaştığınız bir sorun olabilir.

Çözüm

Bu sorunu çözmek için aşağıdaki yaklaşımlardan birini uygulayabilirsiniz:

  1. Sınıfları Derleyici yapılandırma dosyanıza ekleyin.
  2. Veri katmanı modüllerinizde Compose derleyicisini etkinleştirin veya uygun durumlarda sınıflarınızı @Stable ya da @Immutable ile etiketleyin.
    • Veri katmanınıza Compose bağımlılığı eklemek buna dahildir. Ancak bu, Compose-UI için değil, yalnızca Compose çalışma zamanının bağımlılığıdır.
  3. Kullanıcı arayüzü modülünüzde, veri katmanı sınıflarınızı kullanıcı arayüzüne özel sarmalayıcı sınıflarına sarmalayın.

Aynı sorun, Composer derleyicisini kullanmayan harici kitaplıklar kullanılırken de ortaya çıkar.

Her composable atlanamaz

Kararlılıkla ilgili sorunları düzeltmeye çalışırken, her composable'ı atlanabilir hâle getirmeye çalışmamalısınız. Bunu yapmaya çalışmak, erken optimizasyona yol açabilir ve bu da, düzelttiğinden çok soruna yol açar.

Atlanabilir olmanın gerçek bir avantaj sağlamadığı ve kodun sürdürülmesinin zor olduğu birçok durum vardır. Örnek:

  • Sık sık veya hiç yeniden düzenlenmeyen bir composable.
  • Tek başına atlanabilir composable'lar çağıran bir composable.
  • Bir composable, çok sayıda parametreye sahip olup pahalı ve eşit uygulamalara sahiptir. Bu durumda, herhangi bir parametrenin değişip değişmediğini kontrol etmenin maliyeti, ucuz bir yeniden düzenleme maliyetinden ağır basabilir.

Bir composable, atlanabilir olduğunda buna değmeyebilecek küçük bir ek yük getirir. Yeniden başlatılabilir olmanın, gereğinden fazla ek yük gerektirdiğini düşündüğünüz durumlarda, composable'ınıza yeniden başlatılamaz olacak şekilde ek açıklama ekleyebilirsiniz.