Bir uygulamadaki durum, zaman içinde değişebilen herhangi bir değerdir. Bu çok geniş bir tanımdır ve Room veritabanından sınıftaki bir değişkene kadar her şeyi kapsar.
Tüm Android uygulamaları, durumu kullanıcıya gösterir. Android uygulamalarındaki duruma ilişkin birkaç örnek:
- Ağ bağlantısı kurulamadığında gösterilen bir Snackbar.
- Bir blog yayını ve ilişkili yorumlar.
- Kullanıcı tıkladığında oynatılan düğmelerde dalgalanma animasyonları.
- Kullanıcının bir resmin üzerine çizebileceği çıkartmalar.
Jetpack Compose, Android uygulamasında durumu nerede ve nasıl depolayıp kullanacağınız konusunda net olmanıza yardımcı olur. Bu kılavuzda, durum ile composable'lar arasındaki bağlantı ve Jetpack Compose'un durumla daha kolay çalışmak için sunduğu API'ler üzerinde durulmaktadır.
Durum ve kompozisyon
Compose, bildirimseldir ve bu nedenle yalnızca aynı composable'ı yeni bağımsız değişkenlerle çağırarak güncellenebilir. Bu bağımsız değişkenler, kullanıcı arayüzü durumunun temsilleridir. Bir durum her güncellendiğinde yeniden oluşturma işlemi gerçekleşir. Bu nedenle, TextField
gibi öğeler, zorunlu XML tabanlı görünümlerde olduğu gibi otomatik olarak güncellenmez. Bir composable'ın buna göre güncellenmesi için yeni durumun açıkça belirtilmesi 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 kodu çalıştırıp metin girmeye çalıştığınızda hiçbir şey olmadığını görürsünüz. Bunun nedeni, TextField
parametresinin kendiliğinden güncellenmemesi, value
parametresi değiştiğinde güncellenmesidir. Bunun nedeni, Oluşturma'da oluşturma ve yeniden oluşturma işlemlerinin işleyiş şeklidir.
İlk beste ve yeniden beste hakkında daha fazla bilgi edinmek için Thinking in Compose başlıklı makaleyi inceleyin.
Composable'larda durum
Birleştirilebilir işlevler, bir nesneyi bellekte depolamak için remember
API'sini kullanabilir. remember
tarafından hesaplanan bir değer, ilk bileşim sırasında Composition'da depolanır ve depolanan değer, yeniden bileşim sırasında döndürülür.
remember
, hem değiştirilebilir hem de değiştirilemez nesneleri depolamak için kullanılabilir.
mutableStateOf
gözlemlenebilir bir tür olan
MutableState<T>
gözlemlenebilirini oluşturur.
Bu tür, Compose çalışma zamanıyla entegre edilmiştir.
interface MutableState<T> : State<T> {
override var value: T
}
value
programlarında yapılan tüm değişiklikler, value
okuyan tüm composable işlevlerin yeniden oluşturulmasına neden olur.
Bir composable'da MutableState
nesnesi bildirmenin üç yolu vardır:
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
Bu bildirimler eşdeğerdir ve durumun farklı kullanımları için söz dizimi kolaylığı olarak sağlanır. Yazdığınız composable'da en kolay okunabilen kodu üreteni seçmelisiniz.
by
temsilci söz dizimi için aşağıdaki içe aktarmalar gerekir:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
Hatırlanan değeri diğer composable'lar için parametre olarak veya hangi composable'ların görüntüleneceğini değiştirmek üzere ifadelerde mantık olarak bile kullanabilirsiniz. Örneğin, ad boşsa selamlama mesajının gösterilmesini istemiyorsanız durumu bir if
ifadesinde 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şturma işlemleri arasında durumu korumanıza yardımcı olsa da yapılandırma değişiklikleri arasında durum korunmaz. Bunun için rememberSaveable
uygulamasını kullanmanız gerekir. rememberSaveable
, Bundle
içinde kaydedilebilecek tüm değerleri otomatik olarak kaydeder. Diğer değerler için özel bir kaydedici nesnesi iletebilirsiniz.
Desteklenen diğer eyalet türleri
Compose, durumu tutmak için MutableState<T>
kullanmanızı gerektirmez. Diğer gözlemlenebilir türleri destekler. Compose'da başka bir gözlemlenebilir türü okumadan önce, durumu değiştiğinde composable'ların otomatik olarak yeniden oluşturulabilmesi için bu türü State<T>
türüne dönüştürmeniz gerekir.
Compose, Android uygulamalarında kullanılan yaygın gözlemlenebilir türlerden State<T>
oluşturma işlevleriyle birlikte gelir. Bu entegrasyonları kullanmadan önce, aşağıda belirtildiği gibi uygun yapıları ekleyin:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
, yaşam döngüsüne duyarlı bir şekildeFlow
değerlerini toplar ve uygulamanızın uygulama kaynaklarını korumasını sağlar. ComposeState
'dan yayılan en son değeri temsil eder. Android uygulamalarında akış toplamak için bu API'yi kullanmanız önerilir.build.gradle
dosyasında şu bağımlılık gereklidir (2.6.0-beta01 veya daha yeni bir sürüm olmalıdır):
Kotlin
dependencies {
...
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}
Groovy
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
-
collectAsState
,collectAsStateWithLifecycle
ile benzerdir. ÇünküFlow
değerlerini toplar ve bunları ComposeState
'a dönüştürür.Platformdan bağımsız kod için yalnızca Android'e özel olan
collectAsStateWithLifecycle
yerinecollectAsState
kullanın.collectAsState
,compose-runtime
içinde kullanılabildiğinden ek bağımlılıklar gerekmez. -
observeAsState()
buLiveData
değerini gözlemlemeye başlar ve değerleriniState
üzerinden gösterir.build.gradle
dosyasında aşağıdaki bağımlılık gereklidir:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.8.1")
}
Groovy
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.8.1"
}
-
subscribeAsState()
, RxJava2'nin reaktif akışlarını (ör.Single
,Observable
,Completable
) ComposeState
'e dönüştüren uzantı işlevleridir.build.gradle
dosyasında aşağıdaki bağımlılık gereklidir:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.8.1")
}
Groovy
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.8.1"
}
-
subscribeAsState()
, RxJava3'ün reaktif akışlarını (ör.Single
,Observable
,Completable
) ComposeState
'e dönüştüren uzantı işlevleridir.build.gradle
dosyasında aşağıdaki bağımlılık gereklidir:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.8.1")
}
Groovy
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.8.1"
}
Durum bilgili ve durum bilgisiz karşılaştırması
Bir nesneyi depolamak için remember
kullanan bir composable, dahili durum oluşturarak composable'ı durumlu hale getirir. HelloContent
, name
durumunu dahili olarak tuttuğu ve değiştirdiği için durum bilgisi olan bir composable örneğidir. Bu, arayan kişinin durumu kontrol etmesi gerekmediği ve durumu kendisinin yönetmesi gerekmeden kullanabileceği durumlarda yararlı olabilir. Ancak, dahili durumu olan composable işlevler daha az yeniden kullanılabilir ve test edilmesi daha zordur.
Durumsuz bir composable, herhangi bir durumu tutmayan composable'dır. Durum bilgisizliği elde etmenin kolay bir yolu durum yükseltme kullanmaktır.
Yeniden kullanılabilir composable işlevler geliştirirken genellikle aynı composable işlevin hem durumlu hem de durumsuz bir sürümünü kullanıma sunmak istersiniz. Durumlu sürüm, durumla ilgilenmeyen arayanlar için uygundur. Durumsuz sürüm ise durumu kontrol etmesi veya yükseltmesi gereken arayanlar için gereklidir.
State hoisting
Compose'da durum yükseltme, durumun composable'ı durum bilgisiz hale getirmek için composable'ın çağırana taşınmasıdır. Jetpack Compose'da durum yükseltme için genel kalıp, durum değişkenini iki parametreyle değiştirmektir:
value: T
: Gösterilecek mevcut değeronValueChange: (T) -> Unit
: Değerin değişmesini isteyen bir etkinlik. BuradaT
, önerilen yeni değerdir.
Ancak onValueChange
ile sınırlı değilsiniz. Birleştirilebilir için daha spesifik etkinlikler uygunsa bunları lambda'lar kullanarak tanımlamanız gerekir.
Bu şekilde yükseltilen durumun bazı önemli özellikleri vardır:
- Tek ve doğru kaynak: Durumu kopyalamak yerine taşıyarak tek bir doğru kaynak olmasını sağlıyoruz. Bu, hataları önlemeye yardımcı olur.
- Kapsüllenmiş: Yalnızca durum bilgisi olan composable'lar durumlarını değiştirebilir. Tamamen dahili bir birimdir.
- Paylaşılabilir: Yükseltilmiş durum birden fazla composable ile paylaşılabilir.
name
öğesini farklı bir composable'da okumak istiyorsanız hoisting bunu yapmanıza olanak tanır. - Araya girilebilir: Durumsuz composable'ları arayanlar, durumu değiştirmeden önce etkinlikleri yoksayabilir veya değiştirebilir.
- Ayrılmış: Durumsuz composable'ların durumu herhangi bir yerde depolanabilir. Örneğin, artık
name
öğesiniViewModel
içine taşıyabilirsiniz.
Örnek durumda, name
ve onValueChange
öğelerini HelloContent
öğesinden çıkarıp ağaçta HelloContent
öğesini çağıran 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") }) } }
Durumu HelloContent
'dan dışarı taşıyarak composable hakkında akıl yürütmek, onu farklı durumlarda yeniden kullanmak ve test etmek daha kolay olur. HelloContent
, durumunun nasıl depolandığından bağımsızdır. Ayrıştırma, HelloScreen
öğesini değiştirirseniz veya yerine başka bir öğe koyarsanız HelloContent
öğesinin uygulanma şeklini değiştirmeniz gerekmediği anlamına gelir.

Durumun azaldığı ve etkinliklerin arttığı bu kalıba tek yönlü veri akışı adı verilir. Bu durumda, durum HelloScreen
'dan HelloContent
'ye düşer ve etkinlikler HelloContent
'den HelloScreen
'ya yükselir. Tek yönlü veri akışını izleyerek, kullanıcı arayüzünde durumu gösteren composable'ları, uygulamanızın durumu depolayan ve değiştiren bölümlerinden ayırabilirsiniz.
Daha fazla bilgi edinmek için Durumu nereye taşıyabilirim? sayfasını inceleyin.
Compose'da durumu geri yükleme
rememberSaveable
API, remember
'ye benzer şekilde çalışır. Çünkü yeniden oluşturma işlemlerinde ve ayrıca kaydedilmiş örnek durumu mekanizması kullanılarak etkinlik veya süreç yeniden oluşturma işlemlerinde durumu korur. Örneğin, bu durum ekran döndürüldüğünde yaşanır.
Durumu depolama yöntemleri
Bundle
'ya eklenen tüm veri türleri otomatik olarak kaydedilir. Bundle
'ya eklenemeyen bir öğeyi kaydetmek istiyorsanız birkaç seçeneğiniz vardır.
Parcelize
En basit çözüm, nesneye @Parcelize
notunu eklemektir. Nesne paketlenebilir hale gelir ve paketlenebilir. Örneğin, bu kod, paketlenebilir City
veri türü oluşturur ve durumu kaydeder.
@Parcelize data class City(val name: String, val country: String) : Parcelable @Composable fun CityScreen() { var selectedCity = rememberSaveable { mutableStateOf(City("Madrid", "Spain")) } }
MapSaver
@Parcelize
herhangi bir nedenle uygun değilse bir nesneyi, sistemin Bundle
öğesine kaydedebileceği bir değerler kümesine dönüştürmek için kendi kuralınızı tanımlamak üzere mapSaver
öğesini 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")) } }
ListSaver
Harita için anahtarları tanımlamanıza gerek kalmaması için listSaver
öğesini de kullanabilir ve dizinlerini anahtar olarak 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 durum bilgisi depolayıcılar
Basit durum yükseltme, composable işlevlerin kendisinde yönetilebilir. Ancak izlenecek durum miktarı artarsa veya composable işlevlerde gerçekleştirilecek mantık ortaya çıkarsa mantık ve durum sorumluluklarını diğer sınıflara (durum tutucular) devretmek iyi bir uygulamadır.
Daha fazla bilgi edinmek için Compose'da durum yükseltme belgelerine veya daha genel olarak mimari kılavuzundaki Durum tutucular ve kullanıcı arayüzü durumu sayfasına bakın.
Anahtarlar değiştiğinde hatırlatma hesaplamalarını yeniden tetikleme
remember
API'si genellikle MutableState
ile birlikte kullanılır:
var name by remember { mutableStateOf("") }
Burada, remember
işlevinin kullanılması MutableState
değerinin yeniden oluşturmalarda korunmasını sağlar.
Genel olarak remember
, calculation
lambda parametresini alır. remember
ilk kez çalıştırıldığında calculation
lambda'sını ç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, başlatılması veya hesaplanması maliyetli olan herhangi bir nesneyi ya da bir işlemin sonucunu Composition'da depolamak için remember
öğesini de kullanabilirsiniz. Bu hesaplamayı her yeniden oluşturmada tekrarlamak istemeyebilirsiniz.
Örneğin, pahalı bir işlem olan şu ShaderBrush
nesnesini oluşturmak:
val brush = remember { ShaderBrush( BitmapShader( ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT ) ) }
remember
, değer Kompozisyon'dan ayrılana kadar değeri saklar. Ancak, önbelleğe alınmış değeri geçersiz kılmanın bir yolu vardır. remember
API'si key
veya keys
parametresini de alır. Bu anahtarlardan herhangi biri değişirse işlev bir sonraki remember
yeniden oluşturulduğunda önbelleği geçersiz kılar ve hesaplama lambda bloğunu tekrar yürütür. Bu mekanizma, Composition'daki bir nesnenin kullanım ömrü üzerinde kontrol sahibi olmanızı sağlar. Hesaplama, hatırlanan değer Kompozisyon'dan ayrılana kadar değil, girişler değişene kadar geçerli kalır.
Bu mekanizmanın nasıl çalıştığı aşağıdaki örneklerde gösterilmektedir.
Bu snippet'te, Box
composable'ının arka plan boyası olarak kullanılan bir ShaderBrush
oluşturuluyor. remember
, daha önce açıklandığı gibi yeniden oluşturmak maliyetli olduğundan ShaderBrush
örneğini depolar. remember
, seçilen arka plan resmi olan avatarRes
değerini key1
parametresi olarak alır. avatarRes
değişirse fırça yeni resimle yeniden oluşturulur ve avatarRes
'ya yeniden uygulanır.Box
Bu durum, kullanıcı bir seçiciden arka plan olarak 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) ) { /* ... */ } }
Aşağıdaki snippet'te durum, düz durum tutucu sınıfına yükseltilir
MyAppState
. rememberMyAppState
işlevi, remember
kullanarak sınıfın bir örneğini başlatmak için kullanılır. Bu tür işlevleri, yeniden oluşturma işlemlerinden sonra da varlığını sürdürecek bir örnek oluşturmak için kullanmak, Compose'da yaygın bir yöntemdir. rememberMyAppState
işlevi, remember
için key
parametresi olarak kullanılan windowSizeClass
değerini alır. Bu parametre değişirse uygulamanın, düz durum tutucu sınıfını en son değerle yeniden oluşturması gerekir. Örneğin, kullanıcının cihazı döndürmesi bu duruma neden olabilir.
@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 karar vermek ve depolanan değeri geçersiz kılmak için sınıfın equals uygulamasını kullanır.
Yeniden oluşturmanın ötesinde anahtarlarla durumu saklama
rememberSaveable
API, remember
etrafında bir sarmalayıcıdır ve verileri Bundle
içinde saklayabilir. Bu API, durumun yalnızca yeniden oluşturma sırasında değil, etkinlik yeniden oluşturma ve sistem tarafından başlatılan işlem sonlandırma sırasında da korunmasını sağlar.
rememberSaveable
, remember
'nin keys
aldığı parametreleri aynı amaçla alır.input
Girişlerden herhangi biri değiştiğinde önbellek geçersiz kılınır. İşlev bir sonraki sefer yeniden oluşturulduğunda rememberSaveable
hesaplama lambda bloğunu yeniden yürütür.
Aşağıdaki örnekte, rememberSaveable
, userTypedQuery
değerini typedQuery
değişene kadar saklar:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Daha fazla bilgi
State ve Jetpack Compose hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara göz atın.
Örnekler
Codelab uygulamaları
Videolar
Bloglar
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- Compose kullanıcı arayüzünüzü tasarlama
- Compose'da kullanıcı arayüzü durumunu kaydetme
- Oluşturma'daki yan etkiler