Android Jetpack Compose Recomposition Nedir? Nasıl kullanılır?

Hikmet Tütüncü
3 min readJul 29, 2024

--

Recomposition, Jetpack Compose’da temel bir kavramdır ve kullanıcı arayüzünün dinamik olarak güncellenmesini sağlar. Bir değer değiştiğinde, belirli UI öğesi (Composable) ekranda yeniden çizilir. Kullanıcı etkileşimleri, veri değişiklikleri veya diğer faktörler sonucu tetiklenebilir.

Composable fonksiyonların davranışını etkileyen veriler state olarak adlandırılır. State değişimi olduğunda ilgili Composable yeniden oluşturulur.

Recomposition

State değiştiğinde, o state’e bağlı olan tüm Composable’ları yeniden çağırır. Bu süreç recomposition olarak adlandırılır.

Örnek bir uygulama olarak ekranda bir sayaç tutup, iki buton ile bu sayaçtaki değeri azaltıp arttırma uygulamasını gözden geçirelim.

@Composable
fun CounterApp() {
val count = remember { mutableStateOf(0) }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally

) {
Text(text = "Count: ${count.value}")
Button(onClick = { count.value++ }) {
Text(text = "Increase")
}
Button(onClick = { count.value-- }) {
Text(text = "Decrease")
}
}
}

Bu kod parçasını incelediğimizde;

count değerinin remember ve mutableStateOf ile oluşturulduğunu görüyoruz. remember ifadesi oluşturulan state’i bir kez oluşturup, sonraki aşamalarda aynı referansı döndürmesini sağlar. Dolayısıyla performans artışı sağlanır. mutableStateOf ise bir state değişkeni oluşturur.

Butonlara tıklandığında count state’inin değeri arttırılır veya azaltılır. Bu değişiklik, bu state’i kullanan Composable fonksiyonların güncellenmesine sebep olur.

Uygulamanın ekran görüntüsü.

Gereksiz Recomposition’dan Kaçınmanın Önemi ve Örnekler

Bir Jetpack Compose uygulamasında performans sorunlarını minimize etmek için gereksiz recomposition kullanımından kaçınmak gerekir. Gereksiz recomposition, uygulamanın akıcılığını düşürebilir ve hatta donmalara neden olabilir.

Neden gereksiz recomposition olur?

  • Çok Sık Değişen State: Bir state değeri çok sık değiştiğinde, ona bağlı olan tüm composable’lar sürekli olarak yeniden oluşturulur.
  • Karmaşık State Hiyerarşisi: Büyük ve karmaşık bir state ağacı, gereksiz recomposition’lara neden olabilir.
  • Yanlış Kullanılan Compose Fonksiyonları: remember veya derivedStateOf gibi fonksiyonlar yanlış kullanıldığında, beklenmedik recomposition'lar oluşabilir.

Gereksiz Recomposition’dan Kaçınma Örnekleri

  1. State Hoisting:

Bir Compose bileşenindeki state’i (durumu) daha üst bir bileşene taşıma işlemidir. Bu, performans iyileştirmeleri, kod tekrarını azaltma ve state yönetimini kolaylaştırma gibi avantajlar sağlar.

@Composable
fun CounterScreenStateHoisting() {
val countState = remember { mutableStateOf(0) }

Column {
Counter(
count = countState.value,
onIncrease = {
countState.value++
},
onDecrease = {
countState.value--
}
)
}
}

@Composable
fun Counter(count: Int, onIncrease: () -> Unit, onDecrease: () -> Unit) {
Text(text = "Count: $count")
Button(onClick = onIncrease) {
Text(text = "Increase")
}
Button(onClick = onDecrease) {
Text(text = "Decrease")
}
}

Bu kod incelendiğinde; bir önceki koddan farklı olarak Counter ayrı bir Composable şeklinde tanımlandığı görülür. Bu Composable içerisinde hiçbir şekilde state değerine erişim yoktur. Counter Composable fonksiyonu sadece bileşeni görüntüleme ve kullanıcı etkileşimini yönetir. Sayacın arttırıp azaltılacağı fonksiyonlar parametre olarak Counter fonksiyonuna verilmiştir. State değerlerinin mümkün oldukça üst katmanda tutulması ve buradan yönetilmesi daha karmaşık uygulamalarda performans düşüşünün önüne geçer.

2. Derived State Kullanımı:

derivedStateOf fonksiyonu, Jetpack Compose’da hesaplanan değerleri tutmak için kullanılan bir mekanizmadır. Bir diğer deyişle, bir state’in değerine bağlı olarak yeni bir state türetmemizi sağlar. Bu sayede, karmaşık hesaplamaların sonucunu tekrar tekrar hesaplamaktan kaçınır ve performansı artırır.

import androidx.compose.runtime.*

@Composable
fun CounterWithSum() {
val count1 = remember { mutableStateOf(0) }
val count2 = remember { mutableStateOf(0) }

val sum = derivedStateOf { count1.value + count2.value }

Text(text = "Toplam: $sum")
}

Bu örnekte görüleceği üzere, sum state’i, count1 ve count2 state’lerine bağlı. Bu state’lerden biri değiştiğinde, sum state’i derivedStateOf içindeki lambda ifadesine göre yeniden düzenlenir ve kaydedilir. Bu şekilde tekrarlanan hesaplamaları önleyerek performansı arttırır. Kodun daha okunaklı olmasını sağlar. Ayrıca kodun bakımını da kolaylaştırır.

Sonuç

Bu yazımda, Jetpack Compose’da recomposition’ın nasıl çalıştığını ve state yönetiminin ne kadar önemli olduğunu gördük. Recomposition, kullanıcı arayüzünü dinamik ve güncel tutmak için güçlü bir araçtır. Gereksiz kullanımının önlenmesi ise uygulamanın performans artışını sağlar.

Daha karmaşık uygulamalarda, state yönetimi için daha gelişmiş teknikler (örneğin, ViewModel, LiveData) kullanılabilir.

Uygulamanın tüm kodlarına buradan ulaşabilirsiniz.

Teşekkürler.

--

--

No responses yet