Recomposition — məlumat dəyişdikdə istifadəçi interfeysinin hissələrini əl ilə View elementlərini yeniləmədən avtomatik yenidən quran Jetpack Compose mexanizmidir. Composable funksiyasının asılı olduğu vəziyyət dəyişəni dəyərini dəyişdikdə, Compose yalnız həmin funksiyanı yenidən işə salır, UI ağacının qalan hissəsini toxunulmaz qoyur. Google Android Developers, 2026 məlumatlarına görə, Recomposition-un düzgün başa düşülməsi lazımsız təkrar çəkmələrin sayını 40–60% azaltmağa imkan verir.
Əsas məqamlar
Recomposition — Composition-da artıq iştirak etmiş Composable funksiyalarının parametrlərin və ya vəziyyətin yeni qiymətləri ilə təkrar icrasıdır. Rekompozisiyanın əsas məqsədi UI ağacını aktual məlumatlarla sinxronlaşdırmaqdır, bütün interfeysi sıfırdan qurmadan. Birdəfəlik baş verən Composition-dan fərqli olaraq, Recomposition ekranın ömrü boyu yüzlərlə dəfə işə düşə bilər.
Recomposition smart invalidation prinsipi ilə işləyir: Compose hər bir Composable funksiyasının hansı State obyektlərini oxuduğunu izləyir və yalnız asılılıqları dəyişənləri yenidən işə salmaq üçün qeyd edir. Buna snapshot sistemi vasitəsilə nail olunur, o icra zamanı bütün State oxuma əməliyyatlarını qeydə alır və Composer bu asılılıqları konkret funksiyalarla əlaqələndirir.
Anlamaq vacibdir: rekompozisiya ekranın dərhal təkrar çəkilməsi demək deyil. Compose üç fazada işləyir: Composition (UI təsvirinin qurulması), Layout (ölçülərin və mövqelərin hesablanması) və Drawing (kətan üzərində çəkmə). Əgər rekompozisiyadan sonra elementlərin ölçüləri və yerləşməsi dəyişməyibsə, Layout mərhələsi buraxıla bilər. Görünüş dəyişməyibsə — Drawing buraxılır. Bu üçfazalı arxitektura hər UI yeniləməsinin minimal dəyərini təmin edir.
Rekompozisiyanın üç əsas triggeri var. Birinci — Composable funksiyasının gövdəsində oxunan State obyektinin dəyişməsi. mutableStateOf və ya derivedStateOf öz dəyərini dəyişdikdə, əvvəlki kompozisiyada bu State-in oxunmasını qeydə almış bütün funksiyalar yenidən işə salınmaq üçün qeyd olunur.
İkinci trigger — parametrlərin dəyişməsi Composable funksiyasının valideyn funksiyasından çağırılması zamanı. Valideyn funksiyası yeni dəyər ötürərsə (məsələn, mətn və ya rəqəm dəyişibsə), uşaq funksiya öz daxilində State oxumasa belə yenidən işə salınacaq. Compose parametrlərin yeni və köhnə qiymətlərini equals vasitəsilə müqayisə edir, əgər bərabərdirsə — funksiya buraxıla bilər.
Üçüncü trigger — CompositionLocal-in dəyişməsi CompositionLocalProvider vasitəsilə. .current vasitəsilə CompositionLocal oxuyan bütün funksiyalar provider dəyişdikdə yenidən işə salınır. Bu mexanizm MaterialTheme tərəfindən istifadə olunur: mövzunun dəyişməsi (açıq/qaranlıq) MaterialTheme.colorScheme oxuyan bütün komponentlərin rekompozisiyasına səbəb olur.
@Composable
fun RecompositionDemo() {
var counter by remember { mutableStateOf(0) }
var text by remember { mutableStateOf("Hello") }
Column {
Text("Sayğac: $counter") // counter dəyişdikdə rekompozisiya
Text("Mesaj: $text") // mətn dəyişdikdə rekompozisiya
Button(onClick = { counter++ }) {
Text("+1")
}
Button(onClick = { text = "Dünya" }) {
Text("Mətni dəyiş")
}
}
}
+1 düyməsinə basmaq counter-i dəyişir, bu da yalnız birinci Text sətirinin və Column-un özünün rekompozisiyasına səbəb olur. text-i göstərən ikinci Text sətiri yenidən işə salınmır. Belə izolyasiya snapshot sisteminin nəticəsidir: hər bir Composable funksiyası yalnız oxuduğu State obyektləri haqqında bilir.
Rekompozisiyanın optimallaşdırılması düzgün məlumat strukturlarının seçilməsi ilə başlayır. Dəyişən (mutableListOf) əvəzinə dəyişməz kolleksiyalardan (listOf, mapOf) istifadə edin. Compose parametrləri equals ilə müqayisə edir, əgər kolleksiya dəyişibsə, lakin equals true qaytarıbsa — funksiya yenidən işə salınmayacaq. Dəyişən kolleksiyalar üçün element səviyyəsində dəyişiklikləri düzgün izləyən SnapshotStateList-dən istifadə edin.
İkinci üsul — sabit hissələrin ayrılması UI-nin ayrıca Composable funksiyalarına. Ekranın bir hissəsi tez-tez dəyişən vəziyyətdən asılı deyilsə, onu parametrlərlə ayrıca funksiyaya çıxarın. Rekompozisiya gəldikdə, sabit funksiya eyni parametrləri alır, Compose onları müqayisə edir və icranı buraxır. Bu, parametrlərin bir hissəsinin dəyişdiyi böyük bir funksiyanın tərkibində bu hissəni yenidən işə salmaqdan daha sərfəlidir.
Üçüncü üsul — LazyColumn-da açarlar. LazyColumn, LazyGrid və digər tənbəl konteynerlərdə item üçün həmişə key göstərin. Açar Compose-a siyahı dəyişdikdə elementləri identifikasiya etməyə imkan verir: əlavə etmə, silmə və ya yerdəyişmə. Açar olmadan Compose hər dəyişiklikdə siyahının bütün elementlərini yenidən işə salır, bu da böyük siyahılarda nəzərəçarpacaq performans itkisinə səbəb olur.
// Optimallaşdırılmış struktur: sabit hissələr ayrıca çıxarılıb
@Composable
fun OptimizedScreen(items: List<Item>) {
Column {
Header() // elementlərdən asılı deyil — rekompozisiya yoxdur
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(items, key = { it.id }) { item ->
ItemRow(item = item) // yalnız dəyişmiş elementlər üçün rekompozisiya
}
}
}
}
@Composable
fun Header() {
Text("Element siyahısı", style = MaterialTheme.typography.headlineMedium)
}
@Composable
fun ItemRow(item: Item) {
Text(item.title)
}
Skipping — Compose-un Composable funksiyasının icrasını buraxdığı mexanizmdir, əgər onun bütün parametrləri dəyişməyibsə. Skipping-in düzgün işləməsi üçün parametr tipləri sabit (stable) olmalıdır. Kotlin kompilyatoru aşağıdakıları sabit kimi qeyd edir: primitiv tiplər (Int, Float, Boolean), String, lambda funksiyaları, həmçinin bütün sahələri sabit və val olan siniflər.
Stability — istifadəçi məlumat siniflərinə əlavə edilə bilən @Stable və ya @Immutable annotasiyasıdır. Sinif dəyişən sahə (var) ehtiva edirsə, kompilyator onu qeyri-sabit hesab edir və Compose belə parametrləri olan funksiyaları buraxa bilməz. Var olan siniflər üçün @Stable istifadə edin, əgər dəyişiklik barədə bildirişin snapshot sistemi vasitəsilə göndəriləcəyinə zəmanət verirsinizsə.
Stability-ni kompilyator flag-ı vasitəsilə yoxlaya bilərsiniz: -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports". O, bütün Composable funksiyalarının və onların parametrlərinin stability göstəricisi ilə siyahısını əks etdirən hesabat generasiya edir. Parametr qeyri-sabitdirsə — skipping mümkün deyil və funksiya hər valideyn rekompozisiyasında yenidən işə salınacaq.
| Tip | Sabitlik | Skipping |
|---|---|---|
| Int, Float, Boolean | Sabit | Bəli |
| String | Sabit | Bəli |
| Lambda | Sabit | Bəli |
| val sahələri olan data class | Sabit | Bəli |
| var sahələri olan data class | Qeyri-sabit | Xeyr |
| List<String> | Qeyri-sabit | Xeyr |
Diqqət edin: List<String> qeyri-sabit hesab olunur, çünki bu interfeysdir, konkret realizasiya deyil. Kotlin Collections Immutable kitabxanasından immutableListOf() istifadə edin və ya siyahını @Stable sinfinə sarın. Lambda həmişə sabitdir, çünki onun equals yalnız referensiyaları müqayisə edir və çağırış yerində yeni lambda yaradıldıqda valideyn funksiyası da yenidən işə salınır.
Rekompozisiyaların monitorinqi üçün Android Studio Compose Recomposition Counts rejimi ilə Layout Inspector təqdim edir. Bu rejimdə hər bir Composable funksiyası rekompozisiyaların sayını və yenidən işə salınma səbəblərini göstərir. Bu, çox tez-tez rekompozisiya olunan funksiyaları tapmağa və kök səbəbi müəyyən etməyə imkan verir — qeyri-sabit parametrlər və ya lazımsız State asılılıqları.
Əlavə alətlər: Compose Metrics (instrumentation testləri vasitəsilə statistika toplanması) və Recomposition Timer (hər funksiyanın icra müddətinin ölçülməsi). Google bu alətləri profil zamanı işə salmağı və release versiyalarında söndürməyi tövsiyə edir, çünki onlar hər rekompozisiyaya 20%-ə qədər overhead əlavə edir.
Rekompozisiyaları təhlil edərkən unnecessary recomposition nümunələrini axtarın: funksiya yenidən işə salınır, halbuki onun nəticə UI dəyişməməlidir. Tez-tez səbəb remember olmadan lambdaların istifadəsidir, hər dəfə yeni lambda obyekti yaradılır və Compose parametri dəyişmiş hesab edir. Həll yolu: lambdaları sabit tutmalarla remember { } içinə sarma.
// Pis: hər valideyn rekompozisiyasında yeni lambda
@Composable
fun Parent() {
Child(onClick = { doSomething() }) // hər dəfə yeni lambda
}
// Yaxşı: remember lambdanı sabitləşdirir
@Composable
fun Parent() {
val onClick = remember { { doSomething() } }
Child(onClick = onClick) // eyni referensiya
}
Tez-tez verilən suallar
Xeyr, rekompozisiya yalnız Composition mərhələsidir. Ondan sonra Layout və Drawing icra olunur. Əgər rekompozisiyadan sonra elementlərin ölçüləri və yerləşməsi dəyişməyibsə, Layout və Drawing tamamilə buraxıla bilər, bu da GPU resurslarına qənaət edir.
Animasiyalar zamanı rekompozisiya saniyədə 120 dəfəyə qədər işə düşə bilər (120fps). Adi qarşılıqlı əlaqə üçün — saniyədə 10–60 dəfə. Hər rekompozisiyanın kadr büdcəsinə (8–16 ms) sığması vacibdir, əks halda tətbiq ləngiyəcək.
Səbəb — valideyn funksiyasından parametrin dəyişməsidir. Valideyn (öz səbəbindən) yenidən işə salınır və yeni dəyər ötürür. Bunun qarşısını almaq üçün parametrlərin stability-ni yoxlayın və lambdaları və hesablanmış dəyərləri sabitləşdirmək üçün remember istifadə edin.
Birbaşa söndürmə yoxdur, lakin məcburi skipping var — readInComposition vasitəsilə State funksiya gövdəsindən kənarda oxunur, bu da asılılığı qeydə almır. Bunu ehtiyatla istifadə edin: funksiya dəyişikliklərə reaksiya verməyəcək, bu da köhnəlmiş UI-ya səbəb ola bilər.
Composition daha bahalıdır, çünki bütün slotları və ağac düyünlərini sıfırdan yaradır. Recomposition mövcud slotları təkrar istifadə edir və yalnız onların dəyərlərini yeniləyir. Praktikada ekranın Composition-ı 2–10 ms, bir elementin rekompozisiyası isə 0.1–1 ms çəkir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun