Jetpack Compose State<T> ve MutableState<T>, Compose anlık görüntü sistemi tarafından desteklenen genel amaçlı değer tutuculardır. En yaygın kullanım amacı kullanıcı arayüzü yeniden oluşturma işlemini tetiklemek olsa da anlık görüntü sistemi, kullanıcı arayüzü oluşturma işlemine bağlı değildir.
AppState kitaplıkları (Transform ve StateStore) sayesinde ViewModel'ler, yöneticiler, depolar ve arka plan hizmetleri genelinde Compose State öğelerini tutabilir, türetebilir, gözlemleyebilir ve kalıcı hale getirebilirsiniz.
Oluşturma durumunu kullanıcı arayüzünün ötesinde neden kullanmalısınız?
Kullanıcı arayüzü composable'ı, transform veya derivedStateOf gibi durumu gözlemleyen bir blokta Compose State değerini okuduğunuzda Compose çalışma zamanı, mimarinizin tüm katmanlarında iki önemli avantaj sağlar:
- Otomatik ve dinamik bağımlılık izleme: Bir durumun
.valuedeğerini okumak (veyabyözellik yetkilendirmesini kullanmak), bu durumu otomatik olarak bloğun bağımlılığı olarak kaydeder. İzleme dinamik olduğundan bağımlılıklar, çalışma zamanında hangi kod yollarının yürütüldüğüne göre belirlenir. Koşullu bir dal kullanılmazsa (örneğin,ifkontrolünden veya erkenreturnişleminden sonra) bu daldaki durumlar okunmaz ve bunlarda yapılan değişiklikler gereksiz yeniden hesaplamaları tetiklemez. - Tutarlılık ve ayrıntı düzeyi: Ayrı, ayrıntılı
MutableStateözellikleri tanımlayabilir ve çok özellikli yazma işlemleriniSnapshot.withMutableSnapshotile sarmalayabilirsiniz. Ara güncellemeler, değiştirilebilir anlık görüntüye izole edilir ve blok tamamlandığında atomik olarak uygulanır. Bu sayede, anlık görüntü içinde okuma yapan gözlemciler hiçbir zaman tutarsız ara durum görmez ve yalnızca okudukları belirli özellikler değiştiğinde yeniden hesaplama yapar.StateFlow'nin aksine, tek bir monolitikStateFlow<UiState>(herhangi bir alan değiştiğinde her toplayıcıyı geçersiz kılar) ile ayrıStateFlowözellikleri (tek bir atomik işlemde birlikte güncellenemez) arasında seçim yapmanız gerekmez.
Mimariniz için doğru durum API'sini seçme
Bir durum parçasının ne kadar süreyle etkin kalması gerektiğine ve hangi bileşenlerin bu duruma erişmesi gerektiğine bağlı olarak Compose State'u nasıl tutacağınızı ve kalıcı hale getireceğinizi seçin:
| Eyalet kategorisi | Yaşam döngüsü ve kapsam | Örnekler | Önerilen Compose State API'leri |
|---|---|---|---|
| Canlı yayın durumu | Her zaman bellekte depolanır. Başlangıçta yeni sorgulanır ve işlem sonlandırma sırasında kalıcı olmaz. | Ağ bağlantısı durumu, Bluetooth bağlantısı durumu, öğe seçimi gibi geçici kullanıcı arayüzü durumu. |
|
| Geçici kullanıcı arayüzü durumu | Yapılandırma değişikliklerinden ve sistem tarafından başlatılan işlem sonlandırmadan etkilenmez, süresiz olarak saklanmaz; tek bir ekran veya etkinlikle sınırlıdır. | Genişletilmiş veya daraltılmış kullanıcı arayüzü öğeleri, kaydırma konumu, ekranda arama sorgusu veya filtre açma/kapatma düğmeleri |
|
| Geçici oturum durumu | Arka plan işlemi sonlandırıldığında silinmez, süresiz olarak saklanmaz; etkinlikler, hizmetler veya widget'lar arasında paylaşılır. | Etkin odaklanma zamanlayıcısı, çok adımlı ödeme sepeti veya devam eden form taslağı. |
|
| Kalıcı durum | Diskte süresiz olarak saklanır. | Kullanıcı tercihleri ve ayarları (DataStore), yapılandırılmış uygulama verileri ve medya kitaplıkları (Room). | transform içinde collectAsState kullanılarak toplanan DataStore veya Room akışları |
ViewModel'de Compose durumunu kullanma
ViewModel içinde, bağımsız ekran girişlerini ayrıntılı MutableState özellikleri olarak tanımlayabilir, SavedStateHandle.saveable ile işlem sonlandırma boyunca kalıcı hale getirebilir, Snapshot.withMutableSnapshot ile birden fazla özelliği atomik olarak güncelleyebilir ve bunları transform içinde depo Flow akışlarıyla birleştirebilirsiniz:
sealed interface TaskListState { data object Loading : TaskListState data class Success( val tasks: List<Task>, val selectedTaskIds: Set<String>, val isOnline: Boolean = true, ) : TaskListState } @HiltViewModel class TaskListViewModel @Inject constructor( private val tasksRepository: TasksRepository, savedStateHandle: SavedStateHandle, ) : ViewModel() { var selectedTaskIds by mutableStateOf(emptySet<String>()) private set var searchQuery by savedStateHandle.saveable { mutableStateOf("") } private set fun updateSearchQuery(query: String) { Snapshot.withMutableSnapshot { searchQuery = query selectedTaskIds = emptySet() } } val tasksState: State<TaskListState> = transform<TaskListState>( initialValue = TaskListState.Loading, scope = viewModelScope, ) { val tasks = remember(searchQuery) { tasksRepository.getTasks(searchQuery) }.collectAsState(initial = null).value ?: return@transform TaskListState.Loading TaskListState.Success( tasks = tasks, selectedTaskIds = selectedTaskIds, ) } }
Bu ViewModel belgesindeki temel örüntüler:
- Reaktif kaydedilmiş durum için
SavedStateHandle.saveablekullanın:mutableStateOfilesearchQueryöğesiniSavedStateHandle.saveableöğesine devretmek (androidx.lifecycle:lifecycle-viewmodel-composeüzerinden), değeri işlem sonlandırma boyuncaMutableStateolarak korur. Böylecetransform, okumaları otomatik olarak izler. YalnızcaSavedStateHandle.savedkullanmaktan kaçının. Bu, ComposeStateyerine düz bir Kotlin özelliği döndürür ve değiştirildiğinde yeniden oluşturmayı tetiklemez. Snapshot.withMutableSnapshotile atomik çoklu özellik yazma:Snapshot.withMutableSnapshotiçindesearchQueryveselectedTaskIdsdeğerlerini güncellemek, yazma işlemlerini izole eder ve her iki değişikliği de tek bir atomik anlık görüntü işleminde uygular. Böylece gözlemciler (transformdahil), yenisearchQuerydeğerini eskiselectedTaskIdsdeğeriyle eşlenmiş olarak görmek yerine her iki güncellemeyi de tek bir yeniden oluşturma geçişinde birlikte görür.remember(key)ile yeniden oluşturma işlemlerinde akışları yeniden kullanma:rememberiçindekitasksRepository.getTasks(searchQuery)öğesini anahtar olaraksearchQueryile sarmalamak,selectedTaskIdsdeğiştiğinde vetransformbloğunu yeniden oluşturduğunda Compose'un sorguyu yeniden başlatmak yerine mevcut veritabanıFlowöğesini yeniden kullanmasını sağlar.
Uygulamanızda canlı sistem durumunu paylaşma
Birden fazla ViewModel, etkinlik veya hizmet arasında paylaşılan canlı sistem durumu (ör. ağ veya Bluetooth bağlantı durumu) için işlem sonlandırma sırasında eski durumu diske kaydetmek istemezsiniz. Bunun yerine, başlangıçta geçerli sistem durumunu sorgulayın, uygulama kapsamlı bir singleton içinde özel bir mutableStateOf özelliğinde tutun ve salt okunur bir State<T> gösterin:
interface NetworkMonitor { val isOnline: State<Boolean> } @Singleton class LiveNetworkMonitor @Inject constructor( @ApplicationContext context: Context, ) : NetworkMonitor { private val connectivityManager = context.getSystemService(ConnectivityManager::class.java) private val _isOnline = mutableStateOf(checkCurrentConnectivity()) override val isOnline: State<Boolean> = _isOnline private val callback = object : ConnectivityManager.NetworkCallback() { override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities, ) { _isOnline.value = networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET ) } override fun onLost(network: Network) { _isOnline.value = false } } init { connectivityManager.registerDefaultNetworkCallback(callback) } private fun checkCurrentConnectivity(): Boolean { val network = connectivityManager.activeNetwork ?: return false val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false return capabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET ) } }
MutableState, herhangi bir iş parçacığından tutarlı okuma ve güncellemeleri destekler. Bu sayede NetworkCallback, _isOnline.value öğesini doğrudan arka plan geri çağırma iş parçacığından güncelleyebilir. Arka plan geri çağırması birden fazla MutableState özelliğini birlikte güncelliyorsa yazma işlemlerini Snapshot.withMutableSnapshot içine sarmalayarak atomik olarak uygulanmalarını sağlayın.
Uygulamanızdaki herhangi bir bileşen, networkMonitor.isOnline.value değerini okuyabilir. Bu okuma işlemi tek seferlik bir kontrol olarak, kullanıcı arayüzü composable'ı içinde veya listener, derivedStateOf ya da transform gibi bir durum gözlemleme bloğu içinde yapılabilir. Örneğin, TaskListViewModel, transform bloğundaki networkMonitor.isOnline.value değerini okuyabilir:
val tasksState: State<TaskListState> = transform<TaskListState>( initialValue = TaskListState.Loading, scope = viewModelScope, ) { val tasks = remember(searchQuery) { tasksRepository.getTasks(searchQuery) }.collectAsState(initial = null).value ?: return@transform TaskListState.Loading TaskListState.Success( tasks = tasks, selectedTaskIds = selectedTaskIds, isOnline = networkMonitor.isOnline.value, ) }
transform, searchQuery, selectedTaskIds ve Flow deposuyla birlikte networkMonitor.isOnline.value öğesini de izlediğinden, bağlantıda yapılan herhangi bir değişiklik, veritabanını yeniden sorgulamadan TaskListState.Success öğesini otomatik olarak yeniden hesaplar.