Bestelerin yaşam döngüsü

Bu sayfada, bir bileşenin yaşam döngüsü ve Compose'un bir bileşenin yeniden derlenmesi gerekip gerekmediğine nasıl karar verdiği hakkında bilgi edineceksiniz.

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

Durum yönetimi dokümanlarında belirtildiği gibi, kompozisyonlar uygulamanızın kullanıcı arayüzünü tanımlar ve bileşenlerin çalıştırılmasıyla oluşturulur. Bir kompozisyon, kullanıcı arayüzünüzü tanımlayan bileşenlerin ağaç yapısıdır.

Jetpack Compose, ilk kompozisyon sırasında, kompozisyonunuzda kullanıcı arayüzünüzü tanımlamak için çağırdığınız kompozisyon öğelerini izler. Ardından, uygulamanızın durumu değiştiğinde Jetpack Compose bir yeniden derleme planlar. Yeniden kompozisyon, Jetpack Compose'un durum değişikliklerine yanıt olarak değişmiş olabilecek kompozisyonları yeniden yürütmesi ve ardından kompozisyonu tüm değişiklikleri yansıtacak şekilde güncellemesi işlemidir.

Bir kompozisyon yalnızca ilk kompozisyonla üretilebilir ve yeniden kompozisyon oluşturma işlemiyle güncellenebilir. Bir kompozisyonu değiştirmenin tek yolu yeniden kompozisyon oluşturmaktır.

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

Şekil 1. Kompozisyondaki bir bileşenin yaşam döngüsü. Parça, kompozisyona girer, 0 veya daha fazla kez yeniden derlenir ve kompozisyondan çıkar.

Yeniden oluşturma işlemi genellikle bir State<T> nesnesinde yapılan bir değişiklik tarafından tetiklenir. Oluşturma, bu öğeleri izler ve kompozisyondaki belirli State<T> öğesini okuyan tüm kompozisyon öğelerini ve bu öğelerin çağırdığı, atlanamayan tüm kompozisyon öğelerini çalıştırır.

Bir kompozisyon birden çok kez çağrılırsa kompozisyona birden çok örnek yerleştirilir. Her çağrının, kompozisyonda 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

Şekil 2. Bileşimde MyComposable'ün temsili. Bir derlenebilir öğe birden çok kez çağrılırsa kompozisyona birden çok örnek yerleştirilir. Farklı renge sahip bir öğe, ayrı bir örnek olduğunu gösterir.

Kompozisyondaki bir bileşenin anatomisi

Kompozitte bir bileşenin örneği, çağrı sitesi ile tanımlanır. Oluşturma derleyicisi her çağrı sitesini ayrı olarak değerlendirir. Birden fazla çağrı sitesinden çağrılan kompozitler, kompozisyonda birden fazla kompozit örneği oluşturur.

Bir yeniden derleme sırasında bir derlenebilir, önceki derleme sırasında çağrılanlardan farklı derlenebilirler çağırırsa Derle, hangi derlenebilirlerin çağrıldığını veya çağrılmadığını belirler. Ayrıca, her iki derlemede de çağrılan derlenebilirler için girişleri değişmediyse bunları yeniden derlemekten 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, LoginError bileşenini koşullu olarak çağırır ve LoginInput bileşenini her zaman çağırır. Her çağrının benzersiz bir çağrı yeri ve kaynak konumu vardır. Derleyici, çağrıyı benzersiz şekilde tanımlamak için bu konumları kullanır.

showError işareti true olarak değiştirilirse önceki kodun nasıl yeniden derlendiğini gösteren diyagram. 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 derlenmediği anlamına gelir.

LoginInput önce çağrılırken şimdi ikinci sırada çağrılsa bile LoginInput örneği yeniden derlemelerde korunur. Ayrıca, LoginInput'te yeniden derleme sırasında değişen herhangi bir parametre olmadığından, LoginInput çağrısı Derle tarafından atlanır.

Akıllı yeniden derlemelere yardımcı olmak için ek bilgi ekleme

Bir derlenebilir öğeyi birden çok kez çağırmak, öğeyi kompozisyona da birden çok kez ekler. Bir bileşeni aynı çağrı sitesinden birden çok kez çağırırken Compose, söz konusu bileşene yapılan her çağrıyı benzersiz şekilde tanımlayacak herhangi bir bilgiye sahip değildir. Bu nedenle, örnekleri birbirinden ayırmak 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 altına yeni bir movie eklenirse Oluştur, listedeki konumları değişmediğinden ve bu nedenle movie girişi bu örnekler için aynı olduğundan, Oluştur'da zaten bulunan örnekleri yeniden kullanabilir.

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şmez ve yeniden derlenmez.

4.Şekil Listenin en altına yeni bir öğe eklendiğinde kompozisyondaki MoviesScreen temsili. Kompozisyondaki MovieOverview bileşenleri yeniden kullanılabilir. MovieOverview'te aynı renk, derlenebilir öğenin yeniden derlenmediğ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 bir yan etki kullanarak film resmi getiriyorsa bu son derece önemlidir. Yeniden derleme işlemi, efekt devam ederken gerçekleşirse iptal edilir ve yeniden 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 yeniden derlenmesi gerekir.

5. Şekil. Listeye yeni bir öğe eklendiğinde kompozisyondaki MoviesScreen temsili. MovieOverview bileşenleri yeniden kullanılamaz ve tüm yan etkiler yeniden başlar. MovieOverview öğesinde farklı bir renk, composable'ın yeniden derlendiği anlamına gelir.

İdeal olarak, MovieOverview örneğinin kimliğini kendisine iletilen movie örneğinin kimliğine bağlı olarak düşünmek isteriz. Film listesini yeniden sıralarsak ideal olarak her MovieOverview bileşenini farklı bir film örneğiyle yeniden oluşturmak yerine, kompozisyon ağacındaki örnekleri de benzer şekilde yeniden sıralamamız gerekir. Oluşturma, ağacın belirli bir bölümünü tanımlamak için hangi değerleri kullanmak istediğinizi çalışma zamanında belirtmenize olanak tanır: key bileşeni.

Bir kod bloğunu, iletilen bir veya daha fazla değerle birleştirilebilir anahtar çağrısıyla sarmalayarak bu değerler birleştirilir ve kompozisyondaki ilgili örneği tanımlamak için kullanılır. key değerinin global olarak benzersiz olması gerekmez. Yalnızca çağrı sitesindeki birleştirilebilir öğelerin ç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 yöntemle, listedeki öğeler değişse bile Oluştur, MovieOverview çağrılarını tanır ve yeniden kullanabilir.

Listenin en üstüne yeni bir öğe eklenirse önceki kodun nasıl yeniden derlendiğini gösteren şema. Liste öğeleri anahtarlarla tanımlandığından, konumları değişse bile Compose bunları yeniden oluşturmayacağını bilir.

Şekil 6. Listeye yeni bir öğe eklendiğinde kompozisyondaki MoviesScreen temsili. MovieOverview bileşenlerinin benzersiz anahtarları olduğundan Compose, hangi MovieOverview örneklerinin değişmediğini tanır ve bunları yeniden kullanabilir. Bu bileşenlerin yan etkilerinin yürütülmesi devam eder.

Bazı bileşenlerde key bileşeni için yerleşik destek bulunur. Örneğin, LazyColumn, items DSL'sinde özel bir key belirtilmesini 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 bileşimden değişmemişse bazı uygun birleştirilebilir işlevlerin yürütülmesi tamamen atlanabilir.

Bir composable işlevi, aşağıdakiler hariç atlanabilir:

  • İşlevin Unit olmayan bir dönüş türü var
  • İşlev, @NonRestartableComposable veya @NonSkippableComposable ile ek açıklamaya sahiptir
  • Gerekli parametrelerden biri kararsız türde

Son koşulu gevşeten deneysel bir derleyici modu olan Güçlü Atlama vardır.

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

  • İki örnek için equals sonucu, aynı iki örnek için tamamen aynı olur.
  • Bu türdeki herkese açık bir mülk değişirse kompozisyon 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ı sayacağı bazı önemli yaygın türler bu sözleşme kapsamına girer:

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

Bu türlerin tümü, değişmez oldukları için istikrarlı sözleşmeye uygundur. Değişmez türler hiçbir zaman değişmediğinden, Composition'un değişikliği bildirmesi gerekmez. Bu nedenle, bu sözleşmeyi uygulamak çok daha kolaydır.

Sabit ancak değişken olan önemli bir tür, Compose'un MutableState türüdür. Bir değer MutableState içinde tutulursa State öğesinin .value mülkünde yapılan değişikliklerden Compose bilgilendirildiğinden durum nesnesi genel olarak kararlı kabul edilir.

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 atlanır.

Oluşturma, bir türün kararlı olduğunu yalnızca kanıtlayabiliyorsa kabul eder. Örneğin, bir arayüz genellikle kararlı olarak kabul edilmez ve uygulaması değişmez olabilecek, değiştirilebilir herkese açık özelliklere sahip türler de kararlı değildir.

Derleme, bir türün kararlı olduğunu anlayamıyorsa ancak Derleme'yi türünü kararlı olarak ele almaya zorlamak istiyorsanız türünü @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 normalde bu türün kararlı olmadığını düşünebilir. @Stable ek açıklamasını ekleyerek Compose'a bu türün kararlı olduğunu bildirirsiniz. Böylece Compose, akıllı yeniden derlemeleri tercih eder. Bu, arayüz parametre türü olarak kullanılıyorsa Compose'un tüm uygulamalarını kararlı olarak değerlendireceği anlamına da gelir.