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 özetlenmektedir.

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ür, bir örneği oluşturulduktan sonra özelliklerinin değerinin asla değişemeyeceği ve tüm yöntemlerin referans açısından şeffaf olduğu bir türü ifade eder.
    • 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ştirilebilir 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 verip vermeyeceğini ve ne zaman vereceğini bilmez.

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 desteği içerir. Bu koleksiyonların değişmez olduğu garanti edilir 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, beklenmedik hatalara yol açabilir. Örneğin, composable'ınızın yeniden oluşturulmasını beklediğinizde yeniden oluşturulmayabilir.

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ız fark etmeksizin Compose derleyicisi, Snack sınıfını kararlı olarak işaretler.

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

List<Snack> türünde bir parametre içeren bir composable'ı ele alalım:

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

Snack öğesine @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 bir composable'ı 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 uymak istiyorsanı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 kendi koleksiyonunuzu oluşturabilirsiniz. Bunu yapmak için List öğesini açıklama eklenmiş sabit bir sınıfa sarmalayın. Bu işlem için, gereksinimlerinize bağlı olarak 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
)

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 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ı, her satırda bir sınıf olacak şekilde 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ı için geçerli olan bir bağımlılıktır ve Compose-UI için geçerli 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 bir composable'ı atlanabilir yapmaya çalışmamalısınız. Bunu yapmaya çalışmak, düzeltmekten 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.
  • Pahalı eşitlik uygulamaları olan çok sayıda parametreye sahip 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 atlanabilir olduğunda küçük bir ek yük oluşturur. Bu ek yük, atlanabilir olmanın avantajlarına değmeyebilir. Hatta yeniden başlatılabilir olmanın, değerinden daha fazla ek yük getirdiğini düşündüğünüz durumlarda composable'ınızı yeniden başlatılamaz olarak işaretleyebilirsiniz.