Bestelerin yaşam döngüsü

Bu sayfada, bir composable'ın yaşam döngüsünü ve Compose'un bir composable'ın yeniden kompozisyona ihtiyaç duyup duymadığına nasıl karar verdiğini öğreneceksiniz.

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

Durumu yönetme belgelerinde belirtildiği gibi Beste, uygulamanızın kullanıcı arayüzünü açıklar ve composable'lar çalıştırılarak oluşturulur. Beste, kullanıcı arayüzünüzü tanımlayan 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 Beste içinde açıklamak için çağırdığınız composable'ları takip eder. Ardından, uygulamanızın durumu değiştiğinde Jetpack Composer bir yeniden oluşturma planlar. Yeniden kompozisyon, Jetpack Compose'un durum değişikliklerine göre değişmiş olabilecek composable'ları yeniden çalıştırması ve ardından Beste'yi değişiklikleri yansıtacak şekilde güncellemesidir.

Bir Beste yalnızca bir başlangıç bestesiyle üretilebilir ve yeniden kompozisyon ile güncellenebilir. Bir Besteyi değiştirmenin tek yolu yeniden oluşturmadır.

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

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

Yeniden oluşturma genellikle bir State<T> nesnesinde değişiklik yapıldığında tetiklenir. Compose bunları izler ve Beste içinde bu belirli State<T> öğesini okuyan tüm composable'lar ile atlanamayan dedikleri composable'ları çalıştırır.

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

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

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

2. Şekil. Kompozisyonda MyComposable gösterimi. Bir composable birden çok kez çağrılırsa Beste içine birden fazla örnek yerleştirilir. Farklı renge sahip bir öğe, ayrı bir örnek olduğunu gösterir.

Bestedeki bir composable'ın anatomisi

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

Bir composable, bir yeniden bestede önceki besteye göre farklı composable'ları çağırırsa Compose 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.

Her yeniden oluşturma işlemi için yeniden başlatmak yerine başarıyla tamamlamaları için kimliği korumak, yan efektleri composable'la ilişkilendirmek açısından çok önemlidir.

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'ı ve her zaman LoginInput composable'ı çağırır. Her çağrının, derleyicinin bunu benzersiz bir şekilde tanımlamak için kullanacağı benzersiz bir çağrı sitesi ve kaynak konumu vardır.

showError işareti doğru olarak değiştirildiğinde önceki kodun nasıl yeniden derleneceğini gösteren şema. LoginError composable eklendi, ancak diğer composable&#39;lar yeniden oluşturulmadı.

3. Şekil. Durum değiştiğinde ve yeniden kompozisyonda LoginScreen gösterimi. Aynı renk, yeniden oluşturulmadığı anlamına gelir.

LoginInput örneğinin ilk çağrıdan ikincisine çağrılmasına rağmen LoginInput örneği yeniden oluşturma işlemlerinde korunur. Ayrıca LoginInput, yeniden oluşturma işleminde değişen herhangi bir parametreye sahip olmadığından LoginInput çağrısı, Compose tarafından atlanır.

Akıllı yeniden oluşturma işlemlerine yardımcı olmak için ek bilgiler ekleyin

Bir composable'ı birden çok kez çağırdığınızda Beste'ye birden çok kez eklenir. Aynı çağrı sitesinden bir composable'ı birden çok kez çağırırken Compose'da bu composable'a yapılan her bir çağrıyı benzersiz şekilde tanımlayacak herhangi bir bilgi bulunmaz. Bu nedenle, örnekleri farklı tutmak için çağrı sitesine ek olarak yürütme sırası kullanılır. Bu davranış bazen gerekli olan tek şeydir, ancak bazı durumlarda istenmeyen davranışlara 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 içinde farklı tutmak için çağrı sitesine ek olarak yürütme sırasını kullanır. Listenin altına yeni bir movie eklenirse Compose, listedeki konumları değişmediğinden zaten Beste'de bulunan örnekleri yeniden kullanabilir. Bu nedenle, movie girişi bu örnekler için aynıdır.

Listenin alt kısmına yeni bir öğe eklendiğinde önceki kodun nasıl yeniden derleneceğini gösteren şema. Listedeki diğer öğelerin konumu değişmedi ve yeniden oluşturulmadı.

4. Şekil. Listenin altına yeni bir öğe eklendiğinde Bestedeki MoviesScreen gösterimi. Beste içindeki MovieOverview composable yeniden kullanılabilir. MovieOverview içindeki aynı renk, composable'ın yeniden derlenmediği anlamına gelir.

Ancak movies listesi, listenin üst kısmına veya ortasına eklenerek, öğeler kaldırılır veya yeniden sıralanarak değiştirilirse giriş parametresi listedeki konumu değişen tüm MovieOverview çağrılarında yeniden oluşturma işlemi yapılır. Örneğin, MovieOverview bir film resmini yan efekt kullanarak getirirse bu son derece önemlidir. Efekt devam ederken yeniden oluşturma işlemi 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 en üstüne yeni bir öğe eklendiğinde önceki kodun nasıl yeniden derleneceğini gösteren şema. Listedeki diğer tüm öğelerin konumu değişir ve bu öğelerin yeniden oluşturulması gerekir.

5. Şekil. Listeye yeni bir öğe eklendiğinde Bestedeki MoviesScreen gösterimi. MovieOverview composable tekrar 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 aktarılan movie kimliğine bağlı olduğunu düşünürüz. Film listesini yeniden sıralarsak ideal olarak, her MovieOverview composable'ı farklı bir film örneğiyle yeniden oluşturmak yerine Beste ağacındaki örnekleri yeniden sıralarız. Compose, çalışma zamanına ağacın belirli bir bölümünü tanımlamak için kullanmak istediğiniz değerleri, yani key composable'ı bildirmenizi sağlayan bir yöntem sunar.

Bir kod bloğunun, içinde aktarılmış bir veya daha fazla değerle composable anahtara yapılan bir çağrıyla sarmalanmasıyla bu değerler, bestedeki örneği tanımlamak için kullanılmak üzere birleştirilir. key değerinin global olarak benzersiz olması gerekmez. Yalnızca çağrı sitesindeki composable'ların çağrıları arasında benzersiz olmalıdır. Dolayısıyla bu örnekte her movie, movies arasında benzersiz olan bir key öğesine sahip olmalıdır; bu key öğesini uygulamanın başka bir yerinde composable ile paylaşması sorun yaratmaz.

@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 için yapılan her bir çağrıyı tanır ve yeniden kullanabilir.

Listenin en üstüne yeni bir öğe eklendiğinde önceki kodun nasıl yeniden derleneceğini gösteren şema. Liste öğeleri anahtarlarla tanımlandığından Compose konumları değişse bile bunları yeniden oluşturmaması gerektiğini bilir.

6. Şekil. Listeye yeni bir öğe eklendiğinde Bestedeki MoviesScreen gösterimi. MovieOverview composable'ları benzersiz anahtarlara sahip olduğundan Compose hangi MovieOverview örneklerinin değişmediğini algılar ve bunları yeniden kullanabilir. Bu nedenle, bu örneklerin yan etkileri çalışmaya devam eder.

Bazı composable'lar key composable için yerleşik desteğe sahiptir. Örneğin LazyColumn, items DSL'sinde ö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

Girişleri önceki besteye göre değişmediği takdirde, yeniden oluşturma sırasında bazı uygun composable işlevlerin yürütmeleri tamamen atlanabilir.

composable işlevler aşağıdaki durumlar dışında atlanabilir:

  • İşlev Unit dışında bir döndürme türüne sahip
  • İşleve @NonRestartableComposable veya @NonSkippableComposable ile not eklenir
  • Zorunlu bir parametre, kararlı olmayan türde

Son gereksinimi 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 her zaman aynı olur.
  • Türün herkese açık mülkü değişirse Beste bildirilir.
  • Tüm herkese açık mülk türleri de stabildir.

Bu sözleşme kapsamında, @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 vardır:

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

Bu türlerin tümü, sabit olduğu için istikrar sözleşmesine uygun olabilir. Sabit türler hiçbir zaman değişmediği için hiçbir zaman değişikliği Bileşim'e bildirmeleri gerekmez; bu nedenle bu sözleşmeyi uygulamak çok daha kolaydır.

Kararlı olan ancak değişken olan önemli türlerden biri, Compose'un MutableState türüdür. MutableState içinde bir değer tutulursa Compose State öğesinin .value özelliğinde yapılan değişiklikler bildirileceğinden durum nesnesinin genel olarak kararlı olduğu kabul edilir.

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

Compose, yalnızca kanıtlanabilen türleri kararlı olarak kabul eder. Örneğin, bir arayüz genellikle kararlı değil olarak kabul edilir. Ayrıca, uygulaması sabit olabilecek herkese açık ve değişken özelliklere sahip türler de kararlı değildir.

Compose bir türün kararlı olduğu sonucuna varamıyorsa ancak Composer'ı kararlı olarak değerlendirilmeye zorlamak istiyorsanız bu türü @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ü normalde sabit olarak kabul edebilir. @Stable ek açıklamasını ekleyerek Compose'a bu türün kararlı olduğunu ve böylece Compose'un akıllı yeniden derlemeleri desteklediğini belirtmiş olursunuz. Bu aynı zamanda, parametre türü arayüz olarak kullanılıyorsa Compose'un tüm uygulamalarını kararlı olarak değerlendireceği anlamına da gelir.