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ştirmeden uygulama kullanıcı arayüzünüzü oluşturmanıza olanak tanıyan bir tanımlayıcı API sağlayarak uygulama kullanıcı arayüzünüzü yazmayı ve sürdürmeyi kolaylaştırır. Bu terminolojinin açıklanması gerekir ancak bu terimlerin uygulama tasarımınız açısından önemi büyüktür.
Açıklayıcı programlama paradigması
Android görünüm hiyerarşisi geçmişte kullanıcı arayüzü widget'larından oluşan bir ağaç olarak temsil edilebilirdi. Uygulamanın durumu, kullanıcı etkileşimleri gibi nedenlerle değiştikçe kullanıcı arayüzü hiyerarşisinin mevcut verileri göstermek için güncellenmesi gerekir.
Kullanıcı arayüzünü güncellemenin en yaygın yolu, findViewById()
gibi işlevleri kullanarak ağaçta gezinmek 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ülemelerle manuel olarak oynamak hata olasılığını artırır. Bir veri birden fazla yerde oluşturuluyorsa bu veriyi gösteren görünümlerden birini güncellemeyi 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ılan bir düğümün değerini ayarlamaya çalışabilir. Genel olarak, yazılım bakımının karmaşıklığı, güncellenmesi gereken görünümlerin sayısıyla birlikte artar.
Son birkaç yıldır tüm sektör, kullanıcı arayüzleri oluşturma ve güncellemeyle ilgili mühendislik çalışmalarını büyük ölçüde basitleştiren açıklayıcı bir kullanıcı arayüzü modeline geçmeye başladı. Bu teknik, ekranın tamamını sıfırdan yeniden oluşturarak ve ardından 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. Compose, bildirime dayalı bir kullanıcı arayüzü çerçevesidir.
Tüm ekranı yeniden oluşturma konusundaki 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 amacıyla 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 düzenleme bölümünde açıklandığı gibi, kullanıcı arayüzü bileşenlerinizi tasarlama biçiminiz üzerinde bazı etkileri vardır.
Basit bir composable işlev
Compose'u kullanarak, veri alan ve kullanıcı arayüzü öğeleri yayınlayan bir dizi birleştirilebilir işlev tanımlayarak kullanıcı arayüzünüzü oluşturabilirsiniz. Basit bir örnek olarak, bir String
alan ve karşılama mesajı gösteren bir Text
widget yayınlayan bir Greeting
widget verilebilir.
Şekil 1. Veri alan ve ekranda bir metin widget'ı oluşturmak için bu verileri kullanan basit bir birleştirilebilir işlev.
Bu işlevle ilgili dikkate değer birkaç nokta:
İşlev,
@Composable
notuyla ek açıklamaya sahiptir. Tüm Composable işlevlerinde bu ek açıklama bulunmalıdır. Bu ek açıklama, Compose derleyicisine bu işlevin verilerin kullanıcı arayüzüne dönüştürülmesi amacıyla tasarlandığını bildirir.İşlev verileri alır. Özelleştirilebilir işlevler parametreleri kabul edebilir. Bu parametreler, uygulama mantığının kullanıcı arayüzünü tanımlamasına olanak tanır. Bu durumda widget'ımız, kullanıcıyı isme göre selamlayabilmek için
String
değerini kabul eder.İşlev, kullanıcı arayüzünde metin gösterir. Bunu, aslında metin kullanıcı arayüzü öğesini oluşturan
Text()
composable işlevini çağırarak yapar. Oluşturulabilir işlevler, diğer composable işlevleri çağırarak kullanıcı arayüzü hiyerarşisi yayar.İşlev, hiçbir şey döndürmez. Kullanıcı arayüzü widget'ları oluşturmak yerine istenen ekran durumunu tanımladıkları için kullanıcı arayüzü yayınlayan oluşturma işlevlerinin herhangi bir değer döndürmesi gerekmez.
Bu işlev hızlıdır, ihtiyatlıdır ve yan etki içermez.
- İş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ü özellikleri veya genel değişkenleri değiştirme gibi yan etkiler olmadan tanımlar.
Genel olarak, tüm composable işlevler Yeniden oluşturma 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
Beyanla ilgili paradigma değişikliği
Nesne odaklı birçok zorunlu kullanıcı arayüzü araç setinde, bir widget ağacı oluşturarak kullanıcı arayüzünü başlatırsı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 ayarlayıcı yöntemleri gösterir.
Compose'un açıklayıcı yaklaşımında widget'lar nispeten durumsuzdur ve ayarlayıcı veya alıcı işlevleri göstermez. Aslında widget'lar nesne olarak gösterilmez.
Aynı birleştirilebilir işlevi farklı bağımsız değişkenlerle çağırarak kullanıcı arayüzünü güncelleyebilirsiniz. Bu, Uygulama mimarisi kılavuzunda açıklandığı gibi ViewModel
gibi mimari kalıplara durum eklemeyi kolaylaştırır. Ardından, gözlemlenebilir veriler her güncellendiğinde composable'larınız mevcut uygulama durumunu bir kullanıcı arayüzüne dönüştürmekten sorumludur.
Şekil 2. Uygulama mantığı, üst düzey composable işleve veri sağlar. Bu işlev, diğer derlenebilir öğeleri çağırarak kullanıcı arayüzünü açıklamak için verileri kullanır ve uygun verileri bu derlenebilir öğelere ve hiyerarşinin alt kısmına iletir.
Kullanıcı kullanıcı arayüzüyle etkileşimde bulunduğunda kullanıcı arayüzü onClick
gibi etkinlikler oluşturur.
Bu etkinlikler, uygulama mantığını bilgilendirmelidir. Uygulama mantığı da 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 denir.
Şekil 3. Kullanıcının bir kullanıcı arayüzü öğesiyle etkileşime geçmesi bir etkinliğin tetiklenmesine neden olmuştur. Uygulama mantığı etkinliğe yanıt verir. Ardından, composable işlevleri gerekirse yeni parametrelerle otomatik olarak tekrar çağrılır.
Dinamik içerik
Birleştirilebilir işlevler XML yerine Kotlin'de yazıldığı için 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, ad listesini alır ve her kullanıcı için bir karşılama mesajı oluşturur.
Kompozit 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 Compose'un en önemli avantajlarından biridir.
Yeniden derleme
Zorunlu bir kullanıcı arayüzü modelinde, bir widget'ı değiştirmek için widget'ın dahili durumunu değiştirmek üzere bir ayarlayıcıyı çağırırsınız. Oluştur'da, derlenebilir işlevi yeni verilerle tekrar çağırırsınız. Bu işlem, işlevin yeniden derlenmesine neden olur. İşlev tarafından yayınlanan widget'lar gerekirse yeni verilerle yeniden çizilir. Oluşturma ç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") } }
Düğme her tıklandığında arayan, clicks
değerini günceller.
Oluştur, yeni değeri göstermek için lambda'yı Text
işleviyle tekrar çağırır. Bu sürece yeniden oluşturma denir. Değere bağlı olmayan diğer işlevler yeniden derlenmez.
Daha önce de belirttiğimiz gibi, kullanıcı arayüzü ağacının tamamını yeniden oluşturmak, hesaplama gücü ve pil ömrü kullanan, hesaplama açısından pahalı olabilir. Oluşturma, bu akıllı yeniden oluşturma özelliğiyle bu sorunu çözer.
Yeniden düzenleme, girişler değiştiğinde composable işlevlerinizi tekrar çağırma işlemidir. Bu durum, işlevin girişleri değiştiğinde ortaya çıkar. Oluştur işlevi, yeni girişlere göre yeniden oluştururken yalnızca değişmiş olabilecek işlevleri veya lambdaları çağırır, geri kalanını atlar. Compose, parametreleri değişmeyen tüm işlevleri veya lambdaları atlayarak verimli bir şekilde yeniden derleme yapabilir.
İşlevin yeniden oluşturulması atlanabileceği için hiçbir zaman composable işlevleri yürütmenin yan etkileri olmasın. Bunu yaparsanız kullanıcılar uygulamanızda garip ve öngörülemeyen davranışlarla karşılaşabilir. Yan etki, uygulamanızın geri kalanı tarafından görülebilen tüm değişikliklerdir. Örneğin, aşağıdaki işlemlerin tümü tehlikeli yan etkilerdir:
- Paylaşılan bir nesnenin mülküne yazma
ViewModel
'te bir gözlemlenebiliri güncelleme- Paylaşılan tercihler güncelleniyor
Birleştirilebilir işlevler, bir animasyon oluşturulurken olduğu gibi her karede bir yeniden yürütülebilir. Birleştirilebilir işlevler, animasyonlar sırasında takılma olmaması için hızlı olmalıdır. Paylaşılan tercihlerden okuma gibi pahalı işlemler yapmanız gerekiyorsa bunu arka planda bir coroutine'te yapın ve değer sonucunu, birleştirilebilir işleve parametre olarak iletin.
Örneğin, bu kod SharedPreferences
içindeki bir değeri güncellemek için bir composable oluşturur. Kompozit, paylaşılan tercihlerden kendisi okumamalı veya yazmamalıdır. Bunun yerine bu kod, okuma ve yazma işlemlerini arka planda çalışan bir ViewModel
içine taşır. Uygulama mantığı, güncellemeyi tetiklemek için mevcut değeri bir geri çağırma ile iletir.
@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ı noktalar ele alınmaktadır:
- Yeniden derleme, mümkün olduğunca fazla birleştirilebilir işlevi ve lambda'yı atlar.
- Yeniden derleme işlemi iyimserdir ve iptal edilebilir.
- Bir composable işlev, oldukça sık, bir animasyonun her karesi kadar sık çalıştırılabilir.
- Kompozit işlevler paralel olarak yürütülebilir.
- Birleştirilebilir işlevler herhangi bir sırada yürütülebilir.
Aşağıdaki bölümlerde, yeniden derlemeyi desteklemek için birleştirilebilir işlevlerin nasıl oluşturulacağı ele alınmaktadır. Her durumda en iyi uygulama, composable işlevlerinizi hızlı, bağlantılı ve yan etkiden uzak tutmaktır.
Yeniden derleme mümkün olduğunca atlar
Kullanıcı arayüzünüzün bölümleri geçersiz olduğunda Oluştur, yalnızca güncellenmesi gereken bölümleri yeniden oluşturmak için elinden geleni yapar. Bu, kullanıcı arayüzü ağacında bir düğmenin bileşenini yeniden çalıştırırken, düğmenin üstündeki veya altındaki bileşenlerden hiçbirini çalıştırmadan atlayabileceği anlamına gelir.
Her birleştirilebilir işlev ve lambda kendi kendine yeniden derlenebilir. Aşağıda, yeniden oluşturmanın 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) 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 derleme sırasında yürütülecek tek şey olabilir.
Oluşturma, header
değiştiğinde üst öğelerinden birini yürütmeden Column
lambdasına atlayabilir. Ayrıca, Column
yürütüldüğünde, names
değişmediyse Oluştur, LazyColumn
öğelerini atlamayı seçebilir.
Yine, composable işlevlerin veya lambda'ların çalıştırılmasında yan etki bulunmamalıdır. Bir yan etki gerçekleştirmeniz gerektiğinde, bu işlemi bir geri aramadan tetikleyin.
Yeniden oluşturma iyimser
Oluşturma, bir derlenebilir öğenin parametrelerinin değişmiş olabileceğini düşündüğünde yeniden oluşturma işlemini başlatır. Yeniden düzenleme iyimser bir durumdur. Diğer bir deyişle,Compose parametreler tekrar değişmeden önce yeniden düzenleme işleminin tamamlanmasını bekler. Bir parametre, yeniden derleme tamamlanmadan önce değişirse Derle, yeniden derlemeyi iptal edip yeni parametreyle yeniden başlatabilir.
Yeniden oluşturma iptal edildiğinde Compose, kullanıcı arayüzü ağacını yeniden oluşturmadan siler. 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, uygulama durumunun tutarsız olmasına neden olabilir.
Tüm birleştirilebilir işlevlerin ve lambdaların iyimser yeniden derlemeyi işlemek için tekil ve yan etki içermediğinden emin olun.
Kompozit işlevler oldukça sık çalışabilir
Bazı durumlarda, bir birleştirilebilir işlev kullanıcı arayüzü animasyonunun her karesi için çalışabilir. İşlev, cihaz depolama alanından okuma gibi pahalı işlemler gerçekleştiriyorsa kullanıcı arayüzünde takılmalara neden olabilir.
Örneğin, widget'ınız cihaz ayarlarını okumaya çalıştıysa bu ayarları saniyede yüzlerce kez okuyabilir. Bu da uygulamanızın performansını ciddi şekilde sekteye uğratabilir.
Kompozit işleviniz veri gerektiriyorsa veriler için parametreler tanımlamalıdır. Ardından, pahalı çalışmaları, oluşturma dışında başka bir ileti dizisine taşıyabilir ve mutableStateOf
veya LiveData
kullanarak verileri Oluştur'a iletebilirsiniz.
Kompozit işlevler paralel olarak çalıştırılabilir
Compose, birleştirilebilir işlevleri paralel olarak çalıştırarak yeniden oluşturmayı optimize edebilir. Bu sayede Compose, birden fazla çekirdekten yararlanabilir ve ekranda olmayan birleştirilebilir işlevleri daha düşük öncelikli olarak çalıştırabilir.
Bu optimizasyon, composable işlevinin arka plan ileti dizileri havuzunda yürütülebileceği anlamına gelir.
Bir birleştirilebilir işlev, ViewModel
üzerinde bir işlevi çağırırsa Compose bu işlevi aynı anda birkaç mesaj dizisinden çağırabilir.
Uygulamanızın doğru şekilde davranması için tüm derlenebilir 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 etkiler tetikleyin.
Bir composable işlev çağrıldığında, çağrı, çağrı yapandan farklı bir iş parçacığında gerçekleşebilir. Bu, composable lambda'daki değişkenleri değiştiren koddan kaçınılması gerektiği anlamına gelir. 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 bu koddan kaçınılmalıdır.
Bir listeyi ve sayısını gösteren bir derlenebilir öğeyi gösteren örneği aşağıda 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 etkisizdir ve giriş listesini kullanıcı arayüzüne dönüştürür. Bu kod, küçük bir liste görüntülemek için mükemmeldir. Ancak işlev bir yerel değişkene yazarsa 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ş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österir. Bu nedenle, bu tür yazma işlemleri Compose'da desteklenmez. Bu yazma işlemlerini yasaklayarak çerçevenin, birleştirilebilir lambdaları yürütmek için iş parçacıklarını değiştirmesine izin veririz.
Kompozit işlevler herhangi bir sırada yürütülebilir
Bir composable işlevin koduna bakarsanız kodun göründüğü sırayla çalıştırıldığını varsayabilirsiniz. Ancak bu durumun doğruluğu garanti edilmez. Bir composable işlev, diğer composable işlevlere yönelik çağrılar içeriyorsa bu işlevler herhangi bir sırada çalışabilir. Oluşturma işlemi, bazı kullanıcı arayüzü öğelerinin diğerlerinden daha yüksek önceliğe sahip olduğunu algılayıp bunları önce çizebilir.
Örneğin, sekme düzeninde üç ekran çizmek için şuna benzer bir kodunuz olduğunu varsayalım:
@Composable fun ButtonRow() { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } }
StartScreen
, MiddleScreen
ve EndScreen
'ye yapılan aramalar herhangi bir sırada gerçekleşebilir. Bu, örneğin StartScreen()
'ün bazı genel değişkenleri ayarlamasına (yan etki) ve MiddleScreen()
'ün bu değişiklikten yararlanmasına izin veremezsiniz. Bunun yerine, bu işlevlerin her birinin kendi kendine yeterli olması gerekir.
Daha fazla bilgi
Compose ve derlenebilir 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: JavaScript kapalıyken bağlantı metni gösterilir
- Jetpack Compose için Kotlin
- State ve Jetpack Compose
- Jetpack Compose mimari katmanlandırması