Jetpack Compose, Android için modern bir bildirim temelli Kullanıcı Arayüzü Araç Seti'dir. Compose, ön uç görünümlerini mutlaka değiştirmeden uygulama kullanıcı arayüzünüzü oluşturmanıza olanak tanıyan bir bildirim API'si sağlayarak uygulamanızın kullanıcı arayüzünü yazmayı ve bakımını kolaylaştırır. Bu terminoloji hakkında bazı açıklamalara ihtiyaç vardır, ancak sonuçları uygulamanızın tasarımı açısından önemlidir.
Bildirim temelli programlama paradigması
Geçmişte, Android görünüm hiyerarşisi kullanıcı arayüzü widget'larından oluşan bir ağaç olarak temsil ediliyordu. Uygulamanın durumu, kullanıcı etkileşimleri gibi şeyler nedeniyle değiştiğinden, kullanıcı arayüzü hiyerarşisinin mevcut 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ünümleri manuel olarak değiştirmek hata olasılığını artırır. Bir veri parçası birden fazla yerde oluşturulursa bunları gösteren görünümlerden birini güncellemeyi kolayca unutabilirsiniz. İki güncelleme beklenmedik bir şekilde çakıştığında yasa dışı durumlar oluşturmak da kolaydır. Örneğin, bir güncelleme, kullanıcı arayüzünden yeni kaldırılmış bir düğümün değerini ayarlamaya çalışabilir. Genel olarak, güncelleme gerektiren görünümlerin sayısı arttıkça yazılım bakımının karmaşıklığı da artar.
Son birkaç yıldır sektör genelinde, kullanıcı arayüzlerinin oluşturulması ve güncellenmesiyle ilişkili mühendisliği büyük ölçüde basitleştiren bildirim temelli kullanıcı arayüzü modeline geçiş yapılmaya başlandı. Teknik, tüm ekranı kavramsal olarak sıfırdan yeniden oluşturup yalnızca gerekli değişiklikleri uygulayarak çalışır. Bu yaklaşım, durum bilgili görünüm hiyerarşisini manuel olarak güncellemenin karmaşıklığını önler. Oluşturma, bildirim temelli bir kullanıcı arayüzü çerçevesidir.
Tüm ekranın yeniden üretilmesiyle ilgili zorluklardan biri, zaman, bilgi işlem gücü ve pil kullanımı açısından potansiyel olarak pahalı olmasıdır. Compose bu maliyeti azaltmak için herhangi bir zamanda kullanıcı arayüzünün hangi bölümlerinin yeniden çizilmesi gerektiğini akıllı bir şekilde seçer. Bunun, Yeniden Oluşturma bölümünde açıklandığı gibi kullanıcı arayüzü bileşenlerinizi tasarlama şekliniz üzerinde bazı etkileri olabilir.
Basit bir composable işlev
Compose'u kullanarak veri alan ve kullanıcı arayüzü öğeleri yayınlayan bir composable işlev grubu tanımlayarak kullanıcı arayüzünüzü oluşturabilirsiniz. Basit bir örnek, String
alan ve karşılama mesajı gösteren bir Text
widget'ı yayınlayan Greeting
widget'ıdır.
Şekil 1. Verileri aktaran ve bunu ekranda bir metin widget'ı oluşturmak için kullanan basit bir composable işlev.
Bu işlevle ilgili dikkat edilmesi gereken birkaç nokta:
İşleve
@Composable
ek açıklaması eklenir. Tüm Composable işlevlerinde bu ek açıklama bulunmalıdır. Bu ek açıklama, Compose derleyicisine bu işlevin verileri kullanıcı arayüzüne dönüştürmek olduğunu bildirir.İşlev, verileri alır. Özelleştirilebilir işlevler, uygulama mantığının kullanıcı arayüzünü tanımlamasına olanak tanıyan parametreleri kabul edebilir. Bu örnekte widget'ımız, kullanıcıyı adıyla karşılayabilmek için
String
değerini kabul eder.İşlev, metni kullanıcı arayüzünde görüntüler. Bunu, aslında metin kullanıcı arayüzü öğesini oluşturan
Text()
composable işlevini çağırarak yapar. Özelleştirilebilir işlevler, diğer composable işlevleri çağırarak kullanıcı arayüzü hiyerarşisi oluşturur.İşlev hiçbir şey döndürmez. Kullanıcı arayüzü yayınlayan işlevleri, kullanıcı arayüzü widget'ları oluşturmak yerine istenen ekran durumunu açıkladıkları için hiçbir şey döndürmesine gerek kalmadan oluşturun.
Bu işlev hızlıdır, eşdeğerdir ve yan etkisi 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. - İşlev, kullanıcı arayüzünü, değiştirilen özellikler veya genel değişkenler gibi herhangi bir yan etki olmadan tanımlar.
Genel olarak, tüm composable işlevleri Recomposition bölümünde açıklanan nedenlerle 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
Bildirim temelli paradigma değişimi
Birçok zorunlu nesne tabanlı kullanıcı arayüzü araç setinde, bir widget ağacını hazırlayarak kullanıcı arayüzünü ilk kullanıma hazırlarsınız. Bunu genellikle bir XML düzen dosyasını şişirerek yaparsınız. Her widget kendi dahili durumunu korur ve uygulama mantığının widget ile etkileşim kurmasına olanak tanıyan alıcı ve belirleyici yöntemleri sunar.
Compose'un bildirim temelli yaklaşımında widget'lar göreceli olarak durum bilgisizdir ve ayarlayıcı veya alıcı işlevlerini açığa çıkarmaz. Aslında, widget'lar nesne olarak ortaya çıkmaz. Kullanıcı arayüzünü, aynı composable işlevi farklı bağımsız değişkenlerle çağırarak güncellersiniz. Uygulama mimarisi rehberinde açıklandığı gibi, ViewModel
gibi mimari kalıpları kolayca belirtebilirsiniz. Ardından composable'larınız, her gözlemlenebilir veri güncellemesinde mevcut uygulama durumunu bir kullanıcı arayüzüne dönüştürmekten sorumludur.
2. Şekil. Uygulama mantığı, üst düzey composable işlevine veri sağlar. Bu işlev, diğer composable'ları çağırarak kullanıcı arayüzünü tanımlamak için verileri kullanır ve uygun verileri bu composable'lara ve hiyerarşide aşağı doğru iletir.
Kullanıcı, kullanıcı arayüzüyle etkileşimde bulunduğunda, kullanıcı arayüzü onClick
gibi etkinlikleri öne çıkarır.
Bu etkinlikler, uygulama mantığına bildirim gönderir. Uygulama mantığı, uygulamanın durumunu değiştirebilir.
Durum değiştiğinde, composable işlevler yeni verilerle tekrar çağrılır. Bu, kullanıcı arayüzü öğelerinin yeniden çizilmesine neden olur. Bu sürece yeniden oluşturma adı verilir.
3. Şekil. Kullanıcı, bir kullanıcı arayüzü öğesiyle etkileşimde bulunarak bir etkinliğin tetiklenmesine neden oldu. Uygulama mantığı etkinliğe yanıt verir, ardından composable işlevler gerekirse yeni parametrelerle otomatik olarak tekrar çağrılır.
Dinamik içerik
Oluşturulabilir işlevler XML yerine Kotlin dilinde yazıldığı için diğer herhangi bir Kotlin kodu kadar dinamik olabilirler. Örneğin, 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 karşılama mesajı oluşturur.
Özelleştirilebilir 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ğine sahip olursunuz. Bu güç ve esneklik, Jetpack Composer'ın en önemli avantajlarından biridir.
Yeniden oluşturma
Zorunlu kullanıcı arayüzü modelinde, bir widget'ı değiştirmek için, widget'ın dahili durumunu değiştirmesi için widget'ta bir setter çağırırsınız. Compose'da composable işlevini 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ştirilen bileşenleri akıllıca yeniden derleyebilir.
Örneğin, 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") } }
Düğme her tıklandığında, arayan kişi clicks
değerini günceller.
Compose, yeni değeri göstermek için lambda'yı Text
işleviyle yeniden çağırır. Bu sürece yeniden oluşturma adı verilir. Değere bağlı olmayan diğer işlevler yeniden derlenmez.
Konuştuğumuz gibi, kullanıcı arayüzü ağacının tamamını yeniden oluşturmak hesaplama açısından maliyetli olabilir. Bu da bilgi işlem gücü ve pil ömrü kullanır. Compose bu akıllı yeniden düzenleme ile bu sorunu çözer.
Yeniden derleme, girişler değiştiğinde composable işlevlerinizi tekrar çağırma işlemidir. Bu işlev, işlev girişleri değiştiğinde gerçekleşir. Compose yeni girişlere göre yeniden derlendiğinde yalnızca değişmiş olabilecek işlevleri veya lambdaları çağırır ve geri kalanları atlar. Compose, parametreleri değiştirilmemiş tüm işlevleri veya lambdaları atlayarak verimli bir şekilde yeniden oluşturabilir.
İşlevin yeniden oluşturulması atlanabilir. Bunu yaparsanız kullanıcılar uygulamanızda tuhaf ve tahmin edilemez davranışlarla karşılaşabilir. Yan etki, uygulamanızın geri kalanı tarafından görülebilen her türlü değişikliktir. Örneğin, aşağıdaki işlemlerin tümü tehlikeli yan etkilerdir:
- Paylaşılan bir nesnenin özelliğine yazma
ViewModel
ürününde bir gözlemlenebilir öğe güncelleniyor- Paylaşılan tercihler güncelleniyor
Oluşturulabilir işlevler her kare kadar sıklıkta (ör. bir animasyon oluşturulurken) yeniden yürütülebilir. Oluşturulabilir işlevler, animasyonlar sırasında olumsuzluklardan kaçınmak için hızlı olmalıdır. Paylaşılan tercihlerden okuma gibi pahalı işlemler yapmanız gerekirse bunu bir arka plan eş yordasında yapın ve değer sonucunu composable işleve parametre olarak aktarın.
Örneğin bu kod, SharedPreferences
içindeki bir değeri güncellemek için bir composable oluşturur. composable, paylaşılan tercihlerin kendisini okumamalı veya yazmamalıdır. Bunun yerine, bu kod, okuma ve yazma işlemlerini arka plan eş yordamındaki bir ViewModel
öğesine taşır. Uygulama mantığı, bir güncellemeyi tetiklemek için geçerli değeri bir geri çağırma ile aktarır.
@Composable fun SharedPrefsToggle( text: String, value: Boolean, onValueChanged: (Boolean) -> Unit ) { Row { Text(text) Checkbox(checked = value, onCheckedChange = onValueChanged) } }
Bu dokümanda, Oluştur'u kullanırken dikkat etmeniz gereken bazı konular ele alınmaktadır:
- Oluşturulabilir işlevler herhangi bir sırada yürütülebilir.
- Oluşturulabilir işlevler paralel olarak yürütülebilir.
- Yeniden oluşturma işlemi mümkün olduğunca çok composable işlev ve lambda atlar.
- Yeniden oluşturma işlemi iyimser ve iptal edilebilir.
- composable bir işlev, bir animasyonun her karesi kadar sık çalıştırılabilir.
Aşağıdaki bölümlerde, yeniden oluşturmayı desteklemek için composable işlevlerin nasıl oluşturulacağı ele alınmaktadır. Her durumda en iyi uygulama, composable işlevlerinizi hızlı, benzersiz ve yan efektlerden uzak tutmaktır.
Oluşturulabilir işlevler herhangi bir sırada yürütülebilir
composable işlevi için koda bakarsanız kodun göründüğü sırayla çalıştığını varsayabilirsiniz. Ancak bu her zaman doğru olmayabilir. composable işlev, diğer composable işlevlere çağrı 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 fark edip 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
çağrıları herhangi bir sırada gerçekleşebilir. Diğer bir deyişle, örneğin, StartScreen()
'nin bir global değişken (bir yan etki) ayarlamasına ve MiddleScreen()
adlı kullanıcının bu değişiklikten yararlanmasına izin veremezsiniz. Bunun yerine, bu işlevlerin her birinin bağımsız olması gerekir.
Oluşturulabilir işlevler paralel olarak çalışabilir
Oluşturma, composable işlevlerini paralel olarak çalıştırarak yeniden oluşturma işlemini optimize edebilir. Böylece, Compose birden fazla çekirdekten yararlanabilir ve ekranda olmayan composable işlevleri daha düşük öncelikli olarak çalıştırabilir.
Bu optimizasyon, composable işlevinin arka plan iş parçacıklarından oluşan bir havuz içinde yürütülebileceği anlamına gelir. composable bir işlev ViewModel
üzerinde bir işlev çağırırsa, Compose bu işlevi aynı anda birkaç iş parçacığından çağırabilir.
Uygulamanızın doğru şekilde çalıştığından emin olmak için tüm composable işlevlerinde yan etki olmamalıdır. Bunun yerine, her zaman kullanıcı arayüzü iş parçacığında yürütülen onClick
gibi geri çağırmaların yan etkilerini tetikleyin.
composable bir işlev çağrıldığında, çağrı arayandan farklı bir iş parçacığında gerçekleşebilir. Bu, composable bir lambda içindeki değişkenleri değiştiren koddan kaçınılması gerektiği anlamına gelir. Hem bu kod iş parçacığı güvenli olmadığı hem de composable lambda'nın izin verilmeyen yan etkisidir.
Liste ve sayısını gösteren bir composable örneğini 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 kod, yan etkiler içermez ve giriş listesini kullanıcı arayüzüne dönüştürür. Bu, küçük bir listeyi görüntülemek için çok iyi bir koddur. Ancak, işlev bir yerel değişkene yazarsa bu kod iş parçacığı güvenli veya doğru olmaz:
@Composable @Deprecated("Example with bug") fun ListWithBug(myList: List<String>) { var items = 0 Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item") items++ // Avoid! Side-effect of the column recomposing. } } Text("Count: $items") } }
Bu örnekte, items
her yeniden oluşturmada değiştirilmiştir. Bu, bir animasyonun her karesi veya liste güncellendiğinde olabilir. Her iki durumda da kullanıcı arayüzü
yanlış sayıyı görüntüler. Bu nedenle, bu tür yazma işlemleri Composer'da desteklenmez. Bu yazma işlemleri yasaklanarak, çerçevenin composable lambda'ları yürütmek için iş parçacıklarını değiştirmesine izin verilir.
Yeniden oluşturma işlemini mümkün olduğunca fazla atlama
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 düzenlemek için elinden geleni yapar. Bu, tek bir Button'ın composable'ı kullanıcı arayüzü ağacında üzerindeki veya altındaki composable'ları yürütmeden yeniden çalıştırmaya atlayabileceği anlamına gelir.
Her composable işlev ve lambda kendiliğinden yeniden oluşturulabilir. Aşağıda, yeniden oluşturma işleminin bir liste oluştururken bazı öğeleri nasıl atlayabileceğini gösteren bir örnek verilmiştir:
/** * 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) Divider() // 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 düzenleme sırasında yürütülecek tek şey olabilir.
header
değiştiğinde Compose, üst öğelerinden hiçbirini yürütmeden Column
lambda'ya atlayabilir. Ayrıca, names
değişmediyse Compose Column
öğesini yürütürken LazyColumn
öğelerini atlamayı seçebilir.
Aynı şekilde, tüm composable fonksiyonları veya lambda'ları yürütürken yan etki olmamalıdır. Bir yan etki gerçekleştirmeniz gerektiğinde, geri çağırmayı tetikleyin.
Yeniden düzenleme iyimser
Compose bir composable'ın parametrelerinin değişebileceğini düşündüğünde yeniden oluşturma işlemi başlar. Yeniden oluşturma iyimserdir. Diğer bir deyişle Compose parametreler tekrar değişmeden önce yeniden oluşturma işlemini bitirmeyi bekler. Bir parametre, yeniden oluşturma işlemi tamamlanmadan önce değişirse Oluşturma işlemi, yeniden oluşturmayı iptal edip yeni parametreyle yeniden başlatabilir.
Yeniden oluşturma işlemi iptal edildiğinde Compose kullanıcı arayüzü ağacını yeniden oluşturma işleminden siler. Görüntülenen kullanıcı arayüzüne bağlı herhangi bir yan etkiniz varsa beste iptal edilse bile yan etki uygulanır. Bu durum tutarsız uygulama durumuna neden olabilir.
İyimser yeniden bileşimden yararlanabilmek için tüm composable işlevlerin ve lambda'ların eşgüdümlü ve yan etkisi olmadığından emin olun.
Oluşturulabilir işlevler oldukça sık çalışabilir
Bazı durumlarda bir composable işlev, bir kullanıcı arayüzü animasyonunun her karesi için çalışabilir. İşlev, cihazın depolama alanından okuma gibi pahalı işlemler gerçekleştirirse kullanıcı arayüzü duraklamalarına neden olabilir.
Örneğin, widget'ınız cihaz ayarlarını okumaya çalışırsa bu ayarları saniyede yüzlerce kez okuyabilir. Bu da uygulamanızın performansını ciddi şekilde etkileyebilir.
composable fonksiyonunuz veri gerektiriyorsa veri parametrelerini tanımlamalıdır.
Daha sonra, pahalı işleri kompozisyon dışındaki başka bir iş parçacığına taşıyabilir ve mutableStateOf
veya LiveData
kullanarak verileri Compose'a aktarabilirsiniz.
Daha fazla bilgi
Compose'da ve composable işlevlerinde düşünme 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örüntülenir
- Jetpack Compose için Kotlin
- State ve Jetpack Compose
- Jetpack Compose mimari katmanlar