Jetpack Compose, Android için modern bir bildirime dayalı kullanıcı arayüzü araç setidir. Compose, ön uç görünümlerini zorunlu olarak değiştirmenize gerek kalmadan uygulama kullanıcı arayüzünüzü oluşturmanıza olanak tanıyan bir bildirimsel API sağlayarak uygulama kullanıcı arayüzünüzü yazma ve sürdürme sürecini basitleştirir. Bu terminolojinin biraz açıklanması gerekiyor ancak sonuçları uygulama tasarımınız açısından önemlidir.
Bildirimsel programlama paradigması
Geçmişte, Android görünüm hiyerarşisi bir kullanıcı arayüzü widget'ları ağacı olarak gösterilebiliyordu. Uygulamanın durumu, kullanıcı etkileşimleri gibi nedenlerle değiştiğinde kullanıcı arayüzü hiyerarşisinin güncel verileri gösterecek şekilde güncellenmesi gerekir.
Kullanıcı arayüzünü güncellemenin en yaygın yolu, findViewById()
gibi işlevleri kullanarak ağaçta ilerlemek ve button.setText(String)
, container.addChild(View)
veya img.setImageBitmap(Bitmap)
gibi yöntemleri çağırarak düğümleri değiştirmektir. Bu yöntemler, widget'ın dahili durumunu değiştirir.
Görüntülemeleri manuel olarak değiştirmek hata olasılığını artırır. Bir veri parçası birden fazla yerde oluşturuluyorsa bunu gösteren görünümlerden birini güncellemeyi unutabilirsiniz. Bu durum, iki güncelleme beklenmedik bir şekilde çakıştığında yasa dışı durumlara da yol açabilir. Örneğin, bir güncelleme, kullanıcı arayüzünden yeni kaldırılan bir düğümün değerini ayarlamaya çalışabilir. Genel olarak, yazılım bakımı karmaşıklığı, güncellenmesi gereken görünüm sayısıyla birlikte artar.
Son birkaç yıldır sektörün tamamı bildirimsel kullanıcı arayüzü modeline geçmeye başladı. Bu model, kullanıcı arayüzü oluşturma ve güncelleme ile ilişkili mühendislik işlemlerini basitleştirir. Bu teknik, tüm ekranı baştan itibaren kavramsal olarak yeniden oluşturup yalnızca gerekli değişiklikleri uygulayarak çalışır. Bu yaklaşım, durum bilgisi olan bir görünüm hiyerarşisinin manuel olarak güncellenmesinin karmaşıklığını önler. Compose, bildirime dayalı bir kullanıcı arayüzü çerçevesidir.
Ekranın tamamını yeniden oluşturmanın zorluklarından biri, zaman, bilgi işlem gücü ve pil kullanımı açısından maliyetli olabilmesidir. Compose, bu maliyeti azaltmak için kullanıcı arayüzünün hangi bölümlerinin herhangi bir zamanda yeniden çizilmesi gerektiğini akıllıca seçer. Bu durum, Yeniden Oluşturma bölümünde ele alındığı gibi, kullanıcı arayüzü bileşenlerinizi tasarlama şekliniz üzerinde bazı etkiler yaratır.
Örnek bir composable işlev
Compose'u kullanarak, veri alan ve kullanıcı arayüzü öğeleri yayan bir dizi birleştirilebilir işlev tanımlayarak kullanıcı arayüzünüzü oluşturabilirsiniz. Örneğin, String
alanını alan ve bir selamlama mesajı gösteren Text
widget'ı yayan bir Greeting
widget'ı.

Bu işlevle ilgili dikkat edilmesi gereken birkaç nokta:
- Ek açıklama: İşlev,
@Composable
ek açıklamasıyla açıklanır. Tüm composable işlevler bu ek açıklamaya sahip olmalıdır. Bu ek açıklama, Compose derleyicisine bu işlevin verileri kullanıcı arayüzüne dönüştürmek için tasarlandığını bildirir. - Veri girişi: İşlev, veri alır. Composable işlevler, uygulamanın mantığının kullanıcı arayüzünü tanımlamasına olanak tanıyan parametreleri kabul edebilir. Bu örnekte, widget'ımız
String
kabul ediyor. Böylece kullanıcıyı adıyla selamlayabiliyor. - Kullanıcı arayüzü gösterimi: İşlev, metni kullanıcı arayüzünde gösterir. Bu işlem, metin kullanıcı arayüzü öğesini oluşturan
Text()
composable işlevi çağrılarak yapılır. Composable işlevler, diğer composable işlevleri çağırarak kullanıcı arayüzü hiyerarşisi oluşturur. - Dönüş değeri yok: İşlev herhangi bir değer döndürmez. Kullanıcı arayüzü yayan Compose işlevlerinin herhangi bir şey döndürmesi gerekmez. Bunun nedeni, kullanıcı arayüzü widget'ları oluşturmak yerine hedef ekran durumunu açıklamalarıdır.
Özellikler: Bu işlev hızlıdır, idempotent'tır ve yan etkileri yoktur.
- İşlev, aynı bağımsız değişkenle birden çok kez çağrıldığında aynı şekilde davranır ve genel değişkenler veya
random()
çağrıları gibi diğer değerleri kullanmaz. - Bu işlev, özellikleri veya genel değişkenleri değiştirme gibi yan etkiler olmadan kullanıcı arayüzünü tanımlar.
Genel olarak, Yeniden Oluşturma bölümünde belirtilen nedenlerden dolayı tüm composable işlevler bu özelliklerle yazılmalıdır.
- İşlev, aynı bağımsız değişkenle birden çok kez çağrıldığında aynı şekilde davranır ve genel değişkenler veya
Bildirimsel paradigma değişikliği
Birçok zorunlu nesne yönelimli kullanıcı arayüzü araç setinde, kullanıcı arayüzünü bir widget ağacı oluşturarak başlatırsınız. Bu işlem genellikle bir XML düzen dosyasını genişleterek yapılır. Her widget kendi dahili durumunu korur ve uygulama mantığının widget ile etkileşime girmesine olanak tanıyan getter ve setter yöntemlerini kullanıma sunar.
Compose'un bildirimsel yaklaşımında widget'lar nispeten durumsuz olup ayarlayıcı veya alıcı işlevlerini kullanıma sunmaz. Aslında widget'lar nesne olarak gösterilmez.
Aynı composable işlevi farklı bağımsız değişkenlerle çağırarak kullanıcı arayüzünü güncellersiniz. Bu, ViewModel
gibi mimari kalıplara durum sağlamayı kolaylaştırır. Bu kalıplar, Uygulama mimarisi kılavuzunda açıklanmıştır. Daha sonra, gözlemlenebilir veriler her güncellendiğinde mevcut uygulama durumunu kullanıcı arayüzüne dönüştürmekle composable'larınız ilgilenir.

Kullanıcı, kullanıcı arayüzüyle etkileşim kurduğunda kullanıcı arayüzü onClick
gibi etkinlikler oluşturur.
Bu etkinlikler, uygulama mantığını bilgilendirmelidir. Bu mantık daha sonra uygulamanın durumunu değiştirebilir.
Durum değiştiğinde, composable işlevler yeni verilerle tekrar çağrılır. Bu durum, kullanıcı arayüzü öğelerinin yeniden çizilmesine neden olur. Bu sürece yeniden oluşturma denir.

Dinamik içerik
Composable işlevler XML yerine Kotlin ile yazıldığından diğer Kotlin kodları kadar dinamik olabilir. Örneğin, bir kullanıcı listesini karşılayan bir kullanıcı arayüzü oluşturmak istediğinizi varsayalım:
@Composable fun Greeting(names: List<String>) { for (name in names) { Text("Hello $name") } }
Bu işlev, bir ad listesi alır ve her kullanıcı için bir selamlama oluşturur.
Composable işlevler oldukça karmaşık olabilir. Belirli bir kullanıcı arayüzü öğesini göstermek isteyip istemediğinize karar vermek için if
ifadelerini kullanabilirsiniz. Döngüleri kullanabilirsiniz. Yardımcı işlevleri çağırabilirsiniz. Temel dilin tüm esnekliğinden yararlanabilirsiniz.
Bu güç ve esneklik, Jetpack Compose'un temel avantajlarından biridir.
Yeniden oluşturma
Zorunlu kullanıcı arayüzü modelinde, bir widget'ı değiştirmek için widget'ta bir ayarlayıcı çağırarak widget'ın dahili durumunu değiştirirsiniz. Compose'da, composable işlevi yeni verilerle tekrar çağırırsınız. Bu işlem, işlevin yeniden oluşturulmasına neden olur. İşlev tarafından yayınlanan widget'lar, gerekirse yeni verilerle yeniden çizilir. Compose çerçevesi, yalnızca değişen bileşenleri akıllı bir şekilde yeniden oluşturabilir.
Örneğin, bir düğme görüntüleyen şu composable işlevi ele alalım:
@Composable fun ClickCounter(clicks: Int, onClick: () -> Unit) { Button(onClick = onClick) { Text("I've been clicked $clicks times") } }
Arayan, düğmeyi her tıkladığında clicks
değerini günceller.
Compose, yeni değeri göstermek için lambda'yı Text
işleviyle tekrar çağırır. Bu işleme yeniden oluşturma denir. Değere bağlı olmayan diğer işlevler yeniden oluşturulmaz.
Daha önce de belirttiğimiz gibi, kullanıcı arayüzü ağacının tamamını yeniden oluşturmak hesaplama açısından maliyetli olabilir. Bu da işlem gücü ve pil ömrünü etkiler. Compose, bu sorunu akıllı yeniden oluşturma özelliğiyle çözüyor.
Yeniden oluşturma, girişler değiştiğinde composable işlevlerinizi tekrar çağırma işlemidir. Oluşturma, yeni girişlere göre yeniden oluşturma yaptığında yalnızca değişmiş olabilecek işlevleri veya lambda'ları çağırır ve geri kalanları atlar. Compose, değişmeyen parametrelerle işlevleri veya lambda'ları atlayarak verimli bir şekilde yeniden oluşturur.
Bir işlevin yeniden oluşturulması atlanabileceğinden, birleştirilebilir işlevlerin yürütülmesinden kaynaklanan yan etkilere asla güvenmeyin. Bu durumda kullanıcılar uygulamanızda garip ve tahmin edilemeyen davranışlarla karşılaşabilir. Yan etki, uygulamanızın geri kalanında görülebilen herhangi bir değişikliktir. Örneğin, aşağıdaki işlemlerin tümü tehlikeli yan etkilerdir:
- Paylaşılan bir nesnenin özelliğine yazma
ViewModel
konumunda bir gözlemlenebilir öğeyi güncelleme- Paylaşılan tercihleri güncelleme
Bir animasyon oluşturulurken olduğu gibi, birleştirilebilir işlevler her karede yeniden yürütülebilir. Animasyonlar sırasında takılmayı önlemek için birleştirilebilir işlevler hızlı olmalıdır. Paylaşılan tercihlerden okuma gibi maliyetli işlemler yapmanız gerekiyorsa bunu arka plan coroutine'inde yapın ve değer sonucunu parametre olarak composable işlevine iletin.
Örneğin, bu kod, SharedPreferences
içindeki bir değeri güncellemek için composable oluşturur. Composable, paylaşılan tercihlerden okuma veya yazma işlemi yapmamalıdır. Bunun yerine, bu kod okuma ve yazma işlemlerini arka planda çalışan bir ViewModel
rutinine taşır. Uygulama mantığı, güncellemeyi tetiklemek için geri çağırma ile geçerli değeri iletir.
@Composable fun SharedPrefsToggle( text: String, value: Boolean, onValueChanged: (Boolean) -> Unit ) { Row { Text(text) Checkbox(checked = value, onCheckedChange = onValueChanged) } }
Bu belgede, Oluştur özelliğini kullanırken dikkat etmeniz gereken bazı noktalar ele alınmaktadır:
- Yeniden oluşturma, mümkün olduğunca çok sayıda composable işlevi ve lambda'yı atlar.
- Yeniden oluşturma işlemi iyimserdir ve iptal edilebilir.
- Bir composable işlevi, animasyonun her karesi kadar sık çalıştırılabilir.
- Composable işlevler paralel olarak yürütülebilir.
- Composable işlevler herhangi bir sırada yürütülebilir.
Aşağıdaki bölümlerde, yeniden oluşturmayı desteklemek için birleştirilebilir işlevlerin nasıl oluşturulacağı ele alınacaktır. Her durumda, en iyi uygulama, birleştirilebilir işlevlerinizi hızlı, idempotent ve yan etkisiz tutmaktır.
Yeniden oluşturma işlemi mümkün olduğunca fazla bölümü atlar.
Kullanıcı arayüzünüzün bazı bölümleri geçersiz olduğunda Compose, yalnızca güncellenmesi gereken bölümleri yeniden oluşturmak için elinden geleni yapar. Bu nedenle, kullanıcı arayüzü ağacında daha yüksek veya daha düşük bir composable'ı yürütmeden tek bir Button
composable'ı yeniden çalıştırmak için atlayabilir.
Her composable işlev ve lambda kendi başına yeniden oluşturulabilir. Aşağıdaki örnekte, bir liste oluşturulurken yeniden oluşturma işleminin bazı öğeleri nasıl atlayabileceği gösterilmektedir:
/** * Display a list of names the user can click with a header */ @Composable fun NamePicker( header: String, names: List<String>, onNameClicked: (String) -> Unit ) { Column { // this will recompose when [header] changes, but not when [names] changes Text(header, style = MaterialTheme.typography.bodyLarge) HorizontalDivider() // LazyColumn is the Compose version of a RecyclerView. // The lambda passed to items() is similar to a RecyclerView.ViewHolder. LazyColumn { items(names) { name -> // When an item's [name] updates, the adapter for that item // will recompose. This will not recompose when [header] changes NamePickerItem(name, onNameClicked) } } } } /** * Display a single name the user can click. */ @Composable private fun NamePickerItem(name: String, onClicked: (String) -> Unit) { Text(name, Modifier.clickable(onClick = { onClicked(name) })) }
Bu kapsamların her biri, yeniden oluşturma sırasında yürütülecek tek şey olabilir.
header
değiştiğinde Compose, üst öğelerinden herhangi birini yürütmeden Column
lambda'sına atlayabilir. Ayrıca Column
yürütülürken names
değişmediyse Compose, LazyColumn
öğelerini atlamayı seçebilir.
Yine, tüm composable işlevler veya lambda'lar yan etkisiz olmalıdır. Bir yan etki gerçekleştirmeniz gerektiğinde bunu bir geri çağırma işlevinden tetikleyin.
Yeniden oluşturma iyimserdir
Yeniden oluşturma, Compose'un bir composable'ın parametrelerinin değişmiş olabileceğini düşündüğü her zaman başlar. Yeniden oluşturma iyimserdir. Bu,Compose'un parametreler tekrar değişmeden önce yeniden oluşturmayı tamamlamayı beklediği anlamına gelir. Bir parametre, yeniden oluşturma işlemi tamamlanmadan önce değişirse Compose, yeniden oluşturma işlemini iptal edip yeni parametreyle yeniden başlatabilir.
Yeniden oluşturma işlemi iptal edildiğinde Compose, yeniden oluşturma işlemindeki kullanıcı arayüzü ağacını atar. Kullanıcı arayüzünün görüntülenmesine bağlı yan etkileriniz varsa kompozisyon iptal edilse bile yan etki uygulanır. Bu durum, uygulamanın tutarsız bir durumda olmasına neden olabilir.
İyimser yeniden oluşturmayı işlemek için tüm composable işlevlerin ve lambda'ların idempotent ve yan etkisiz olduğunu doğrulayın.
Composable işlevler oldukça sık çalışabilir
Bazı durumlarda, composable işlevler bir kullanıcı arayüzü animasyonunun her karesi için çalışabilir. İşlev, cihaz depolama alanından okuma gibi maliyetli işlemler gerçekleştiriyorsa kullanıcı arayüzünde takılmaya neden olabilir.
Örneğin, widget'ınız cihaz ayarlarını okumaya çalışırsa bu ayarları saniyede yüzlerce kez okuyabilir ve bu durum uygulamanızın performansını olumsuz etkileyebilir.
Bir composable işlevin veriye ihtiyacı varsa bu veriler için parametreler tanımlayın. Ardından, pahalı işlemleri kompozisyonun dışında başka bir iş parçacığına taşıyabilir ve sonuçta elde edilen değeri mutableStateOf
veya LiveData
kullanarak parametre olarak composable işlevine iletebilirsiniz.
Composable işlevler paralel olarak çalıştırılabilir.
Compose, composable işlevleri paralel olarak çalıştırarak yeniden oluşturmayı optimize edebilir. Bu sayede Compose, birden fazla çekirdekten yararlanabilir ve ekranda olmayan composable işlevlerini daha düşük bir öncelikte çalıştırabilir.
Bu optimizasyon, bir composable işlevin arka plan iş parçacıkları havuzunda yürütülebileceği anlamına gelir.
Bir composable işlevi, ViewModel
üzerinde bir işlevi çağırırsa Compose, bu işlevi aynı anda birden fazla iş parçacığından çağırabilir.
Uygulamanızın doğru şekilde çalıştığını doğrulamak için tüm composable işlevlerin yan etkisi olmamalıdır. Bunun yerine, her zaman kullanıcı arayüzü iş parçacığında yürütülen onClick
gibi geri çağırmalardan yan etkileri tetikleyin.
Bir composable işlev çağrıldığında, çağıran işlevden farklı bir iş parçacığında çağrılabilir. Bu nedenle, hem iş parçacığı açısından güvenli olmadığı hem de composable lambda'nın izin verilmeyen bir yan etkisi olduğu için composable lambda'daki değişkenleri değiştiren kodlardan kaçınılmalıdır.
Bir listeyi ve sayısını gösteren bir composable'ı gösteren örneği burada bulabilirsiniz:
@Composable fun ListComposable(myList: List<String>) { Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item") } } Text("Count: ${myList.size}") } }
Bu kodun yan etkisi yoktur ve giriş listesini kullanıcı arayüzüne dönüştürür. Bu, küçük bir listeyi görüntülemek için harika bir kod. Ancak işlev yerel bir değişkene yazıyorsa bu kod iş parçacığı açısından güvenli veya doğru olmaz:
@Composable fun ListWithBug(myList: List<String>) { var items = 0 Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Card { Text("Item: $item") items++ // Avoid! Side-effect of the column recomposing. } } } Text("Count: $items") } }
Bu örnekte, items
her yeniden oluşturmada değiştirilir. Bu, animasyonun her karesi veya listenin güncellendiği zaman olabilir. Her iki durumda da kullanıcı arayüzünde yanlış sayı gösterilir. Bu nedenle, bu tür yazma işlemleri Oluşturma'da desteklenmez. Bu yazma işlemlerini yasaklayarak, çerçevenin işlenebilir lambda'ları yürütmek için iş parçacıklarını değiştirmesine izin veririz.
Composable işlevler herhangi bir sırada yürütülebilir.
Bir composable işlevinin koduna baktığınızda kodun göründüğü sırayla çalıştırıldığını düşünebilirsiniz. Ancak bu durumun geçerli olacağı garanti edilmez. Bir composable işlevi, diğer composable işlevlere yapılan çağrıları içeriyorsa bu işlevler herhangi bir sırada çalışabilir. Oluşturma, bazı kullanıcı arayüzü öğelerinin diğerlerinden daha yüksek öncelikli olduğunu tanıma ve bunları önce çizme seçeneğine sahiptir.
Örneğin, bir sekme düzeninde üç ekran çizmek için aşağıdaki gibi bir kodunuz olduğunu varsayalım:
@Composable fun ButtonRow() { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } }
StartScreen
, MiddleScreen
ve EndScreen
numaralarına yapılan aramalar herhangi bir sırada gerçekleşebilir. Bu nedenle, örneğin StartScreen()
'nın bazı genel değişkenleri (yan etki) ayarlaması ve MiddleScreen()
'nın bu değişiklikten yararlanması mümkün değildir. Bunun yerine, bu işlevlerin her birinin bağımsız olması gerekir.
Daha fazla bilgi
Compose'da nasıl düşüneceğiniz ve composable işlevler hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara göz atın.
Videolar
Sizin için önerilenler
- Not: Bağlantı metni, JavaScript kapalıyken gösterilir.
- Jetpack Compose için Kotlin
- State ve Jetpack Compose
- Jetpack Compose mimari katmanları