Jetpack Compose, Android için modern ve bildirime dayalı bir kullanıcı arayüzü araç setidir. Compose, uygulama kullanıcı arayüzünüzü zorunlu olarak ön uç görünümlerini değiştirmeden oluşturmanıza olanak tanıyan bildirim temelli bir 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 sonuçları uygulama tasarımınız için önemlidir.
Bildirimli 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 edilebiliyordu. Kullanıcı etkileşimleri gibi nedenlerle uygulamanın durumu değiştikçe 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 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üleme sayısını manuel olarak değiştirmek hata olasılığını artırır. Bir veri parçası birden fazla yerde oluşturuluyorsa, veriyi 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ının karmaşıklığı, güncellenmesi gereken görünüm sayısıyla birlikte artar.
Son birkaç yıldır tüm sektör, kullanıcı arayüzleri oluşturmayı ve güncellemeyi basitleştiren açıklayıcı bir kullanıcı arayüzü modeline geçmeye başladı.
Bu teknik, kavramsal olarak tüm ekranı sıfırdan yeniden oluşturup yalnızca gerekli değişiklikleri uygulayarak çalışır. Bu yaklaşım, durum bilgisi olan bir görünüm hiyerarşisini manuel olarak güncellemenin karmaşıklığını ortadan kaldırır. Compose, açıklayıcı bir kullanıcı arayüzü çerçevesidir.
Tüm ekranı 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 yeniden çizilmesi gerektiğini akıllıca seçer. Yeniden oluşturma bölümünde açıklandığı gibi, bu durum kullanıcı arayüzü bileşenlerinizi tasarlama şeklinizi etkiler.
Örnek bir composable işlev
Compose'u kullanarak, verileri alan ve kullanıcı arayüzü öğeleri oluşturan bir dizi composable işlev tanımlayarak kullanıcı arayüzünüzü oluşturabilirsiniz. Örneğin, Greeting widget'ı bir String alır ve karşılama mesajı gösteren bir Text widget'ı oluşturur.
Bu işlevle ilgili dikkat edilmesi gereken birkaç nokta:
- Ek açıklama: İşlev,
@Composableek açıklamasıyla açıklanır. Tüm composable işlevlerde 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 için tasarlandığını bildirir. - Veri girişi: İşlev, verileri alır. Composable işlevler, uygulama mantığının kullanıcı arayüzünü tanımlamasına olanak tanıyan parametreleri kabul edebilir. Bu durumda widget'ımız, kullanıcıyı adıyla karşılayabilmek için bir
Stringkabul eder. - Kullanıcı arayüzü ekranı: İşlev, kullanıcı arayüzünde metin gösterir. Bunu, metin kullanıcı arayüzü öğesini oluşturan
Text()composable işlevini çağırarak yapar. Oluşturulabilir işlevler, diğer oluşturulabilir işlevleri çağırarak kullanıcı arayüzü hiyerarşisi oluşturur. - Döndürülen değer yok: İşlev herhangi bir değer döndürmez. Kullanıcı arayüzü oluşturan Compose işlevlerinin herhangi bir şey döndürmesi gerekmez. Çünkü bu işlevler, kullanıcı arayüzü widget'ları oluşturmak yerine hedef ekran durumunu tanımlar.
Özellikler: Bu işlev hızlıdır, idempotent'tir 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. - İşlev, özellikleri veya genel değişkenleri değiştirme gibi yan etkiler olmadan kullanıcı arayüzünü tanımlar.
Genel olarak, tüm composable işlevler Yeniden oluşturma bölümünde ele alınan nedenlerden dolayı 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şikliği
Birçok zorunlu nesne tabanlı kullanıcı arayüzü araç setinde, bir widget ağacını örneklendirerek 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şime girmesine olanak tanıyan alıcı ve ayarlayıcı yöntemlerini gösterir.
Compose'un bildirimsel yaklaşımında widget'lar nispeten durum bilgisizdir ve belirleyici veya alıcı işlevleri 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, Uygulama mimarisi kılavuzunda açıklandığı gibi ViewModel gibi mimari kalıplara durum sağlamayı kolaylaştırır. Ardından, gözlemlenebilir veriler her güncellendiğinde mevcut uygulama durumunu bir kullanıcı arayüzüne dönüştürmekten composable'larınız sorumlu olur.
Kullanıcı, kullanıcı arayüzüyle etkileşimde bulunduğunda kullanıcı arayüzü, onClick gibi etkinlikleri tetikler.
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 işleme yeniden oluşturma denir.
Dinamik içerik
composable işlevler XML yerine Kotlin'de 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.
Birleş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ğinden yararlanabilirsiniz.
Bu güç ve esneklik, Jetpack Compose'un en önemli 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 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 oluşturulan 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, düğme gösteren ş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.
Compose, yeni değeri göstermek için lambda'yı Text işleviyle tekrar çağırır. Bu işleme yeniden oluşturma adı verilir. Değere bağlı olmayan diğer işlevler yeniden oluşturulmaz.
Daha önce de belirttiğimiz gibi, tüm kullanıcı arayüzü ağacını yeniden oluşturmak, işlem gücü ve pil ömrü açısından maliyetli olabilir. Compose, bu sorunu akıllı yeniden oluşturma ile çözer.
Yeniden oluşturma, girişler değiştiğinde composable işlevlerinizi tekrar çağırma işlemidir. Compose, yeni girişlere göre yeniden oluşturma işlemi yaptığında yalnızca değişmiş olabilecek işlevleri veya lambda'ları çağırır ve geri kalanları atlar. Compose, parametreleri değişmeyen işlevleri veya lambda'ları atlayarak verimli bir şekilde yeniden oluşturur.
Bir işlevin yeniden oluşturulması atlanabileceğinden, composable işlevlerin yürütülmesinden kaynaklanan yan etkilere asla güvenmeyin. Aksi takdirde kullanıcılar uygulamanızda garip ve öngörülemeyen davranışlarla karşılaşabilir. Yan etki, uygulamanızın geri kalanında 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
ViewModeliçinde bir gözlemlenebilir öğeyi güncelleme- Paylaşılan tercihler güncelleniyor
Composable işlevler, animasyon oluşturulurken olduğu gibi her karede yeniden yürütülebilir. Animasyonlar sırasında takılma olmaması için composable işlevler hızlı olmalıdır. Paylaşılan tercihlerden okuma gibi maliyetli işlemler yapmanız gerekiyorsa bunu arka plandaki bir eş yordamda yapın ve değer sonucunu parametre olarak composable işleve iletin.
Örneğin, bu kod SharedPreferences içindeki bir değeri güncellemek için bir composable oluşturur. Oluşturulabilir öğe, paylaşılan tercihlerden okuma veya yazma yapmamalıdır. Bunun yerine bu kod, okuma ve yazma işlemlerini arka plandaki bir eş yordamda ViewModel'e taşır. Uygulama mantığı, bir güncellemeyi tetiklemek için geçerli değeri bir geri çağırma işleviyle iletir.
@Composable fun SharedPrefsToggle( text: String, value: Boolean, onValueChanged: (Boolean) -> Unit ) { Row { Text(text) Checkbox(checked = value, onCheckedChange = onValueChanged) } }
Bu belgede, Compose'u kullanırken dikkat etmeniz gereken bazı noktalar ele alınmaktadır:
- Yeniden oluşturma, mümkün olduğunca çok composable işlevi ve lambda'yı atlar.
- Yeniden oluşturma iyimserdir ve iptal edilebilir.
- Bir composable işlev, animasyonun her karesinde olduğu gibi oldukça sık çalıştırılabilir.
- Composable işlevler paralel olarak yürütülebilir.
- Oluşturulabilir işlevler herhangi bir sırayla yürütülebilir.
Aşağıdaki bölümlerde, yeniden oluşturmayı destekleyen composable işlevlerin nasıl oluşturulacağı açıklanmaktadır. Her durumda en iyi uygulama, composable işlevlerinizi hızlı, idempotent ve yan etkisiz tutmaktır.
Yeniden oluşturma, mümkün olduğunca çok atlanır
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, kullanıcı arayüzü ağacında daha yüksek veya daha düşük birleştirilebilir öğelerden hiçbirini yürütmeden tek bir Button birleştirilebilir öğesini yeniden çalıştırmayı atlayabileceği anlamına gelir.
Her composable işlev ve lambda kendi kendine yeniden oluşturulabilir. Aşağıdaki örnekte, yeniden oluşturma işleminin bir listeyi oluştururken 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ülen tek şey olabilir.
Oluşturma, header değiştiğinde üst öğelerinden hiçbirini yürütmeden Column lambda'ya atlayabilir. Column yürütülürken names değişmediyse Compose, LazyColumn öğelerini atlamayı seçebilir.
Tüm composable işlevler veya lambda'lar yan etkisiz olmalıdır. Yan etki gerçekleştirmeniz gerektiğinde bunu bir geri çağırmadan tetikleyin.
Yeniden oluşturma iyimserdir
Yeniden oluşturma, Compose bir composable'ın parametrelerinin değişmiş olabileceğini düşündüğünde başlar. Yeniden oluşturma iyimserdir. Yani Compose,parametreler tekrar değişmeden önce yeniden oluşturma işleminin tamamlanmasını bekler. Yeniden oluşturma tamamlanmadan önce bir parametre değişirse Compose, yeniden oluşturmayı iptal edip yeni parametreyle yeniden başlatabilir.
Yeniden oluşturma iptal edildiğinde Compose, yeniden oluşturma işlemindeki kullanıcı arayüzü ağacını siler. Kullanıcı arayüzünün gösterilmesine bağlı yan etkileriniz varsa oluşturma iptal edilse bile yan etki uygulanır. Bu durum, uygulama durumunun tutarsız olmasına neden olabilir.
İyimser yeniden oluşturma işlemini gerçekleştirmek için tüm composable işlevlerin ve lambda'ların eş kuvvetli ve yan etkisiz olduğunu doğrulayın.
Birleştirilebilir işlevler oldukça sık çalıştırılabilir
Bazı durumlarda, composable işlev bir kullanıcı arayüzü animasyonunun her karesi için çalıştırılabilir. İşlev, cihaz depolama alanından okuma gibi pahalı 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 da uygulamanızın performansını olumsuz etkileyebilir.
Bir composable işlevin veriye ihtiyacı varsa bu veri için parametreler tanımlayın. Ardından, yüksek maliyetli işlemleri oluşturma dışında başka bir iş parçacığına taşıyabilir ve elde edilen değeri, mutableStateOf veya LiveData kullanarak parametre olarak composable işleve iletebilirsiniz.
Composable işlevler paralel olarak çalışabilir
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şlevleri daha düşük öncelikli olarak çalıştırabilir.
Bu optimizasyon, composable işlevin arka plan iş parçacığı havuzunda yürütülebileceği anlamına gelir.
Bir composable 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 davrandığı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ğrı, çağırandan farklı bir iş parçacığında gerçekleşebilir. Bu nedenle, bir composable lambda'daki değişkenleri değiştiren kodlardan kaçınılmalıdır. Bu tür kodlar hem iş parçacığı açısından güvenli değildir hem de composable lambda'nın izin verilmeyen bir yan etkisidir.
Aşağıda, bir listeyi ve sayısını gösteren bir composable örneği verilmiştir:
@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 liste görüntülemek için harika bir koddur. 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şturma işleminde değiştirilir. Bu, bir animasyonun her karesi veya listenin güncellendiği an olabilir. Her iki durumda da kullanıcı arayüzünde
yanlış sayı gösterilir. Bu nedenle, bu tür yazma işlemleri Compose'da desteklenmez. Bu yazma işlemlerini yasaklayarak, çerçevenin composable lambda'ları yürütmek için iş parçacıklarını değiştirmesine izin veririz.
Oluşturulabilir işlevler herhangi bir sırayla yürütülebilir
Bir composable işlevin koduna bakarsanız kodun göründüğü sırayla çalıştırıldığını düşünebilirsiniz. Ancak bu her zaman doğru değildir. Bir composable işlev, diğer composable işlevlere çağrılar içeriyorsa bu işlevler herhangi bir sırada çalıştırılabilir. Compose, 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 çağrıları herhangi bir sırayla gerçekleşebilir. Yani, örneğin StartScreen()'in bazı genel değişkenleri (yan etki) ayarlamasını ve MiddleScreen()'in bu değişiklikten yararlanmasını sağlayamazsınız. Bunun yerine, bu işlevlerin her birinin bağımsız olması gerekir.
Daha fazla bilgi
Compose'da düşünme 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: JavaScript kapalıyken bağlantı metni gösterilir.
- Jetpack Compose için Kotlin
- State ve Jetpack Compose
- Jetpack Compose mimari katmanları