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 belgede, bunu yapmak için kullanabileceğiniz çeşitli teknikler açıklanmaktadır.

Güçlü atlamayı etkinleştirme

Öncelikle güçlü atlama modunu etkinleştirmeyi denemelisiniz. Güçlü atlama modu, kararsız parametreler içeren composable'ların atlanmasına olanak tanır ve kararlılığın neden olduğu 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

Ayrıca kararsız bir sınıfı tamamen değişmez hale getirmeyi de deneyebilirsiniz.

  • Değişmez: Bu türde, bir örneği oluşturulduktan sonra özelliklerin değeri hiçbir zaman değişmez ve tüm yöntemler referans açısından şeffaftır.
    • Sınıfın tüm özelliklerinin var yerine val olduğundan ve değişmez türde olduğundan emin olun.
    • String, Int ve Float gibi temel türler her zaman sabittir.
    • Bu mümkün değilse değiştirilebilir tüm özellikler için Compose durumunu kullanmanız gerekir.
  • Stable: Değişebilir bir türü gösterir. Compose çalışma zamanı, türün herkese açık özelliklerinden veya yöntem davranışlarından herhangi birinin önceki bir çağırmadan farklı sonuçlar vereceği zamanı ve durumu algılamaz.

Değiştirilemeyen koleksiyonlar

Compose'un bir sınıfı kararsız olarak değerlendirmesinin yaygın bir nedeni 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 değişmez olduğundan tamamen emin olamaz ve bu nedenle bunları kararsız olarak işaretler.

Bu sorunu çözmek için değişmez koleksiyonları kullanabilirsiniz. Compose derleyicisi, Kotlinx Immutable Collections için destek içerir. Bu koleksiyonlar değişmez olacak şekilde tasarlanmıştır ve Compose derleyicisi bunları bu şekilde ele alır. Bu kitaplık hâlâ alfa sürümündedir. Bu nedenle, API'sinde değişiklikler olabilir.

Kararlılık sorunlarını teşhis etme kılavuzundaki bu kararsız sınıfı tekrar göz önünde bulundurun:

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

Değişmez bir koleksiyon kullanarak tags öğesini sabit 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şmez olur ve Compose derleyicisi sınıfı kararlı olarak işaretler.

Stable veya Immutable ile not ekleme

Kararlılık sorunlarını çözmek için kararsız sınıflara @Stable veya @Immutable ekleyebilirsiniz.

Bir sınıfı açıklama eklemek, derleyicinin sınıfınız hakkında çıkarım yapmasını geçersiz kılar. Bu, !! Kotlin operatörüne benzer. Bu ek açıklamaları nasıl kullandığınız konusunda çok dikkatli olmalısınız. Derleyici davranışını geçersiz kılmak, composable'ınızın yeniden oluşturulmaması gibi beklenmedik hatalara yol açabilir.

Sınıfınızı açıklama olmadan kararlı hale getirmek mümkünse bu şekilde kararlılık elde etmeye çalışmalısınız.

Aşağıdaki snippet, değişmez olarak ek açıklama eklenmiş bir veri sınıfının en basit örneğini sunar:

@Immutable
data class Snack(

)

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

Koleksiyonlardaki ek açıklama içeren sınıflar

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

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

Snack öğesini @Immutable ile açıklama 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şı karşıyadır. Compose derleyicisi, kararlı türlerin koleksiyonu olsa bile List türündeki bir parametreyi her zaman kararsız olarak işaretler.

Tek bir parametreyi kararlı olarak işaretleyemez veya birleştirilebilir bir öğeyi her zaman atlanabilir olacak şekilde açıklama ekleyemezsiniz. İlerlemek için birden fazla yol vardır.

Kararsız koleksiyonlar 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 uymaktan memnunsanız kararlılık yapılandırma dosyanıza kotlin.collections.* ekleyerek Kotlin koleksiyonlarının kararlı olarak kabul edilmesini etkinleştirebilirsiniz.

Değişmez koleksiyon

Değişmezlik için derleme süresi güvenliği sağlamak amacıyla List yerine kotlinx immutable collection kullanabilirsiniz.

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

Wrapper

Değişmez bir koleksiyon kullanamıyorsanız kendinizinkini oluşturabilirsiniz. Bunu yapmak için List öğesini açıklama eklenmiş sabit bir sınıfa sarın. İhtiyaçlarınıza bağlı olarak, bu işlem için genel bir sarmalayıcı en iyi seçenek olabilir.

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

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

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

Çözüm

Bu yaklaşımlardan birini uyguladıktan sonra Compose derleyicisi artık 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
)

Compose, yeniden oluşturma sırasında girişlerinden hiçbiri değişmediyse HighlightedSnacks atlayabilir.

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

Compose Compiler 1.5.5'ten itibaren, derleme sırasında kararlı olarak kabul edilecek 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ın kararlı olarak kabul edilmesini sağlar.

Yapılandırma dosyası, satır başına bir sınıf içeren düz metin dosyasıdır. Yorumlar, tekli ve çiftli 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 eklentisi yapılandırmasının composeCompiler seçenekler bloğuna iletin.

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

Compose derleyicisi 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ırma oluşturup bu yolu her modüle iletebilirsiniz.

Birden fazla modül

Sık karşılaşılan bir diğer sorun ise çok modüllü mimariyle ilgilidir. Compose derleyicisi, yalnızca referans verdiği ilkel olmayan tüm türler açıkça kararlı olarak işaretlenmişse veya Compose derleyicisiyle de oluşturulmuş bir modüldeyse bir sınıfın kararlı olup olmadığını çıkarabilir.

Veri katmanınız, kullanıcı arayüzü katmanınızdan ayrı bir modüldeyse (önerilen yaklaşım budur) bu sorunla karşılaşabilirsiniz.

Çözüm

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

  1. Sınıfları derleyici yapılandırma dosyanıza ekleyin.
  2. Veri katmanı modüllerinizde Compose derleyicisini etkinleştirin veya sınıflarınızı uygun yerlerde @Stable ya da @Immutable ile etiketleyin.
    • Bu işlem, veri katmanınıza bir Compose bağımlılığı eklemeyi içerir. Ancak bu yalnızca Compose çalışma zamanının bağımlılığıdır ve Compose-UI için değildir.
  3. Kullanıcı arayüzü modülünüzde, veri katmanı sınıflarınızı kullanıcı arayüzüne özgü sarmalayıcı sınıflara yerleştirin.

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

Her composable atlanabilir olmamalıdır.

Kararlılıkla ilgili sorunları düzeltmeye çalışırken her composable'ı atlanabilir yapmaya çalışmamalısınız. Bunu yapmaya çalışmak, düzeltilenden daha fazla soruna yol açan erken optimizasyona neden olabilir.

Atlanabilir olmanın gerçek bir fayda sağlamadığı ve bakımı zor kodlara yol açabileceği birçok durum vardır. Örneğin:

  • Sık sık veya hiç yeniden oluşturulmayan bir composable.
  • Kendi içinde yalnızca atlanabilir composable'ları çağıran bir composable.
  • Çok sayıda parametreye sahip ve pahalı eşitlik uygulamaları olan bir composable. Bu durumda, herhangi bir parametrenin değişip değişmediğini kontrol etmenin maliyeti, ucuz bir yeniden oluşturmanın maliyetinden daha yüksek olabilir.

Bir composable'ın atlanabilir olması, değmeyebilecek küçük bir ek yük oluşturur. Hatta yeniden başlatılabilir olmanın değeceğinden daha fazla ek yük oluşturduğunu belirlediğiniz durumlarda composable'ınızı non-restartable (yeniden başlatılamaz) olarak da ek açıklama ekleyebilirsiniz.