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ında birkaç durum örneği:
- Ağ bağlantısı kurulamadığında gösterilen bir Snackbar.
- Bir blog yayını ve ilişkili yorumlar.
- Kullanıcı düğmeleri tıkladığında oynatılan dalga 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 bileşenler arasındaki bağlantıya ve Jetpack Compose'un durumla daha kolay çalışmak için sunduğu API'lere odaklanılmaktadır.
Durum ve kompozisyon
Oluşturma beyandır. Bu nedenle, tek güncelleme yöntemi, aynı derlenebilir öğeyi 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 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 kodu çalıştırıp metin girmeye çalışırsanız hiçbir şey olmadığını görürsünüz. Bunun nedeni, TextField
'ün kendisini güncellememesidir. TextField
, value
parametresi değiştiğinde güncellenir. Bunun nedeni, bestenin ve yeniden bestenin Compose’da çalışma şeklidir.
İlk kompozisyon ve yeniden kompozisyon hakkında daha fazla bilgi edinmek için Oluşturma modunda düşünme başlıklı makaleyi inceleyin.
Birleştirilebilir öğelerdeki durum
Oluşturulabilir işlevler, bir nesneyi bellekte depolamak için remember
API'yi kullanabilir. remember
tarafından hesaplanan bir değer, ilk kompozisyon sırasında kompozisyonda depolanır ve depolanan değer yeniden kompozisyon sırasında döndürülür.
remember
hem değişken hem de sabit nesneleri depolamak için kullanılabilir.
mutableStateOf
, MutableState<T>
adlı gözlemlenebilir bir tür oluşturur. Bu tür, derleme çalışma zamanında entegre edilmiş bir gözlemlenebilir türdür.
interface MutableState<T> : State<T> {
override var value: T
}
value
'te yapılan değişiklikler, value
değerini okuyan tüm derlenebilir işlevlerin yeniden derlenmesini planlar.
Bir bileşende MutableState
nesnesi tanımlamanın üç 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 şekeri olarak sağlanır. Yazdığınız bileşende en kolay okunur kodu üreten seçeneği tercih etmeniz gerekir.
by
temsilci söz dizimi aşağıdaki içe aktarma işlemlerini gerektirir:
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şsa karşılama mesajını görüntülemek 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ş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 özel bir tasarruf nesnesi iletebilirsiniz.
Desteklenen diğer durum türleri
Compose, durum bilgisini korumak 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, durum değiştiğinde birleştirilebilirlerin otomatik olarak yeniden derlenebilmesi için türü State<T>
olarak 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 öğeleri ekleyin:
Flow
:collectAsStateWithLifecycle()
collectAsStateWithLifecycle()
,Flow
kaynağından yaşam döngüsüne duyarlı bir şekilde değer toplayarak uygulamanızın uygulama kaynaklarını korumasını sağlar. 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.8.7")
}
Groovy
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
-
collectAsState
, aynı zamanda birFlow
öğesinden değerleri toplayıp Oluştur simgesineState
dönüştürdüğü içincollectAsStateWithLifecycle
ile benzerdir.Yalnızca Android için olan
collectAsStateWithLifecycle
yerine platformdan bağımsız kod içincollectAsState
kullanın.collectAsState
,compose-runtime
'te kullanılabildiği için ek bağımlılıklara ihtiyaç duymaz. -
observeAsState()
, buLiveData
öğesini gözlemlemeye başlar ve değerleriniState
üzerinden temsil eder.build.gradle
dosyasında aşağıdaki bağımlılık gereklidir:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-livedata:1.7.8")
}
Groovy
dependencies {
...
implementation "androidx.compose.runtime:runtime-livedata:1.7.8"
}
-
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 zorunludur:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava2:1.7.8")
}
Groovy
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava2:1.7.8"
}
-
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 zorunludur:
Kotlin
dependencies {
...
implementation("androidx.compose.runtime:runtime-rxjava3:1.7.8")
}
Eski
dependencies {
...
implementation "androidx.compose.runtime:runtime-rxjava3:1.7.8"
}
Durum bilgili ve durum bilgisiz
Bir nesneyi depolamak için remember
kullanan bir bileşen, dahili durum oluşturur ve bileşeni durumlu hale getirir. HelloContent
, name
durumunu dahili olarak saklayıp değiştirdiği için durum bilgisine sahip bir bileşen örneğidir. Bu, arayan kişinin durumu kontrol etmesine gerek olmadığı ve durumu yönetmek zorunda kalmadan kullanabildiği durumlarda yararlı olabilir. Ancak, dahili durumu olan composable'lar daha az yeniden kullanılabilir ve test edilmesi daha zordur.
Durumsuz bir bileşen, herhangi bir durum içermeyen bir bileşendir. 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 onValueChange
ile sınırlı değilsiniz. Kompozit için daha spesifik etkinlikler uygunsa bunları lambda kullanarak tanımlamanız gerekir.
Bu şekilde kaldırılan durum bazı önemli özelliklere sahiptir:
- Tek doğru kaynak: Durumu kopyalamak yerine taşıyarak yalnızca tek bir doğru kaynak olmasını sağlıyoruz. Bu sayede hatalardan kaçınabilirsiniz.
- Encapsulated: Yalnızca durum bilgili composable'ların durumlarını değiştirebilir. Tamamen dahilidir.
- Paylaşılabilir: Kaldırılmış durum, birden fazla composable ile paylaşılabilir.
name
değerini farklı bir bileşende okumak isterseniz kaldırma işlemi bunu yapmanıza olanak tanır. - Engellenebilir: Durum bilgisi olmayan birleştirilebilir öğeleri çağıranlar, 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, artık
name
'üViewModel
'e taşımak mümkün.
Örnek durumda, name
ve onValueChange
öğelerini HelloContent
'den ayıklayıp ağaçta HelloContent
'yi çağıran bir HelloScreen
bileşenine 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
'ten kaldırarak, birleştirilebilir öğe hakkında mantık yürütmek, farklı durumlarda yeniden kullanmak ve test etmek daha kolaydır. HelloContent
, durumunun depolanma şeklinden ayrılır. Ayrıştırma, HelloScreen
'ü değiştirirseniz veya değiştirirseniz HelloContent
'un uygulanma şeklini değiştirmeniz gerekmediği anlamına gelir.

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
iken HelloScreen
olur. Tek yönlü veri akışını izleyerek, kullanıcı arayüzünde durumu gösteren bileşenleri, durumunu depolayan ve değiştiren uygulamanızın bölümlerinden ayırabilirsiniz.
Daha fazla bilgi edinmek için Kaldırma durumu sayfasını inceleyin.
Oluşturma bölümünde durumu geri yükleme
rememberSaveable
API'si, kayıtlı örnek durumu mekanizmasını kullanarak yeniden oluşturma işlemlerinde ve ayrıca etkinlik veya süreç yeniden oluşturma işlemlerinde durumu koruduğu için remember
'e benzer şekilde çalışır. Örneğin, ekran döndürüldüğünde bu durumla karşılaşabilirsiniz.
Durumu depolama yöntemleri
Bundle
'e eklenen tüm veri türleri otomatik olarak kaydedilir. Bundle
'e eklenemeyen bir öğeyi kaydetmek istiyorsanız birkaç seçeneğiniz vardır.
Paket haline getir
En basit çözüm, nesneye @Parcelize
ek açıklama eklemektir. Nesne ayrıştırılabilir hale gelir ve paketlenebilir. Örneğin, bu kodda paketlenebilir bir City
veri türü oluşturulur ve duruma kaydedilir.
@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
'ye kaydedebileceği bir değer kümesine dönüştürmeyle ilgili 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")) } }
ListSaver
Haritanın anahtarlarını tanımlama ihtiyacını ortadan kaldırmak için listSaver
'ü 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'daki eyalet sahipleri
Basit durum kaldırma işlemi, composable işlevlerin kendisinden yönetilebilir. Ancak, takip edilecek durum miktarı artarsa veya birleştirilebilir işlevlerde uygulanacak 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 kaldırma dokümanlarına veya daha genel olarak mimari kılavuzundaki Durum tutucular ve kullanıcı arayüzü durumu sayfasına göz atın.
Tuşlar değiştiğinde hesaplamaları hatırlamayı yeniden tetikle
remember
API, MutableState
ile birlikte sıkça kullanılır:
var name by remember { mutableStateOf("") }
Burada remember
işlevinin kullanılması, MutableState
değerinin yeniden derlemelerden etkilenmemesini sağlar.
Genel olarak remember
, calculation
lambda parametresi alır. remember
ilk ç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 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 derlemede 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 kompozisyondan çıkana kadar depolar. Ancak önbelleğe alınmış değeri geçersiz kılma yöntemi vardır. remember
API'si ayrıca bir key
veya keys
parametresi alır. Bu anahtarlardan herhangi biri değişirse işlev bir sonraki kez yeniden derlendiğinde remember
önbelleği geçersiz kılar ve hesaplama lambda bloğunu tekrar yürütür. Bu mekanizma, kompozisyondaki bir nesnenin kullanım ömrü üzerinde kontrol sahibi olmanızı sağlar. Hesaplama, hatırlanan değer kompozisyondan çıkana 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, bir ShaderBrush
oluşturulur ve Box
kompozit öğesinin arka plan boyası olarak kullanılır. remember
, daha önce açıklandığı gibi yeniden oluşturmanın pahalı olması nedeniyle ShaderBrush
örneğini saklar. remember
, seçili 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ı 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) ) { /* ... */ } }
Sonraki snippet'te state, basit bir 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 sağlar. Yeniden derlemelerden etkilenmeyen bir örnek oluşturmak için bu tür işlevleri göstermek, Oluştur'da yaygın bir modeldir. rememberMyAppState
işlevi, remember
için key
parametresi olarak işlev gören 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ı cihazı döndürdüğünde bu durum ortaya çıkabilir.
@Composable private fun rememberMyAppState( windowSizeClass: WindowSizeClass ): MyAppState { return remember(windowSizeClass) { MyAppState(windowSizeClass) } } @Stable class MyAppState( private val windowSizeClass: WindowSizeClass ) { /* ... */ }
Oluşturma, 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 eşit uygulamasını kullanır.
Yeniden derlemenin ötesinde anahtarlarla durumu depolama
rememberSaveable
API'si, verileri Bundle
içinde saklayabilen remember
sarmalayıcısıdır. Bu API, durumun yalnızca yeniden derlemeden değil, etkinlik yeniden oluşturma ve sistem tarafından başlatılan işlem sonlandırma işlemlerinden de sağ çıkmasına olanak tanır.
rememberSaveable
, remember
'nin keys
almasıyla aynı amaçla input
parametrelerini alır. Girişlerden herhangi biri değiştiğinde önbellek geçersiz kılınır. İşlev bir sonraki sefer yeniden derlendiğinde rememberSaveable
, hesaplama lambda bloğunu yeniden yürütür.
Aşağıdaki örnekte, rememberSaveable
, typedQuery
değişene kadar userTypedQuery
değerini saklar:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Daha fazla bilgi
Durum 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
- Oluştur'da kullanıcı arayüzü durumunu kaydetme
- Oluşturma bölümündeki yan etkiler