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

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

Güçlü atlamayı 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 bölümüne bakın.

Sınıfı değiştirilemez hale getirme

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

  • Değişmez: Bu tür bir örneği oluşturulduktan sonra özelliklerin değerinin hiçbir zaman değişemeyeceği ve tüm yöntemlerin referans açısından şeffaf olduğu bir türü gösterir.
    • Sınıfın tüm özelliklerinin var yerine val olduğundan ve değiştirilemez türde olduğundan emin olun.
    • String, Int ve Float gibi ilkel türler her zaman değiştirilemez.
    • Bu mümkün değilse tüm değiştirilebilir özellikler için Compose durumunu kullanmanız gerekir.
  • Kararlı: Değişebilir bir türü belirtir. Compose çalışma zamanı, türün herkese açık özelliklerinden veya yöntem davranışlarından herhangi birinin önceki bir çağrıdan farklı sonuçlar verip vermeyeceğini ve ne zaman vereceğini bilemez.

Sabit koleksiyonlar

Compose'un bir sınıfı kararsız olarak kabul etmesinin yaygın nedenlerinden biri koleksiyonlardır. Kararlılık sorunlarını teşhis etme 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 bu koleksiyonları 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 değiştirilemez olması garanti edilir. Compose derleyicisi de bu koleksiyonları bu şekilde ele alır. Bu kitaplık hâlâ alfa sürümünde olduğundan API'sinde olası 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()
    …
}

Bu işlemden sonra sınıfın tüm parametreleri değiştirilemez hale gelir ve Compose derleyicisi sınıfı kararlı olarak işaretler.

Stable veya Immutable ile not ekleyin

Kararlılık sorunlarını çözmenin bir yolu, kararsız sınıfları @Stable veya @Immutable ile açıklamaktır.

Bir sınıfa not eklemek, derleyicinin sınıfınız hakkında tahmin edeceği bilgileri geçersiz kılar. Bu operatör, !! Kotlin operatörüne benzer. Bu ek açıklamaları nasıl kullanacağınıza çok dikkat etmeniz gerekir. Derleyici davranışını geçersiz kılmak, beklenmedik hatalara (ör. bileşeninizin beklediğinizde yeniden derlenmemesi) neden olabilir.

Sınıfınızı ek açıklama olmadan kararlı hale getirmek mümkünse bu şekilde kararlılık sağlamak için çaba göstermeniz gerekir.

Aşağıdaki snippet, sabit olarak ek açıklama verilen bir veri sınıfının minimum bir örneğini sağlar:

@Immutable
data class Snack(
…
)

İster @Immutable ister @Stable ek açıklamasını kullanın, 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@Immutable ile ek açıklamayla belirtseniz bile Derleme derleyicisi, HighlightedSnacks'daki snacks parametresini kararsız olarak işaretlemeye devam eder.

Koleksiyon türleri söz konusu olduğunda parametreler, sınıflarla aynı sorunla karşılaşır. Compose derleyicisi, kararlı türlerden oluşan bir koleksiyon olsa bile List türündeki bir parametreyi her zaman kararsız olarak işaretler.

Tek bir parametreyi sabit olarak işaretleyemez veya her zaman atlanabilir olacak şekilde bir composable'a ek açıklama ekleyemezsiniz. İleriye doğru birden fazla yol var.

Kararsız koleksiyon sorununu çözmenin çeşitli yolları vardır. Aşağıdaki alt bölümlerde bu farklı yaklaşımlar özetlenmiştir.

Yapılandırma dosyası

Kod tabanınızdaki kararlılık sözleşmesine uymaktan memnunsanız kararlılık yapılandırma dosyanıza kotlin.collections.* ekleyerek Kotlin koleksiyonlarını kararlı olarak kabul edebilirsiniz.

Sabit koleksiyon

Değişmezlik için derleme zamanında güvenlik sağlamak istiyorsanız List yerine kotlinx immutable koleksiyonunu kullanabilirsiniz.

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

Wrapper

Sabit bir koleksiyon kullanamıyorsanız kendi koleksiyonunuzu oluşturabilirsiniz. Bunun için List öğesini, ek açıklamalı bir kararlı sınıfa sarmalayın. İhtiyaçlarınıza bağlı olarak, bunun için muhtemelen en iyi seçenek genel bir sarmalayıcıdır.

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

Daha sonra bunu composable'ınızdaki parametre türü olarak kullanabilirsiniz.

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

Çözüm

Bu yaklaşımlardan herhangi biri uygulandıktan sonra, Compose derleyicisi HighlightedSnacks Composable'ı hem skippable hem de restartable olarak işaretliyor.

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
)

Oluşturma işlemi sırasında, girişlerinden hiçbiri değişmediyse Oluştur artık HighlightedSnacks öğesini atlayabilir.

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

Compose Compiler 1.5.5 ile başlayarak, kararlı olarak değerlendirilecek sınıfların bir yapılandırma dosyası, derleme sırasında sağlanabilir. Bu sayede, LocalDateTime gibi standart kitaplık sınıfları gibi sizin kontrol etmediğiniz sınıfları kararlı olarak değerlendirebilirsiniz.

Yapılandırma dosyası, her satırda bir sınıf bulunan bir düz metin dosyasıdır. Yorumlar, tek ve çift joker karakterler desteklenir. Örnek yapılandırma:

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

Bu özelliği etkinleştirmek için yapılandırma dosyasının yolunu Compose derleyici Gradle eklentisinin composeCompiler seçenekler bloğuna aktarın.

composeCompiler {
  stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
}

Compose derleyici, projenizdeki her modülde ayrı ayrı çalıştığından, gerekirse farklı modüllere 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 fazla modül

Sık karşılaşılan bir diğer sorun da çok modüllü mimaridir. Compose derleyicisi, yalnızca referans verdiği ilkel olmayan türlerin tümü açıkça kararlı olarak işaretlenmişse veya Compose derleyicisiyle de derlenmiş bir modüldeyse bir sınıfın kararlı olup olmadığını anlayabilir.

Veri katmanınız, önerilen yaklaşım olan kullanıcı arayüzü katmanınızdan ayrı bir modülde ise bu sorunla karşılaşabilirsiniz.

Çö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 derleyiciyi etkinleştirin veya uygun durumlarda sınıflarınızı @Stable ya da @Immutable ile etiketleyin.
    • Bu işlem, veri katmanınıza bir Compose bağımlılığı eklemeyi içerir. Ancak bu, Compose-UI için değil, yalnızca Compose çalışma zamanı için bir bağımlılıktır.
  3. Kullanıcı arayüzü modülünde, veri katmanı sınıflarınızı kullanıcı arayüzüne özel sarmalayıcı sınıflarıyla sarmalayın.

Aynı sorun, harici kitaplıklarda Compose derleyicisi kullanılmadığında da ortaya çıkar.

Her composable atlanabilir olmamalıdır

Kararlılıkla ilgili sorunları düzeltmeye çalışırken her bir bileşiği atlanabilir hale getirmeye çalışmamalısınız. Bunu yapmaya çalışmak, düzelttiğinden daha fazla soruna yol açan erken optimizasyona neden olabilir.

Atlanabilir olmanın gerçek bir avantaj sağlamadığı ve kod yönetiminin zorlaşmasına yol açabildiği birçok durum vardır. Örnek:

  • Sık sık veya hiç yeniden bestelenmeyen bir composable.
  • Kendi başına yalnızca atlanabilir derlenebilir öğeleri çağıran bir derlenebilir öğe.
  • Pahalı eşittir uygulamalarının bulunduğu çok sayıda parametre içeren bir bileşen. Bu durumda, herhangi bir parametrenin değişip değişmediğini kontrol etmenin maliyeti, ucuz bir yeniden derlemenin maliyetinden daha yüksek olabilir.

Atlanabilir bir composable, buna değmeyebilecek küçük bir ek yük ekler. Hatta, yeniden başlatılabilir olmanın maliyetinin avantajından daha fazla olduğunu belirlediğiniz durumlarda bile, bileşeninizi yeniden başlatılamaz olarak ek açıklamayla belirtebilirsiniz.