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

Performans sorunlarına neden olan kararsız bir sınıf ile 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.

Sınıfı sabit hale getirin

İlk olarak kararsız bir sınıfı tamamen sabit hale getirmeyi denemelisiniz.

  • Sabit: Herhangi bir özelliğin değerinin, söz konusu türdeki bir örnek oluşturulduktan sonra asla değişmediği ve tüm yöntemlerin artık ş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 tüm değişken özellikler için Oluşturma durumunu kullanmanız gerekir.
  • Kararlı: Değişebilir olan bir türü belirtir. Compose çalışma zamanı, türün herkese açık mülklerinin veya yöntem davranışının önceki bir çağrıdan farklı sonuçlar verip vermeyeceğini ve ne zaman olacağını 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 olamıyor ve bu nedenle bunları kararsız olarak işaretliyor.

Bu sorunu çözmek için sabit koleksiyonları kullanabilirsiniz. Compose derleyicisi Kotlinx Sabit Koleksiyonları için destek sunar. Bu koleksiyonların değişmez olması garanti edilir ve Compose derleyicisi bunları bu şekilde değerlendirir. 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 şu kararsız sınıfı tekrar ele alın:

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

Sabit bir koleksiyon kullanarak tags uygulaması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 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ız hakkında çıkarımlarını 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, öngörülemeyen hatalara neden olabilir. Örneğin, oluşturduğunuz dosyanın beklediğiniz zamanda yeniden oluşturulamaması gibi.

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çıklamalı 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 derleyici 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 oluşturma örneği düşünün:

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

Snack için @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ürlerden oluşan bir koleksiyon olsa bile geçerlidir.

Tek bir parametreyi kararlı olarak işaretleyemez veya her zaman atlanabilir olacak şekilde oluşturma işlemine ek açıklama ekleyemezsiniz. Birkaç ileriye dönük yol vardır.

Kararsız koleksiyonlar sorununu birkaç şekilde çözebilirsiniz. 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 uymaktan memnunsanız kararlılık yapılandırma dosyanıza kotlin.collections.* ekleyerek Kotlin koleksiyonlarını kararlı olarak kabul edebilirsiniz.

Sabit koleksiyon

Sabitliğin derleme süresinde güvenlik için List yerine bir kotlinx sabit koleksiyonu kullanabilirsiniz.

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

Wrapper

Sabit bir koleksiyonu kullanamıyorsanız kendi koleksiyonunuzu oluşturabilirsiniz. Bunu 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 genel bir sarmalayıcıdır.

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

Daha sonra, bunu oluşturduğunuz oluşturabileceğiniz öğede 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 öğesini 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
)

Yeniden oluşturma sırasında, girişlerinden hiçbiri değişmediyse Compose artık HighlightedSnacks öğesini atlayabilir.

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

Compose Compiler 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 Oluştur 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ı olarak ç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

Sık karşılaşılan diğer bir sorun da çok modüllü mimariyle ilgilidir. Compose derleyicisi, bir sınıfın kararlı olup olmadığını ancak başvuruda bulunduğu tüm ilkel olmayan türlerin açık bir şekilde kararlı olarak veya Compose derleyicisiyle de oluşturulmuş bir modülde işaretlenmiş olması durumunda anlayabilir.

Veri katmanınız, önerilen yaklaşım olan kullanıcı arayüzü katmanından ayrı bir modüldeyse 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 derleyiciyi etkinleştirin veya uygun durumlarda sınıflarınızı @Stable ya da @Immutable ile etiketleyin.
    • Bu işlem, veri katmanınıza Compose bağımlılığı eklemeyi de içerir. 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ıyla sarmalayın.

Oluşturma derleyicisini kullanmayan harici kitaplıklar kullanılırken de aynı sorun ortaya çıkar.

Oluşturulan her içerik atlanabilir olmamalıdır

Kararlılıkla ilgili sorunları düzeltmeye çalışırken, her oluşturma özelliğini atlanabilir hale getirmeye çalışmamalısınız. Bunu yapmaya çalışmak, erken optimizasyona yol açabilir ve bu da, düzelttiğinden daha fazla soruna yol açar.

Atlanabilir olmanın gerçek bir fayda sağlamadığı ve kod yönetiminin zor olduğu birçok durum vardır. Örneğin:

  • Sık sık veya hiç yeniden düzenlenmeyen bir kompozisyon.
  • Kendi başına yalnızca atlanabilir composable öğe çağıran kompozisyon.
  • Çok sayıda parametre içeren ve aynı zamanda pahalı uygulamalara karşılık gelen bir sütun. Bu durumda, herhangi bir parametrenin değişip değişmediğini kontrol etmenin maliyeti, ucuz bir yeniden düzenleme maliyetinden ağır basabilir.

Oluşturulan bir öğe atlanabilir olduğunda, buna değmeyebilecek küçük bir ek yük ekler. Yeniden başlatılabilir olmanın aslında gerekli olandan daha fazla ek yük gerektirdiğini düşündüğünüz durumlarda, oluşturduğunuz oluşturduğunuz içeriğe yeniden başlatılamaz şekilde ek açıklama bile ekleyebilirsiniz.