Bu sayfada, composable'ların yaşam döngüsü ve Compose'un bir composable'ın yeniden oluşturulması gerekip gerekmediğine nasıl karar verdiği hakkında bilgi edineceksiniz.
Yaşam döngüsüne genel bakış
Durumu yönetme dokümanlarında belirtildiği gibi, bir kompozisyon, uygulamanızın kullanıcı arayüzünü tanımlar ve composable'lar çalıştırılarak oluşturulur. Kompozisyon, kullanıcı arayüzünüzü tanımlayan composable'ların ağaç yapısıdır.
Jetpack Compose, ilk kompozisyon sırasında composable'larınızı ilk kez çalıştırdığında, kullanıcı arayüzünüzü bir kompozisyonda tanımlamak için çağırdığınız composable'ları takip eder. Ardından, uygulamanızın durumu değiştiğinde Jetpack Compose bir yeniden oluşturma planlar. Yeniden oluşturma, Jetpack Compose'un durum değişikliklerine yanıt olarak değişmiş olabilecek composable'ları yeniden yürütmesi ve ardından değişiklikleri yansıtmak için Composition'ı güncellemesidir.
Bir beste yalnızca ilk beste ile üretilebilir ve yeniden beste yapılarak güncellenebilir. Bir kompozisyonu değiştirmenin tek yolu yeniden kompozisyondur.
1.şekil Composition'daki bir composable'ın yaşam döngüsü. Bu işlev, Composition'a girer, 0 veya daha fazla kez yeniden oluşturulur ve Composition'dan çıkar.
Yeniden oluşturma genellikle bir State<T>
nesnesinde yapılan bir değişiklikle tetiklenir. Compose, bunları izler ve kompozisyonda bu belirli State<T>
değerini okuyan tüm composable'ları ve çağırdıkları, atlanamayan tüm composable'ları çalıştırır.
Bir composable birden fazla kez çağrılırsa Composition'a birden fazla örnek yerleştirilir. Her görüşmenin beste içinde kendi yaşam döngüsü vardır.
@Composable fun MyComposable() { Column { Text("Hello") Text("World") } }
Şekil 2. Beste içinde MyComposable
öğesinin temsili. Bir composable birden fazla kez çağrılırsa Composition'a birden fazla örnek yerleştirilir. Farklı renkteki bir öğe, ayrı bir örnek olduğunu gösterir.
Composition'da composable'ın anatomisi
Composition'daki bir composable'ın örneği, çağrı sitesi ile tanımlanır. Compose derleyicisi, her çağrı sitesini ayrı olarak değerlendirir. Birden fazla çağrı sitesinden çağrılan composable'lar, Composition'da composable'ın birden fazla örneğini oluşturur.
Yeniden oluşturma sırasında bir composable, önceki oluşturma sırasında çağırdığından farklı composable'lar çağırırsa Compose, hangi composable'ların çağrıldığını veya çağrılmadığını belirler. Her iki oluşturmada da çağrılan composable'lar için Compose, girişleri değişmediyse bunları yeniden oluşturmaktan kaçınır.
Yan etkilerin bestelenebilir öğeleriyle ilişkilendirilmesi için kimliğin korunması çok önemlidir. Böylece yan etkiler, her yeniden oluşturma işleminde yeniden başlatılmak yerine başarılı bir şekilde tamamlanabilir.
Aşağıdaki örneği inceleyelim:
@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
composable'ını koşullu olarak çağırır ve LoginInput
composable'ını her zaman çağırır. Her çağrının, derleyicinin benzersiz şekilde tanımlamak için kullanacağı benzersiz bir çağrı sitesi ve kaynak konumu vardır.
3.Şekil Durum değiştiğinde ve yeniden oluşturma gerçekleştiğinde Kompozisyon'daki LoginScreen
öğesinin temsili. Aynı renk, yeniden oluşturulmadığı anlamına gelir.
LoginInput
önce çağrılmaktan ikinci çağrılmaya geçse de LoginInput
örneği yeniden oluşturma işlemlerinde korunur. Ayrıca, LoginInput
, yeniden oluşturma sırasında değişen parametreler içermediğinden LoginInput
çağrısı Compose tarafından atlanır.
Akıllı yeniden oluşturma özelliğine yardımcı olmak için ek bilgiler ekleme
Bir composable'ı birden çok kez çağırmak, onu Composition'a da birden çok kez ekler. Aynı çağrı sitesinden bir composable birden çok kez çağrıldığında Compose, bu composable'a yapılan her çağrıyı benzersiz şekilde tanımlayacak bilgilere sahip olmadığından örnekleri farklı tutmak için çağrı sitesine ek olarak yürütme sırası kullanılır. Bu davranış bazen yeterli olsa da 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, Composition'da örneğin farklı kalmasını sağlamak için çağrı sitesine ek olarak yürütme sırasını kullanır. Listenin alt kısmına yeni bir movie
eklenirse Oluşturma, listedeki konumları değişmediği için kompozisyonda zaten bulunan örnekleri yeniden kullanabilir. Bu nedenle, bu örnekler için movie
girişi aynıdır.
Şekil 4. Listeye yeni bir öğe eklendiğinde Kompozisyon'daki MoviesScreen
öğesinin gösterimi. Composition'daki MovieOverview
composable'ları yeniden kullanabilirsiniz. MovieOverview
içindeki aynı renk, composable'ın yeniden oluşturulmadığı anlamına gelir.
Ancak movies
listesi, listenin üst veya ortasına öğe eklenerek, öğeler kaldırılarak ya da yeniden sıralanarak değişirse giriş parametresinin listedeki konumu değişen tüm MovieOverview
çağrılarında yeniden oluşturmaya neden olur. Örneğin, MovieOverview
, yan etki kullanarak bir film resmi getiriyorsa bu durum son derece önemlidir. Efekt devam ederken yeniden oluşturma işlemi gerçekleşirse bu işlem iptal edilir ve yeniden başlatılır.
@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) /* ... */ } }
5.şekil Listeye yeni bir öğe eklendiğinde Kompozisyon'daki MoviesScreen
öğesinin gösterimi. MovieOverview
composables yeniden kullanılamaz ve tüm yan etkiler yeniden başlar. MovieOverview
içinde farklı bir renk, composable'ın yeniden oluşturulduğu anlamına gelir.
İdeal olarak, MovieOverview
örneğinin kimliğinin, kendisine iletilen movie
kimliğine bağlı olduğunu düşünmek isteriz. Film listesini yeniden sıralarsak her MovieOverview
composable'ı farklı bir film örneğiyle yeniden oluşturmak yerine, ideal olarak Composition ağacındaki örnekleri de benzer şekilde 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ğlar: key
composable'ı.
Bir kod bloğunu, bir veya daha fazla değerin iletildiği anahtar composable'ı ile sarmalayarak bu değerleri birleştirip kompozisyondaki örneği tanımlamak için kullanabilirsiniz. Bir key
için değerin küresel olarak benzersiz olması gerekmez. Yalnızca çağrı sitesindeki composable'ların çağrıları arasında benzersiz olması gerekir. Dolayısıyla bu örnekte her movie
, movies
arasında benzersiz olan bir key
içermelidir. Bu key
, uygulamadaki başka bir yerde bulunan diğer bazı composable'larla paylaşılabilir.
@Composable fun MoviesScreenWithKey(movies: List<Movie>) { Column { for (movie in movies) { key(movie.id) { // Unique ID for this movie MovieOverview(movie) } } } }
Yukarıdaki bilgiler sayesinde, listedeki öğeler değişse bile Compose, MovieOverview
için yapılan ayrı ayrı çağrıları tanır ve bunları yeniden kullanabilir.
6.şekil Listeye yeni bir öğe eklendiğinde Kompozisyon'daki MoviesScreen
öğesinin gösterimi. MovieOverview
composable'ların benzersiz anahtarları olduğundan Compose, hangi MovieOverview
örneklerinin değişmediğini tanır ve bunları yeniden kullanabilir. Bu örneklerin yan etkileri yürütülmeye devam eder.
Bazı composable'lar, key
composable'ı için yerleşik destek sunar. Ö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 oluşturma işleminden değişmemişse uygun olan bazı composable işlevlerin yürütülmesi tamamen atlanabilir.
Bir composable işlev, aşağıdaki durumlar hariç atlanmaya uygundur:
- İşlevin
Unit
olmayan bir dönüş türü var. - İşlev,
@NonRestartableComposable
veya@NonSkippableComposable
ile açıklama eklenmiş - Gerekli bir parametre kararlı olmayan bir türde
Son koşulu gevşeten deneysel bir derleyici modu olan Strong Skipping 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
işlevinin sonucu, aynı iki örnek için her zaman aynı olacaktır. - Türün herkese açık bir özelliği değişirse Composition bilgilendirilir.
- Tüm genel mülk türleri de kararlıdır.
Bu sözleşmeye dahil olan ve Compose derleyicisinin, @Stable
ek açıklaması kullanılarak açıkça kararlı olarak işaretlenmemiş olsalar bile kararlı olarak değerlendireceği bazı önemli ortak 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'lar)
Bu türlerin tümü değişmez oldukları için kararlı sözleşmeye uyabilir. Değişmez türler asla değişmediğinden, değişikliğin bileşimini asla bildirmeleri gerekmez. Bu nedenle, bu sözleşmeyi takip etmek çok daha kolaydır.
Sabit ancak değiştirilebilir olan önemli bir tür, Compose'un MutableState
türüdür. Bir değer MutableState
içinde tutuluyorsa Compose, State
öğesinin .value
özelliğindeki değişikliklerden haberdar olacağından genel olarak durum nesnesinin kararlı olduğu 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 konumuna 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.
Compose, bir türün kararlı olduğunu yalnızca kanıtlayabildiği takdirde kabul eder. Örneğin, bir arayüz genellikle kararlı olarak kabul edilmez ve uygulanması değişmez olabilecek, değiştirilebilir genel özelliklere sahip türler de kararlı değildir.
Compose, bir türün kararlı olduğunu çıkaramıyorsa ancak Compose'un bunu kararlı olarak ele almasını zorlamak istiyorsanız 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, normalde bu türü kararlı olarak değerlendirmeyebilir. @Stable
Açıklamasını ekleyerek Compose'a bu türün kararlı olduğunu bildirirsiniz. Böylece Compose, akıllı yeniden oluşturmaları tercih edebilir. 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.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- State ve Jetpack Compose
- Oluşturma'daki yan etkiler
- Compose'da kullanıcı arayüzü durumunu kaydetme