Bir uygulamadaki durum, zaman içinde değişebilen herhangi bir değerdir. Bu, çok geniş bir tanımdır ve Oda veritabanından bir sınıftaki değişkene kadar her şeyi kapsar.
Tüm Android uygulamaları, kullanıcıya gösterilir. Android uygulamalarında birkaç durum örneği:
- Ağ bağlantısının kurulamadığı durumlarda gösterilen bir Snackbar.
- Bir blog yayını ve ilişkili yorumlar.
- Kullanıcı tıkladığında oynatılan düğmelerde dalga animasyonları.
- Kullanıcının bir resmin üzerine çizebileceği çıkartmalar.
Jetpack Compose, bir Android uygulamasındaki durumu nerede ve nasıl depoladığınızı ve kullandığınız konusunda açık olmanıza yardımcı olur. Bu kılavuz, durum ile composable'lar arasındaki bağlantıya ve Jetpack Compose'un durum üzerinde daha kolay çalışmak için sunduğu API'lere odaklanmaktadır.
Durum ve yapı
Compose bildirim temellidir. Dolayısıyla, bunu güncellemenin tek yolu aynı composable'ı yeni bağımsız değişkenlerle çağırmaktır. Bu bağımsız değişkenler, kullanıcı arayüzü
durumunu temsil eder. Bir durum her güncellendiğinde bir yeniden düzenleme gerçekleştirilir. Sonuç olarak TextField
gibi öğeler, zorunlu XML tabanlı görünümlerde olduğu gibi otomatik olarak güncellenmez. Bir composable'ın uygun şekilde güncellenmesi için yeni durumunun açıkça bildirilmesi gerekir.
@Composable private fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField( value = "", onValueChange = { }, label = { Text("Name") } ) } }
Bu komutu çalıştırıp metin girmeye çalışırsanız hiçbir şey olmadığını görürsünüz. Bunun nedeni, TextField
öğesinin kendisini güncellememesidir, value
parametresi değiştiğinde güncellenir. Bunun nedeni, bestenin ve yeniden bestenin Compose’da çalışma şeklidir.
İlk beste ve yeniden düzenleme hakkında daha fazla bilgi edinmek için İçerik Oluşturmada Düşünme sayfasına bakın.
composable'larda durum
Oluşturulabilir işlevler, bir nesneyi bellekte depolamak için remember
API'yi kullanabilir. remember
tarafından hesaplanan bir değer, ilk beste sırasında Bileşim'de depolanır ve depolanan değer yeniden oluşturma sırasında döndürülür.
remember
, hem değişken hem de sabit nesneleri depolamak için kullanılabilir.
mutableStateOf
, yazma çalışma zamanıyla entegre gözlemlenebilir bir tür olan gözlemlenebilir bir MutableState<T>
türü oluşturur.
interface MutableState<T> : State<T> {
override var value: T
}
value
politikasında yapılan değişiklikler, value
değerini okuyan composable işlevlerin yeniden oluşturulmasını planlar.
Bir composable'da MutableState
nesnesini tanımlamanın üç yolu vardır:
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
Bu beyanlar eşdeğerdir ve farklı devlet kullanımları için söz dizimi şekeri olarak sunulur. Yazdığınız composable içinde okunması en kolay kodu üreten kodu seçmelisiniz.
by
yetki verilmiş kullanıcı söz dizimi için aşağıdaki içe aktarma işlemleri gerekir:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
Hatırlanan değeri diğer composable'lar için parametre olarak, hatta hangi composable'ların görüntüleneceğini değiştirmek için ifadelerde mantık olarak kullanabilirsiniz. Örneğin, ad boş olduğunda karşılama mesajının gösterilmesini istemiyorsanız if
ifadesinde durumu kullanın:
@Composable fun HelloContent() { Column(modifier = Modifier.padding(16.dp)) { var name by remember { mutableStateOf("") } if (name.isNotEmpty()) { Text( text = "Hello, $name!", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } }
remember
, yeniden oluşturmalarda durumu korumanıza yardımcı olur ancak yapılandırma değişiklikleri genelinde durum korunmaz. Bunun için rememberSaveable
kullanmanız gerekir. rememberSaveable
, Bundle
içine kaydedilebilecek tüm değerleri otomatik olarak kaydeder. Diğer değerler için bir özel koruyucu nesnesi aktarabilirsiniz.
Desteklenen diğer eyalet türleri
Compose, durum bilgisini korumak için MutableState<T>
kullanmanızı gerektirmez. Diğer gözlemlenebilir türleri destekler. Composer'da başka bir gözlemlenebilir türü okumadan önce, durum değiştiğinde composable'ların otomatik olarak yeniden derlenebilmesi için bunu bir State<T>
biçimine dönüştürmeniz gerekir.
Android uygulamalarında kullanılan yaygın gözlemlenebilir türlerden State<T>
oluşturmak için işlevlerle birlikte gemiler oluşturun. Bu entegrasyonları kullanmadan önce aşağıda açıklandığı şekilde uygun yapıları ekleyin:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
,Flow
'teki değerleri yaşam döngüsüne duyarlı bir şekilde toplayarak uygulamanızın uygulama kaynaklarını korumasına olanak tanır. Oluştur'danState
gönderilen en son değeri temsil eder. Android uygulamalarında akışları toplamak için önerilen yol olarak bu API'yi kullanın.build.gradle
dosyasında aşağıdaki bağımlılık zorunludur (2.6.0-beta01 veya daha yeni bir sürüm olmalıdır):
Kotlin
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
}
Eski
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.2"
}
-
collectAsState
, aynı zamanda birFlow
öğesinden değerleri toplayıp Oluştur simgesineState
dönüştürdüğü içincollectAsStateWithLifecycle
ile benzerdir.Yalnızca Android'de olan
collectAsStateWithLifecycle
yerine, platformdan bağımsız kod içincollectAsState
kullanın.collectAsState
,compose-runtime
üzerinde kullanılabildiğinden ek bağımlılıklar gerekli değildir. -
observeAsState()
, buLiveData
öğesini gözlemlemeye başlar ve değerleriniState
üzerinden temsil eder.build.gradle
dosyasında aşağıdaki bağımlılık zorunludur:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.6.8")
}
Eski
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.6.8"
}
-
subscribeAsState()
, RxJava2'nin reaktif akışlarını (ör.Single
,Observable
,Completable
) Compose'aState
dönüştüren uzantı işlevleridir.build.gradle
dosyasında aşağıdaki bağımlılık zorunludur:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.6.8")
}
Eski
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.6.8"
}
-
subscribeAsState()
, RxJava3'ün reaktif akışlarını (ör.Single
,Observable
,Completable
) Compose'aState
dönüştüren uzantı işlevleridir.build.gradle
dosyasında aşağıdaki bağımlılık zorunludur:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.6.8")
}
Eski
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.6.8"
}
Durum bilgili ve durum bilgisiz
Nesneyi depolamak için remember
kullanan bir composable, dahili durum oluşturarak composable'ı durum bilgili hale getirir. HelloContent
, name
durumunu dahili olarak muhafaza edip değiştirdiği için durum bilgili composable'lara örnektir. Bu, çağrıyı yapanın durumu kontrol etmesinin gerekmediği ve devleti yönetmek zorunda kalmadan bunu kullanabildiği durumlarda yararlı olabilir. Ancak, dahili duruma sahip composable'lar daha az yeniden kullanılabilir ve test edilmesi daha zordur.
Durum bilgisiz composable, herhangi bir durumda olmayan bir composable'dır. Durum bilgisiz duruma ulaşmanın kolay bir yolu, durum kaldırma kullanmaktır.
Yeniden kullanılabilir composable'lar geliştirirken, genellikle aynı composable'ın hem durum bilgili hem de durum bilgisiz sürümünü göstermek istersiniz. Durum bilgili sürüm, devletle ilgilenmeyen arayanlar için uygundur ve durum bilgisiz sürüm, durumu kontrol etmesi veya kaldırması gereken arayanlar için gereklidir.
Eyalet kaldırma
Compose'da durum kaldırma, bir composable'ın durum bilgisiz hale getirmek için composable'ın çağrısına durumu taşıma kalıbıdır. Jetpack Compose'da durum kaldırmanın genel kalıbı durum değişkenini iki parametreyle değiştirmektir:
value: T
: gösterilecek geçerli değeronValueChange: (T) -> Unit
: Değerin değiştirilmesini isteyen bir etkinlik. BuradaT
, önerilen yeni değerdir
Ancak kullanabileceğiniz seçenekler onValueChange
ile sınırlı değildir. composable için daha belirli etkinlikler uygunsa bunları lambdas kullanarak tanımlamanız gerekir.
Bu şekilde kaldırılan eyaletin bazı önemli özellikleri vardır:
- Tek doğru kaynak: Durumu kopyalamak yerine hareket ettirerek tek bir doğru kaynağın bulunmasını sağlıyoruz. Bu sayede hatalardan kaçınabilirsiniz.
- Encapsulated: Yalnızca durum bilgili composable'ların durumlarını değiştirebilir. Her şey tamamen dahili.
- Paylaşılabilir: Kaldırılmış durum, birden fazla composable ile paylaşılabilir.
name
öğesini farklı bir composable'da okumak isterseniz kaldırma işlemi bunu yapmanıza olanak tanır. - Kesişilebilir: Durum bilgisiz composable'lara çağrı yapan kişiler, durumu değiştirmeden önce etkinlikleri yoksaymaya veya değiştirmeye karar verebilir.
- Ayrıştırılmış: Durum bilgisiz composable'ların durumu, herhangi bir yerde depolanabilir. Örneğin,
name
artık birViewModel
içine taşınabilir.
Bu örnekte, name
ve onValueChange
öğelerini HelloContent
öğesinin dışına çıkarıp bunları ağaçta HelloContent
adlı bir HelloScreen
composable'a taşırsınız.
@Composable fun HelloScreen() { var name by rememberSaveable { mutableStateOf("") } HelloContent(name = name, onNameChange = { name = it }) } @Composable fun HelloContent(name: String, onNameChange: (String) -> Unit) { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello, $name", modifier = Modifier.padding(bottom = 8.dp), style = MaterialTheme.typography.bodyMedium ) OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") }) } }
HelloContent
durumunu kaldırarak composable hakkında akıl yürütmek, bunu farklı durumlarda yeniden kullanmak ve test etmek daha kolay olur. HelloContent
, durumunun depolanma şeklinden ayrılır. Ayrıştırma, HelloScreen
öğesini değiştirmeniz veya değiştirmeniz durumunda HelloContent
öğesinin uygulanma şeklini değiştirmeniz gerekmeyeceği anlamına gelir.
![](https://developer.android.com/static/develop/ui/compose/images/udf-hello-screen.png?authuser=7&hl=tr)
Durumun düştüğü ve etkinliklerin arttığı kalıp tek yönlü veri akışı olarak adlandırılır. Bu durumda, durum HelloScreen
değerinden HelloContent
değerine iner ve etkinlikler HelloContent
değerinden HelloScreen
değerine çıkar. Tek yönlü veri akışını izleyerek kullanıcı arayüzünde durum gösteren composable'ları, uygulamanızın durumu depolayan ve değiştiren bölümlerinden ayırabilirsiniz.
Daha fazla bilgi edinmek için Kaldırma durumu sayfasını inceleyin.
Compose'da durum geri yükleniyor
rememberSaveable
API, remember
gibi davranır çünkü yeniden oluşturmalarda ve kaydedilen örnek durumu mekanizmasını kullanarak etkinlik veya işlem oluşturma sırasında durumu korur. Örneğin bu durum,
ekran döndürüldüğünde ortaya çıkar.
Eyalet bilgisini depolamanın yolları
Bundle
öğesine eklenen tüm veri türleri otomatik olarak kaydedilir. Bundle
bölümüne eklenemeyen bir öğeyi kaydetmek istiyorsanız birkaç seçeneğiniz vardır.
Paket haline getir
En basit çözüm, nesneye @Parcelize
notunu eklemektir. Nesne ayrıştırılabilir hale gelir ve paketlenebilir. Örneğin, bu kod ayrıştırılabilir bir City
veri türü oluşturur ve bunu duruma kaydeder.
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
Harita Koruyucu
Herhangi bir nedenle @Parcelize
uygun değilse bir nesneyi Bundle
için kaydedebileceğiniz bir değer grubuna dönüştürmek amacıyla kendi kuralınızı tanımlamak için mapSaver
kullanabilirsiniz.
data class City(val name: String, val country: String) val CitySaver = run { val nameKey = "Name" val countryKey = "Country" mapSaver( save = { mapOf(nameKey to it.name, countryKey to it.country) }, restore = { City(it[nameKey] as String, it[countryKey] as String) } ) } @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
Liste Kaydedeni
Harita için anahtarları tanımlama ihtiyacını ortadan kaldırmak için listSaver
ve dizinlerini anahtar olarak da kullanabilirsiniz:
data class City(val name: String, val country: String) val CitySaver = listSaver<City, Any>( save = { listOf(it.name, it.country) }, restore = { City(it[0] as String, it[1] as String) } ) @Composable fun CityScreen() { var selectedCity = rememberSaveable(stateSaver = CitySaver) { mutableStateOf(City("Madrid", "Spain")) } }
Compose'da eyalet sahipleri
Basit durum kaldırma işlemi, composable işlevlerin kendisinden yönetilebilir. Bununla birlikte, artışların takip edilmesi gereken durum miktarı veya composable işlevlerde gerçekleştirme mantığı varsa bu mantık ve beyan sorumluluklarını diğer sınıflara, yani devlet sahiplerine delege etmek iyi bir uygulamadır.
Daha fazla bilgi edinmek için Compose'da eyalet kaldırma dokümanlarına veya daha genel olarak mimari kılavuzundaki Eyalet sahipleri ve Kullanıcı Arayüzü Durumu sayfasına bakın.
Tuşlar değiştiğinde hesaplamaları hatırlamayı yeniden tetikle
remember
API, MutableState
ile birlikte sıklıkla kullanılır:
var name by remember { mutableStateOf("") }
Burada remember
işlevinin kullanılması, MutableState
değerinin yeniden bestelerde hayatta kalmasını sağlar.
remember
genellikle calculation
lambda parametresi alır. remember
ilk kez çalıştırıldığında calculation
lambda'yı çağırır ve sonucunu depolar. Yeniden oluşturma sırasında remember
, en son depolanan değeri döndürür.
Önbelleğe alma durumunun yanı sıra remember
uygulamasını, herhangi bir nesneyi veya bestedeki başlatılması ya da hesaplanması pahalı olan bir işlemin sonucunu depolamak için de kullanabilirsiniz. Bu hesaplamayı her yeniden oluşturmada tekrarlamak istemeyebilirsiniz.
Örneğin, pahalı bir işlem olan bu ShaderBrush
nesnesini oluşturabilirsiniz:
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember
, değeri Beste'den ayrılana kadar depolar. Bununla birlikte, önbelleğe alınan değeri geçersiz kılmanın bir yolu vardır. remember
API ayrıca bir key
veya keys
parametresi alır. Bu anahtarlardan herhangi biri değişirse işlev yeniden oluşturulduğunda, remember
önbelleği geçersiz kılar ve hesaplamayı tekrar lambda bloku yürütür. Bu mekanizma, Bestedeki bir nesnenin ömrü boyunca kontrol sahibi olmanızı sağlar. Hesaplama, hatırlanan değer Beste'den ayrılana kadar değil, girişler değişene kadar geçerli kalır.
Aşağıdaki örneklerde bu mekanizmanın nasıl çalıştığı gösterilmektedir.
Bu snippet'te ShaderBrush
oluşturulup Box
bir composable'ın arka plan boyası olarak kullanılır. remember
, daha önce açıklandığı gibi yeniden oluşturulması pahalı olduğundan ShaderBrush
örneğini depolar. remember
, seçilen arka plan resmi olan key1
parametresi olarak avatarRes
değerini alır. avatarRes
değişirse fırça, yeni resimle yeniden oluşturulur ve Box
öğesine yeniden uygulanır. Bu durum, kullanıcı seçiciden arka plan olacak başka bir resim seçtiğinde ortaya çıkabilir.
@Composable private fun BackgroundBanner( @DrawableRes avatarRes: Int, modifier: Modifier = Modifier, res: Resources = LocalContext.current.resources ) { val brush = remember(key1 = avatarRes) { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) } Box( modifier = modifier.background(brush) ) { /* ... */ } }
Sonraki snippet'te durum düz durum tutucu sınıfına
MyAppState
çekilir. remember
kullanarak sınıfın bir örneğini başlatmak için bir rememberMyAppState
işlevi sunar. Yeniden bestelemelerden etkilenmeyen bir örnek oluşturmak için bu tür işlevleri sunmak, Compose'da yaygın olarak kullanılan bir kalıptır. rememberMyAppState
işlevi, remember
için key
parametresi görevi gören windowSizeClass
değerini alır. Bu parametre değişirse uygulamanın en son değerle düz durum tutucu sınıfını yeniden oluşturması gerekir. Bu durum, örneğin kullanıcı cihazı döndürürse gerçekleşebilir.
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
Compose, bir anahtarın değişip değişmediğine ve depolanan değeri geçersiz kılıp kılmadığına karar vermek için sınıfın eşittir uygulamasını kullanır.
Yeniden oluşturmanın ötesinde anahtarlar içeren mağaza durumu
rememberSaveable
API, verileri Bundle
içinde depolayabilen, remember
etrafında çalışan bir sarmalayıcıdır. Bu API, devletin yalnızca yeniden oluşturma değil, aynı zamanda etkinlik yeniden oluşturma ve sistem tarafından başlatılan süreç ölümünü de atlatmasını sağlar.
rememberSaveable
, remember
ile keys
aynı amaçla input
parametre alır. Girişlerden herhangi biri değiştiğinde önbellek geçersiz kılınır. İşlev yeniden oluşturulduktan sonra rememberSaveable
, hesaplama lambda bloğunu yeniden yürütür.
Aşağıdaki örnekte rememberSaveable
, typedQuery
değişikliklerine kadar userTypedQuery
depolar:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Daha fazla bilgi
Eyalet ve Jetpack Compose hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara başvurun.
Numuneler
Codelab'ler
Videolar
Bloglar
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Compose kullanıcı arayüzünüzü tasarlama
- Oluşturma'da kullanıcı arayüzü durumunu kaydet
- Compose'da yan etkiler