Bestelerin yaşam döngüsü

Bu sayfada, bir composable'ın yaşam döngüsü hakkında bilgi edinecek ve Compose'un composable'ın yeniden bestelemeye ihtiyacı olup olmadığına nasıl karar verdiğini öğreneceksiniz.

Yaşam döngüsüne genel bakış

Yönetim durumu dokümanlarında belirtildiği gibi, beste, uygulamanızın kullanıcı arayüzünü açıklar ve composable'ların çalıştırılmasıyla üretilir. Beste, kullanıcı arayüzünüzü açıklayan composable'ların ağaç yapısıdır.

Jetpack Compose, composable'larınızı ilk kez çalıştırdığında ilk beste sırasında kullanıcı arayüzünüzü bir Bestede açıklamak için çağırdığınız composable'ları takip eder. Ardından, uygulamanızın durumu değiştiğinde Jetpack Compose bir yeniden düzenleme planlar. Yeniden düzenleme, Jetpack Compose'un durum değişikliklerine yanıt olarak değişmiş olabilecek composable'ları yeniden yürütmesi ve ardından besteyi değişiklikleri yansıtacak şekilde güncellemesidir.

Bir Beste, yalnızca başlangıçtaki bir besteyle üretilebilir ve yeniden besteleme yoluyla güncellenebilir. Bir besteyi değiştirmenin tek yolu yeniden bestelemektir.

Bir composable'ın yaşam döngüsünü gösteren şema

Şekil 1. Bestedeki bir composable'ın yaşam döngüsü. Besteye girer, 0 veya daha fazla kez yeniden yazılır ve Beste'den çıkar.

Yeniden oluşturma, genellikle bir State<T> nesnesinde yapılan değişiklik nedeniyle tetiklenir. Compose bunları izler ve Beste'deki söz konusu State<T> öğesini okuyan tüm composable'ları ve çağrılan ve atlanamayan tüm composable'ları çalıştırır.

Bir composable birden fazla kez çağrılırsa Beste'ye birden fazla örnek yerleştirilir. Bestede her çağrının kendi yaşam döngüsü vardır.

@Composable
fun MyComposable() {
    Column {
        Text("Hello")
        Text("World")
    }
}

Önceki kod snippet&#39;inde bulunan öğelerin hiyerarşik düzenini gösteren şema

Şekil 2. Bestedeki MyComposable temsili. Bir composable birden fazla kez çağrılırsa Beste'ye birden fazla örnek yerleştirilir. Farklı renge sahip bir öğe, ayrı bir örnek olduğunu gösterir.

Bestede bir composable'ın anatomisi

Bestedeki bir composable, çağrı sitesi tarafından tanımlanır. Compose derleyicisi her çağrı sitesini ayrı olarak değerlendirir. Birden fazla çağrı sitesinden composable'ın çağrılması, Beste'de birden fazla composable örneği oluşturur.

Yeniden düzenleme sırasında bir composable, önceki bestede olduğundan farklı composable'lar çağırırsa hangi composable'ların çağrıldığını veya çağrılmadığını belirler, her iki bestede de çağrılan composable'lar için Compose girişleri değişmediyse bunları yeniden oluşturmaktan kaçınır.

Yan etkileri composable ile ilişkilendirmek için kimliğin korunması çok önemlidir. Böylece her yeniden oluşturmada yeniden başlatmak yerine başarıyla tamamlanabilirler.

Aşağıdaki örneği inceleyin:

@Composable
fun LoginScreen(showError: Boolean) {
    if (showError) {
        LoginError()
    }
    LoginInput() // This call site affects where LoginInput is placed in Composition
}

@Composable
fun LoginInput() { /* ... */ }

@Composable
fun LoginError() { /* ... */ }

Yukarıdaki kod snippet'inde LoginScreen, koşullu olarak LoginError composable'ı çağırır ve her zaman LoginInput composable'ı çağırır. Her çağrının benzersiz bir çağrı sitesi ve kaynak konumu vardır. Derleyici, bu bilgileri benzersiz bir şekilde tanımlamak için kullanır.

showError işaretinin true olarak değiştirilmesi durumunda önceki kodun nasıl yeniden oluşturulduğunu gösteren şema. LoginError composable eklenir ancak diğer composable&#39;lar yeniden derlenmez.

Şekil 3. Durum değiştiğinde ve bir yeniden oluşturma gerçekleştiğinde bestede LoginScreen temsili. Aynı renk yeniden düzenlenmediği anlamına gelir.

LoginInput ilk çağrılmadan ikinci çağrılmaya geçse de LoginInput örneği yeniden oluşturmalarda korunacaktır. Ayrıca, LoginInput yeniden oluşturma genelinde değişmiş herhangi bir parametreye sahip olmadığı için LoginInput çağrısı, Compose tarafından atlanır.

Akıllı yeniden bestelemeye yardımcı olmak için ek bilgi ekleyin

Bir composable'ı birden fazla kez çağırmak, onu Beste'ye de birden çok kez ekler. Bir composable, aynı çağrı sitesinden birden fazla kez çağrıldığında, Compose'un bu composable'a yapılan çağrıları benzersiz bir şekilde tanımlayacak herhangi bir bilgisi olmaz. Bu nedenle, örnekleri ayrı tutmak için çağrı sitesine ek olarak yürütme sırası kullanılır. Bazen gereken tek şey bu davranış olsa da bazı durumlarda istenmeyen davranışa neden olabilir.

@Composable
fun MoviesScreen(movies: List<Movie>) {
    Column {
        for (movie in movies) {
            // MovieOverview composables are placed in Composition given its
            // index position in the for loop
            MovieOverview(movie)
        }
    }
}

Yukarıdaki örnekte Compose, örneği Beste'de farklı tutmak için çağrı sitesine ek olarak yürütme sırasını da kullanır. Listenin en altına yeni bir movie eklenirse Compose, Beste'de yer alan örnekleri yeniden kullanabilir. Bunun nedeni, bu örneklerin listedeki konumları değişmemiş olmasıdır. Bu nedenle, movie girişi bu örnekler için aynıdır.

Listenin sonuna yeni bir öğe eklenmesi durumunda önceki kodun nasıl yeniden oluşturulduğunu gösteren şema. Listedeki diğer öğelerin konumu değişmedi ve öğeler yeniden oluşturulmadı.

4.Şekil Listenin sonuna yeni bir öğe eklendiğinde Bestedeki MoviesScreen temsili. Bestedeki MovieOverview composable yeniden kullanılabilir. MovieOverview öğesindeki aynı renk, composable'ın yeniden düzenlenmediği anlamına gelir.

Bununla birlikte, movies listesi, listenin en üstüne veya ortasına eklenerek, öğeler kaldırılarak veya yeniden sıralanarak değişirse giriş parametresinin listedeki konumu değişen tüm MovieOverview çağrılarında yeniden oluşturma işlemi gerçekleşir. Örneğin, MovieOverview yan efekt kullanarak film görüntüsü getirirse bu son derece önemlidir. Efekt devam ederken yeniden oluşturma gerçekleşirse işlem iptal edilir ve tekrar başlar.

@Composable
fun MovieOverview(movie: Movie) {
    Column {
        // Side effect explained later in the docs. If MovieOverview
        // recomposes, while fetching the image is in progress,
        // it is cancelled and restarted.
        val image = loadNetworkImage(movie.url)
        MovieHeader(image)

        /* ... */
    }
}

Listenin başına yeni bir öğe eklenmesi durumunda önceki kodun nasıl yeniden oluşturulduğunu gösteren şema. Listedeki diğer tüm öğelerin konumu değişir ve öğenin yeniden oluşturulması gerekir.

5. Şekil. Listeye yeni bir öğe eklendiğinde Bestedeki MoviesScreen temsili. MovieOverview composable yeniden kullanılamaz ve tüm yan efektler yeniden başlatılır. MovieOverview öğesinde farklı bir renk, composable'ın yeniden derlendiği anlamına gelir.

İdeal olarak MovieOverview örneğinin kimliğinin, kendisine geçirilen movie öğesinin kimliğine bağlı olduğunu düşünmek istiyoruz. Film listesini yeniden sıraladığımızda, ideal olarak her MovieOverview composable'ı farklı bir film örneğiyle yeniden oluşturmak yerine Beste ağacında örnekleri yeniden sıralarız. Compose, çalışma zamanına ağacın belirli bir bölümünü tanımlamak için hangi değerleri kullanmak istediğinizi söylemenizi sağlayan bir yöntem sunar: key composable.

Bir kod bloku, composable'a bir veya daha fazla değer iletilmiş anahtara yapılan bir çağrıyla sarmalandığında bu değerler, bestede o örneği tanımlamak için kullanılmak üzere birleştirilir. key değerinin global olarak benzersiz olması gerekmez. Bunun yalnızca çağrı sitesindeki composable'ların çağrıları arasında benzersiz olması gerekir. Dolayısıyla bu örnekte her movie, movies içinde benzersiz bir key özelliğine sahip olmalıdır. Bu key öğesini uygulamanın başka bir yerinde composable'la paylaşsa da olur.

@Composable
fun MoviesScreenWithKey(movies: List<Movie>) {
    Column {
        for (movie in movies) {
            key(movie.id) { // Unique ID for this movie
                MovieOverview(movie)
            }
        }
    }
}

Yukarıdaki koşullarda, listedeki öğeler değişse bile Compose, MovieOverview çağrılarını ayrı ayrı tanır ve yeniden kullanabilir.

Listenin başına yeni bir öğe eklenmesi durumunda önceki kodun nasıl yeniden oluşturulduğunu gösteren şema. Liste öğeleri anahtarlarla tanımlandığı için, konumları değişse bile Compose bunları yeniden oluşturmayacağını bilir.

6. Şekil. Listeye yeni bir öğe eklendiğinde Bestedeki MoviesScreen temsili. MovieOverview composable'ın benzersiz anahtarları olduğundan Compose, hangi MovieOverview örneklerinin değişmediğini tespit edip bunları yeniden kullanabilir. Bunların yan etkileri devam eder.

Bazı composable'lar yerleşik key composable desteğine sahiptir. Örneğin, LazyColumn, items DSL'de özel bir key belirtmeyi kabul eder.

@Composable
fun MoviesScreenLazy(movies: List<Movie>) {
    LazyColumn {
        items(movies, key = { movie -> movie.id }) { movie ->
            MovieOverview(movie)
        }
    }
}

Girişler değişmediyse atlama

Yeniden oluşturma sırasında, girişleri önceki besteye göre değişmediyse bazı uygun composable işlevlerin yürütme işlemleri tamamen atlanabilir.

Bir composable işlev, aşağıdaki durumlar haricinde atlanmaya uygundur:

  • İşlev, Unit dışında bir dönüş türü içeriyor
  • İşlev, @NonRestartableComposable veya @NonSkippableComposable ile ek açıklamalara sahip
  • Gerekli parametrelerden biri kararsız türde

Son şartı hafifleten deneysel bir derleyici modu olan Güçlü Atlama vardır.

Bir türün kararlı olarak kabul edilmesi için aşağıdaki sözleşmeye uygun olması gerekir:

  • İki örnek için equals sonucu, aynı iki örnek için tamamen aynı olur.
  • Türün herkese açık bir mülkü değişirse Beste bilgilendirilir.
  • Tüm kamu mülkü türleri de sabittir.

@Stable ek açıklaması kullanılarak açıkça kararlı olarak işaretlenmeseler bile, Compose derleyicisinin kararlı olarak değerlendireceği bazı önemli yaygın türler bu sözleşme kapsamına girer:

  • Tüm temel değer türleri: Boolean, Int, Long, Float, Char vb.
  • Yaylı Çalgılar
  • Tüm işlev türleri (lambdas)

Bu türlerin tümü, sabit oldukları için istikrarlı sözleşmeye uygundur. Sabit türler hiçbir zaman değişmediğinden, değişikliğin bileşimini hiçbir zaman bildirmek zorunda kalmazlar. Dolayısıyla, bu sözleşmeye uymak çok daha kolaydır.

Kararlı ancak değişebilir olan önemli bir tür, Compose'un MutableState türüdür. Bir değer MutableState öğesinde tutulursa genel durum nesnesinin kararlı olduğu kabul edilir. Çünkü Compose, State öğesinin .value özelliğinde değişiklik yapıldığında bilgilendirilir.

Bir composable'a parametre olarak iletilen tüm türler kararlı olduğunda parametre değerleri, kullanıcı arayüzü ağacındaki composable konuma göre eşitlik açısından karşılaştırılır. Önceki çağrıdan bu yana tüm değerler değişmediyse yeniden oluşturma işlemi atlanır.

Compose, bir türü kanıtlayabildiği takdirde kararlı olarak kabul eder. Örneğin, bir arayüz genellikle kararlı değildir ve uygulanması sabit olabilen, değişken herkese açık özelliklere sahip türler de kararlı değildir.

Compose bir türün kararlı olduğunu belirleyemiyorsa ancak Compose'u kararlı olarak ele almaya zorlamak istiyorsanız @Stable ek açıklamasıyla işaretleyin.

// Marking the type as stable to favor skipping and smart recompositions.
@Stable
interface UiState<T : Result<T>> {
    val value: T?
    val exception: Throwable?

    val hasError: Boolean
        get() = exception != null
}

Yukarıdaki kod snippet'inde UiState bir arayüz olduğundan, Compose bu türün kararlı olmadığını belirtebilir. @Stable ek açıklaması ekleyerek, Compose'a bu türün kararlı olduğunu bildirerek Compose'un akıllı yeniden bestelere öncelik vermesini sağlarsınız. Bu aynı zamanda, arayüzün parametre türü olarak kullanılması durumunda Compose'un tüm uygulamalarını kararlı olarak değerlendireceği anlamına da gelir.