StateStore Android Jetpack'in bir parçasıdır.
StateStore, paylaşılan uygulama durumunu uygulamanız genelinde Compose State olarak depolayan ve gösteren, tip güvenliği sağlayan bir container'dır.
Kullanım alanları
Uygulama kapsamlı bir StateStore oluşturarak aynı işlemdeki uygulama bileşenleri arasında durum paylaşabilirsiniz:
- Birden fazla etkinlik: Uygulamanız aynı anda birden fazla etkinlik gösteriyorsa (ör. bir e-posta istemcisinde gelen kutusu etkinliği ve düzenleyici etkinliği) veya aynı anda çalışan birden çok kopyayı destekleyen bir etkinliğe sahipse (ör. doküman görüntüleyici etkinliği) aralarında bilgi paylaşmak için
StateStorekullanabilirsiniz. - Etkinlik ve hizmet: Bir etkinlik ile arka plan
CarAppServiceveya AppFunction arasındaki durumu senkronize edin. - Etkinlik ve içerik sağlayıcı veya widget: Bir etkinlik ile ana ekran widget'ı arasında durum paylaşın.
Bir singleton'ın yalnızca anahtarlı arama veya DataStore destekli işlem sonlandırma geri yüklemesi olmadan bellek içi State<T> değerine ihtiyacı varsa bunun yerine doğrudan singleton'da mutableStateOf özelliklerini gösterebilirsiniz. Uygulamanızdaki durum API'lerinin karşılaştırması için Mimariniz için doğru durum API'sini seçme başlıklı makaleyi inceleyin.
API'ye genel bakış
androidx.appstate.statestore paketi, StateStore ve StateStoreKey sınıflarını sağlar:
package androidx.appstate.statestore
import androidx.compose.runtime.State
import kotlinx.serialization.Serializable
public class StateStore {
public val keys: Set<StateStoreKey<*>>
public fun <T> getState(
stateKey: StateStoreKey<T>,
defaultValue: T = stateKey.defaultValue,
): State<T>
public fun <T> setState(stateKey: StateStoreKey<T>, value: T)
public inline fun <T> updateState(
stateKey: StateStoreKey<T>,
defaultValue: T = stateKey.defaultValue,
update: (T) -> T,
)
}
@Serializable
public open class StateStoreKey<T>(
public val defaultValue: T,
)
Durumunuzu tanımlama
StateStore, değerleri depolarken ve alırken tip güvenliği sağlamak için değerleri okumak ve yazmak amacıyla kullanılan anahtarları tanımlamak üzere StateStoreKey sınıfını kullanır. StateStoreKey tanımlarını private veya internal, durumun o bölümüne sahip olan yöneticiye, depoya ya da modüle saklayın:
@Serializable sealed interface FocusSession { @Serializable data object Idle : FocusSession @Serializable data class Running( val taskId: String, val endTimeMillis: Long, ) : FocusSession @Serializable data class Paused( val taskId: String, val remainingMillis: Long, ) : FocusSession } @Serializable private data object FocusSessionKey : StateStoreKey<FocusSession>(defaultValue = FocusSession.Idle)
StateStore örnekleri oluşturma ve ekleme
StateStore, uygulama veya modül kapsamında (örneğin, Application sınıfınızda veya bağımlılık ekleme modülünde) bir kez örneklendirdiğiniz ve StateStore'yi doğrudan kullanıcı arayüzü sınıflarına göstermek yerine durumu okuyan ve yazan yöneticilere veya depolara eklediğiniz normal bir sınıftır:
// Instantiate at the application or DI module level val stateStore = StateStore() // Inject into managers or repositories that encapsulate their own keys class FocusSessionManager( private val stateStore: StateStore, )
Okuma ve yazma durumu
Yöneticinizde veya deponuzda, özel StateStoreKey tanımlarınızı kullanarak eklenen StateStore içindeki değerleri okuyun, yazın ve güncelleyin. Ayrıca, salt okunur State<T> özelliklerini ve mutasyon işlevlerini çağrı yapanlara gösterin.
Okunma durumu
State<T> nesnesi almak için getState(stateKey, defaultValue) yöntemini kullanın. Anahtar henüz başlatılmadıysa StateStore, anahtarı defaultValue parametresiyle doldurur. Bu parametre varsayılan olarak stateKey.defaultValue değerini alır (veya doldurulmamış bir anahtarı başlatırken özel bir defaultValue değeri iletebilirsiniz). getState bir State<T> döndürdüğü için ViewModel'ler, kullanıcı arayüzü composable'ları, widget'lar ve transform blokları, yöneticinin özelliğini reaktif olarak okuyabilir:
class FocusSessionManager( private val stateStore: StateStore, ) { val session: State<FocusSession> = stateStore.getState(FocusSessionKey) } class FocusTimerViewModel( focusSessionManager: FocusSessionManager, ) : ViewModel() { val session: State<FocusSession> = focusSessionManager.session } @Composable fun FocusBanner(viewModel: FocusTimerViewModel = viewModel()) { // Reads state reactively; recomposes when FocusSessionKey updates when (val session = viewModel.session.value) { FocusSession.Idle -> Text(text = "No active focus session") is FocusSession.Running -> Text(text = "Focusing on ${session.taskId}") is FocusSession.Paused -> Text(text = "Paused: ${session.taskId}") } }
Eyaleti yazın
Yöneticinizde bir anahtarla ilişkili değeri ilk kullanıma hazırlamak veya değiştirmek için setState(stateKey, value) kullanın:
class FocusSessionManager( private val stateStore: StateStore, ) { val session: State<FocusSession> = stateStore.getState(FocusSessionKey) fun startFocus(taskId: String, endTimeMillis: Long) { stateStore.setState( FocusSessionKey, FocusSession.Running( taskId = taskId, endTimeMillis = endTimeMillis, ), ) } fun endFocus() { stateStore.setState(FocusSessionKey, FocusSession.Idle) } }
Durumu güncelleme
Bir durumu mevcut değerine göre güncellemeniz gerekiyorsa updateState kullanın.
Bu, mevcut değeri alır (veya ayarlanmamışsa varsayılan değeri kullanır) ve güncelleme lambdanızı uygular:
class FocusSessionManager( private val stateStore: StateStore, ) { val session: State<FocusSession> = stateStore.getState(FocusSessionKey) fun pauseFocus(nowMillis: Long) { stateStore.updateState(FocusSessionKey) { current -> if (current is FocusSession.Running) { FocusSession.Paused( taskId = current.taskId, remainingMillis = (current.endTimeMillis - nowMillis) .coerceAtLeast(0L), ) } else { current } } } fun resumeFocus(nowMillis: Long) { stateStore.updateState(FocusSessionKey) { current -> if (current is FocusSession.Paused) { FocusSession.Running( taskId = current.taskId, endTimeMillis = nowMillis + current.remainingMillis, ) } else { current } } } }
Entegrasyonlar
StateStore, işlem sonlandırma ve uygulama yeniden başlatma işlemleri boyunca durumu korumak ve geri yüklemek için Jetpack DataStore ile entegre olur.
DataStore
androidx.appstate.statestore:statestore-datastore yapısı, paylaşılan StateStore örneğinizde kalıcılığı bir kez yapılandırmanıza olanak tanır. Böylece, herhangi bir yöneticinin kalıcı anahtarları otomatik olarak kaydedilir ve DataStore kullanılarak diskten geri yüklenir.
androidx.appstate.datastore paketi aşağıdaki API'leri sağlar:
package androidx.appstate.datastore
import androidx.appstate.statestore.StateStore
import androidx.datastore.core.DataStore
import kotlinx.coroutines.CoroutineScope
public interface PersistToDataStore
public suspend fun StateStore.syncToDataStore(
path: String,
coroutineScope: CoroutineScope,
)
public suspend fun StateStore.syncToDataStore(
dataStore: DataStore<StateStorePreferences>,
)
PersistToDataStoreuygulayın:PersistToDataStorearayüzünü uygulayarak kalıcı olması gereken tümStateStoreKeyöğelerini işaretleyin:
@Serializable private data object FocusSessionKey : StateStoreKey<FocusSession>(defaultValue = FocusSession.Idle), PersistToDataStore
StateStoreöğesini DataStore'a bağlama: PaylaşılanStateStoreörneğinizi ayarlarken (ör.Applicationsınıfınızda veya bağımlılık ekleme modülünüzde)syncToDataStoreöğesini bir kez çağırın.syncToDataStore, kaydedilen değerleri diskten geri yüklemek ve gelecekteki değişiklikleri sağlanancoroutineScopeiçinde kaydetmeye devam etmek için süresiz olarak askıya alınan birsuspendişlevi olduğundan, bu işlevilaunchiçinde çağırın ve uygulama düzeyindekiCoroutineScopedeğerinizi iletin. BaşlangıçtagetState, bellektekidefaultValuedeğerini döndürür ve DataStore, diskten okuma işlemini tamamladıktan sonraStatedeğerini günceller:
class ProductivityApplication : Application() { val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Default) val stateStore = StateStore().also { store -> // Restore saved values and automatically persist future changes // for all PersistToDataStore keys across managers applicationScope.launch { store.syncToDataStore( path = dataStoreFile("statestore.json").absolutePath, coroutineScope = applicationScope, ) } } val focusSessionManager = FocusSessionManager(stateStore) }
DataStore kalıcılık yönergeleri
syncToDataStore, bir PersistToDataStore anahtarının değeri her değiştiğinde serileştirme yapıp diske yazdığından, nelerin ne zaman kalıcı hale getirileceğini seçerken aşağıdaki yönergeleri uygulayın:
- Her zamanlayıcı adımı yerine başlangıç veya bitiş zaman damgalarını kaydedin: Zamanlayıcılar veya oynatma ilerleme durumu için her saniye veya karede bir
PersistToDataStoreanahtarını güncellemek yerine sabit bir referans değeri (ör.endTimeMillisveyastartedAtMillis) kullanın ve kullanıcı arayüzünde canlı olarak geçen veya kalan süreyi hesaplayın. - Kalıcı bir anahtarı güncellemeden önce hızlı kullanıcı girişini geciktirin: Metin taslakları, arama sorguları veya kaydırma çubukları için anlık girişi bellek içi
MutableState(veyaPersistToDataStoreuygulamayan birStateStoreKey) içinde tutun ve yalnızca giriş tamamlandıktan sonra kalıcıStateStoreKeyüzerindesetStateçağrısı yapın. - Kalıcı anahtarları basit tutun:
StateStoreiçindeki tümPersistToDataStoreanahtarları, her güncellemede tek bir dosyada birlikte serileştirilir. Etkin kimlikler, filtre seçimleri veya devam eden form taslakları gibi kompakt oturum durumlarını kalıcı hale getirin ve büyük koleksiyonları veya sorgulanabilir veri kümelerini Room'da saklayın.