Recomposition — nedir, durum değiştiğinde UI'ın yeniden oluşturulması

Yazar: IT Sectr Yayınlanma: 2026-06-27 Okuma süresi: 7 dk

Recomposition, veri değiştiğinde kullanıcı arayüzünün parçalarını manuel View güncellemesi olmadan otomatik olarak yeniden oluşturan bir Jetpack Compose mekanizmasıdır. Bir Composable fonksiyonunun bağlı olduğu durum değişkeni değerini değiştirdiğinde, Compose yalnızca bu fonksiyonu yeniden başlatır ve UI ağacının geri kalanını dokunulmamış bırakır. Google Android Developers, 2026'ya göre, Recomposition'ı doğru anlamak gereksiz yeniden çizimleri %40–60 oranında azaltmaya olanak tanır.

Ana Noktalar

  • Recomposition — girdi verileri veya Durum değiştiğinde Composable fonksiyonlarının yeniden başlatılması
  • Skipping — parametreleri değişmeyen fonksiyonların atlanması (equals ile karşılaştırma)
  • Stability, Compose'un bir fonksiyonu atlayıp atlayamayacağını belirler — kararlı türler doğru şekilde karşılaştırılır
  • Smart Recomposition tüm ağacı değil, yalnızca minimum fonksiyon kümesini yeniden başlatır
  • Yeniden kompozisyon yeniden çizimi garanti etmez — Layout ve Drawing aşamalarını atlayabilir

Jetpack Compose'da Recomposition Nedir

Recomposition, daha önce Composition'a katılmış Composable fonksiyonlarının yeni parametre veya durum değerleriyle yeniden yürütülmesidir. Yeniden kompozisyonun temel amacı, tüm arayüzü sıfırdan yeniden oluşturmadan UI ağacını mevcut verilerle senkronize etmektir. Bir kez gerçekleşen Composition'ın aksine, Recomposition bir ekranın ömrü boyunca yüzlerce kez tetiklenebilir.

Recomposition, akıllı geçersiz kılma prensibiyle çalışır: Compose, her Composable fonksiyonunun hangi State nesnelerini okuduğunu izler ve yalnızca bağımlılıkları değişenleri yeniden başlatma için işaretler. Bu, yürütme sırasında tüm State okuma işlemlerini kaydeden bir snapshot sistemi ve bu bağımlılıkları belirli fonksiyonlara eşleyen bir Composer aracılığıyla elde edilir.

Anlaşılması önemlidir: yeniden kompozisyon anında ekran yeniden çizimi anlamına gelmez. Compose üç aşamada çalışır: Composition (UI tanımını oluşturma), Layout (boyutları ve konumları hesaplama) ve Drawing (tuval üzerine işleme). Yeniden kompozisyondan sonra öğelerin boyutları ve konumları değişmediyse, Layout aşaması atlanabilir. Görsel görünüm değişmediyse — Drawing atlanır. Bu üç aşamalı mimari, her UI güncellemesi için minimum maliyet sağlar.

Yeniden Kompozisyon Tetikleyicileri: Fonksiyon Yeniden Başlatma Nedenleri

Yeniden kompozisyon için üç ana tetikleyici vardır. Birincisi, bir Composable fonksiyonunun gövdesinde okunan bir State nesnesindeki değişikliktir. mutableStateOf veya derivedStateOf değerini değiştirdiğinde, önceki kompozisyonda bu State'i okuduğunu kaydeden tüm fonksiyonlar yeniden başlatma için işaretlenir.

İkinci tetikleyici, bir üst fonksiyondan çağrıldığında Composable fonksiyonunun parametre değişikliğidir. Üst fonksiyon yeni bir değer aktarırsa (örneğin, metin veya sayı değişti), alt fonksiyon dahili olarak State okumasa bile yeniden başlatılacaktır. Compose, yeni ve eski parametre değerlerini equals aracılığıyla karşılaştırır ve eşitse — fonksiyon atlanabilir.

Üçüncü tetikleyici, CompositionLocalProvider aracılığıyla CompositionLocal değişikliğidir. .current aracılığıyla CompositionLocal okuyan tüm fonksiyonlar, sağlayıcı değiştiğinde yeniden başlatılır. Bu mekanizma MaterialTheme tarafından kullanılır: tema değişikliği (açık/koyu), MaterialTheme.colorScheme okuyan tüm bileşenlerin yeniden kompozisyonuna neden olur.

kotlin
@Composable
fun RecompositionDemo() {
    var counter by remember { mutableStateOf(0) }
    var text by remember { mutableStateOf("Hello") }

    Column {
        Text("Counter: $counter")  // recomposition when counter changes
        Text("Message: $text")    // recomposition when text changes

        Button(onClick = { counter++ }) {
            Text("+1")
        }
        Button(onClick = { text = "World" }) {
            Text("Change Text")
        }
    }
}

+1 düğmesine tıklamak counter'ı değiştirir, yalnızca ilk Text satırının ve Column'ın yeniden kompozisyonuna neden olur. Metni görüntüleyen ikinci Text satırı yeniden başlamaz. Bu izolasyon, snapshot sisteminin sonucudur: her Composable fonksiyon yalnızca okuduğu State nesnelerini bilir.

Yeniden Kompozisyonu Optimize Etme: Pratik Teknikler

Yeniden kompozisyon optimizasyonu, doğru veri yapılarını seçmekle başlar. Değişebilir koleksiyonlar (mutableListOf) yerine değişmez koleksiyonlar (listOf, mapOf) kullanın. Compose, parametreleri equals aracılığıyla karşılaştırır ve bir koleksiyon değiştiyse ancak equals true döndürdüyse — fonksiyon yeniden başlamaz. Değişebilir koleksiyonlar için, öğe düzeyinde doğru değişiklik izleme uygulayan SnapshotStateList kullanın.

İkinci teknik, UI'ın kararlı kısımlarını ayrı Composable fonksiyonlara çıkarmaktır. Ekranın bir kısmı sık değişen duruma bağlı değilse, parametrelerle ayrı bir fonksiyona çıkarın. Yeniden kompozisyon oluştuğunda, kararlı fonksiyon aynı parametreleri alır, Compose bunları karşılaştırır ve yürütmeyi atlar. Bu, bazı parametrelerin değiştiği büyük bir fonksiyonun parçası olarak o kısmı yeniden başlatmaktan daha verimlidir.

Üçüncü teknik, LazyColumn'da anahtarlardır. LazyColumn, LazyGrid ve diğer tembel kapsayıcılardaki öğeler için her zaman bir anahtar belirtin. Anahtar, liste değiştiğinde (ekleme, çıkarma veya yeniden sıralama) Compose'un öğeleri tanımlamasını sağlar. Anahtar olmadan, Compose herhangi bir değişiklikte listenin tüm öğelerini yeniden başlatır, bu da büyük listelerde gözle görülür performans düşüşüne neden olur.

kotlin
// Optimized structure: stable parts extracted separately
@Composable
fun OptimizedScreen(items: List<Item>) {
    Column {
        Header()                         // does not depend on items — no recomposition
        Spacer(modifier = Modifier.height(8.dp))
        LazyColumn {
            items(items, key = { it.id }) { item ->
                ItemRow(item = item)   // recomposition only for changed items
            }
        }
    }
}

@Composable
fun Header() {
    Text("Item list", style = MaterialTheme.typography.headlineMedium)
}

@Composable
fun ItemRow(item: Item) {
    Text(item.title)
}

Compose'da Skipping ve Stability

Skipping, tüm parametreleri değişmediyse Compose'un bir Composable fonksiyonunun yürütülmesini atladığı bir mekanizmadır. Skipping'in doğru çalışması için parametre türleri kararlı (stable) olmalıdır. Kotlin derleyicisi şunları kararlı olarak işaretler: ilkel türler (Int, Float, Boolean), String, lambda fonksiyonları ve tüm alanları kararlı ve val olan sınıflar.

Stability, özel veri sınıflarına eklenebilen @Stable veya @Immutable notasyonudur. Bir sınıf değişebilir alan (var) içeriyorsa, derleyici onu kararsız olarak kabul eder ve Compose bu tür parametrelere sahip fonksiyonları atlayamaz. Var olan sınıflar için, değişiklik bildiriminin snapshot sistemi aracılığıyla gönderileceğini garanti ediyorsanız @Stable kullanın.

Kararlılığı, derleyici bayrağı -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports" ile kontrol edebilirsiniz. Tüm Composable fonksiyonların ve parametrelerinin bir listesini kararlılıkla birlikte oluşturur. Bir parametre kararsızsa — bu fonksiyon için skipping imkansızdır ve her üst yeniden kompozisyonda yeniden başlatılır.

TürKararlılıkSkipping
Int, Float, BooleanKararlıEvet
StringKararlıEvet
LambdaKararlıEvet
val alanlı data classKararlıEvet
var alanlı data classKararsızHayır
List<String>KararsızHayır

Not: List<String>, bir arayüz olduğu için somut bir uygulama olmadığından kararsız kabul edilir. Kotlin Collections Immutable kütüphanesinden immutableListOf() kullanın veya listeyi bir @Stable sınıfına sarın. Lambda her zaman kararlıdır çünkü equals'ı yalnızca referansları karşılaştırır ve çağrı noktasında yeni bir lambda oluşturulduğunda üst fonksiyon da yeniden başlatılır.

Android Studio'da Yeniden Kompozisyonu İzleme

Yeniden kompozisyonu izlemek için Android Studio, Compose Recomposition Counts moduyla Layout Inspector sağlar. Bu modda, her Composable fonksiyon yeniden kompozisyon sayısını ve yeniden başlatma nedenlerini görüntüler. Bu, çok sık yeniden kompoze olan fonksiyonları hızlıca bulmanızı ve temel nedeni belirlemenizi sağlar — kararsız parametreler veya gereksiz State bağımlılıkları.

Ek araçlar: Compose Metrics(instrumentasyon testleri aracılığıyla istatistik toplama) ve Recomposition Timer (her fonksiyonun yürütme süresini ölçme). Google, bu araçların profil oluşturma aşamasında etkinleştirilmesini ve sürüm derlemelerinde devre dışı bırakılmasını önerir, çünkü her yeniden kompozisyon başına %20'ye kadar ek yük eklerler.

Yeniden kompozisyonları analiz ederken, gereksiz yeniden kompozisyon kalıplarını arayın: çıktı UI'ı değişmemesi gerekmesine rağmen bir fonksiyon yeniden başlar. Yaygın bir neden, her seferinde yeni bir lambda nesnesinin oluşturulduğu ve Compose'un parametrenin değiştiğini düşündüğü remember olmadan lambda kullanımıdır. Çözüm: sabit yakalamalarla remember { } içine lambda sarın.

kotlin
// Bad: new lambda on every parent recomposition
@Composable
fun Parent() {
    Child(onClick = { doSomething() })  // new lambda every time
}

// Good: remember stabilizes the lambda
@Composable
fun Parent() {
    val onClick = remember { { doSomething() } }
    Child(onClick = onClick)  // same reference
}

Sıkça Sorulan Sorular

Yeniden kompozisyon ekranın yeniden çizilmesi anlamına mı gelir?

Hayır, yeniden kompozisyon yalnızca Composition aşamasıdır. Ardından Layout ve Drawing yürütülür. Yeniden kompozisyondan sonra öğelerin boyutları ve konumları değişmediyse, Layout ve Drawing tamamen atlanabilir, GPU kaynaklarından tasarruf sağlanır.

Yeniden kompozisyon ne sıklıkta gerçekleşebilir?

Animasyonlar sırasında, yeniden kompozisyon saniyede 120 defaya kadar çalışabilir (120fps). Normal etkileşim için — saniyede 10–60 kez. Her yeniden kompozisyonun kare bütçesine (8–16 ms) sığması önemlidir, aksi takdirde uygulama gecikecektir.

Durum değişmediği halde neden bir fonksiyon yeniden kompoze olur?

Nedeni, üst fonksiyondan gelen parametre değişikliğidir. Üst kendi nedeniyle yeniden başlar ve yeni bir değer aktarır. Bunu önlemek için parametre kararlılığını kontrol edin ve lambdaları ve hesaplanan değerleri kararlı hale getirmek için remember kullanın.

Belirli bir fonksiyon için yeniden kompozisyon devre dışı bırakılabilir mi?

Doğrudan devre dışı bırakma yoktur, ancak readInComposition aracılığıyla zorlamalı skipping vardır — State, fonksiyon gövdesinin dışında okunur, bu bir bağımlılık kaydetmez. Dikkatli kullanın: fonksiyon değişikliklere tepki vermez, bu da güncel olmayan UI'a yol açabilir.

Hangisi daha pahalı: Composition mı yoksa Recomposition mı?

Composition daha pahalıdır çünkü tüm slotları ve ağaç düğümlerini sıfırdan oluşturur. Recomposition mevcut slotları yeniden kullanır ve yalnızca değerlerini günceller. Pratikte, bir ekranın Composition'ı 2–10 ms sürerken, tek bir öğenin yeniden kompozisyonu 0.1–1 ms sürer.

Özet

  • Recomposition — Durum veya parametreler değiştiğinde Composable fonksiyonlarının seçici yeniden başlatılması
  • Snapshot sistemi fonksiyonların Duruma bağımlılıklarını izler ve yeniden kompozisyonu planlar
  • Skipping yalnızca kararlı parametrelere (@Stable veya değişmez) sahip fonksiyonlar için mümkündür
  • Üç tetikleyici: Durum değişikliği, parametre değişikliği, CompositionLocal değişikliği
  • List<T> kararsız kabul edilir — doğru skipping için değişmez koleksiyonlar kullanın
  • Layout Inspector her fonksiyon için yeniden kompozisyon sayaçlarını gösterir
  • Öneri: UI'ın kararlı kısımlarını ayrı fonksiyonlara çıkarın ve lambdalar için remember kullanın

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun