StateStore Bagian dari Android Jetpack.
StateStore adalah penampung yang aman dari jenis yang menyimpan dan mengekspos status aplikasi
bersama sebagai State Compose di seluruh aplikasi Anda.
Kasus penggunaan
Dengan membuat StateStore cakupan aplikasi, Anda dapat berbagi status antara
komponen aplikasi dalam proses yang sama:
- Beberapa aktivitas: Jika aplikasi Anda menampilkan beberapa aktivitas
secara bersamaan (seperti aktivitas kotak masuk dan aktivitas editor di program
email) atau memiliki aktivitas yang mendukung multi-instance
(seperti aktivitas penampil dokumen), Anda dapat menggunakan
StateStoreuntuk berbagi informasi di antara aktivitas tersebut. - Aktivitas dan layanan: Sinkronkan status antara aktivitas dan
CarAppServiceatau AppFunction latar belakang. - Aktivitas dan penyedia konten atau widget: Berbagi status antara aktivitas dan widget layar utama.
Jika singleton hanya memerlukan State<T> dalam memori tanpa pencarian dengan kunci atau
pemulihan penghentian proses yang didukung DataStore, Anda dapat mengekspos properti mutableStateOf
langsung di singleton. Untuk perbandingan API status
di seluruh aplikasi, lihat Memilih API status yang tepat di seluruh
arsitektur.
Ringkasan API
Paket androidx.appstate.statestore menyediakan class StateStore dan
StateStoreKey:
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,
)
Tentukan status Anda
Untuk memastikan keamanan jenis saat menyimpan dan mengambil nilai, StateStore menggunakan
class StateStoreKey untuk menentukan kunci yang digunakan untuk membaca dan menulis nilai. Simpan definisi StateStoreKey private atau internal ke pengelola, repositori, atau modul yang memiliki bagian status tersebut:
@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)
Membuat dan menginjeksikan instance StateStore
StateStore adalah class reguler yang Anda buat instance-nya sekali di cakupan aplikasi atau
modul (misalnya, di class Application atau modul injeksi
dependensi) dan dimasukkan ke dalam pengelola atau repositori yang membaca dan menulis status,
bukan mengekspos StateStore langsung ke class UI:
// 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, )
Status baca dan tulis
Di dalam pengelola atau repositori, baca, tulis, dan perbarui nilai dalam
StateStore yang dimasukkan menggunakan definisi StateStoreKey pribadi, dan ekspos
properti State<T> hanya baca dan fungsi mutasi ke pemanggil.
Status baca
Gunakan getState(stateKey, defaultValue) untuk mengambil objek State<T>. Jika kunci belum diinisialisasi, StateStore akan mengisinya dengan parameter defaultValue, yang secara default ditetapkan ke stateKey.defaultValue (atau Anda dapat meneruskan defaultValue kustom saat menginisialisasi kunci yang belum diisi). Karena
getState menampilkan State<T>, ViewModel, composable UI, widget, dan
blok transform dapat membaca properti pengelola
secara reaktif:
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}") } }
Status tulis
Gunakan setState(stateKey, value) di dalam pengelola untuk melakukan inisialisasi atau mengganti nilai yang terkait dengan kunci:
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) } }
Memperbarui status
Jika Anda perlu memperbarui status berdasarkan nilainya saat ini, gunakan updateState.
Tindakan ini akan mengambil nilai saat ini (atau menggunakan nilai default jika tidak ditetapkan) dan menerapkan lambda update Anda:
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 } } } }
Integrasi
StateStore terintegrasi dengan DataStore Jetpack untuk mempertahankan dan
memulihkan status di seluruh penghentian proses dan mulai ulang aplikasi.
DataStore
Artefak androidx.appstate.statestore:statestore-datastore memungkinkan Anda
mengonfigurasi persistensi sekali pada instance StateStore bersama sehingga
kunci yang dipertahankan pengelola akan otomatis disimpan dan dipulihkan dari disk menggunakan
DataStore.
Paket androidx.appstate.datastore menyediakan API berikut:
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>,
)
- Terapkan
PersistToDataStore: TandaiStateStoreKeyyang harus dipertahankan dengan menerapkan antarmukaPersistToDataStore:
@Serializable private data object FocusSessionKey : StateStoreKey<FocusSession>(defaultValue = FocusSession.Idle), PersistToDataStore
- Mengikat
StateStoreke DataStore: PanggilsyncToDataStoresekali saat menyiapkan instanceStateStorebersama (misalnya, di classApplicationatau modul injeksi dependensi). KarenasyncToDataStoreadalah fungsisuspendyang ditangguhkan tanpa batas waktu untuk memulihkan nilai yang disimpan dari disk dan terus menyimpan perubahan mendatang dalamcoroutineScopeyang disediakan, panggil fungsi tersebut di dalamlaunchdan teruskanCoroutineScopetingkat aplikasi Anda. Saat memulai,getStateawalnya menampilkandefaultValuedalam memori dan memperbaruiStatesetelah DataStore selesai membaca dari disk:
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) }
Panduan persistensi DataStore
Karena syncToDataStore melakukan serialisasi dan menulis ke disk setiap kali nilai kunci PersistToDataStore berubah, ikuti panduan ini saat memilih apa dan kapan harus mempertahankan:
- Simpan stempel waktu mulai atau akhir, bukan setiap tanda timer: Untuk timer atau
progres pemutaran, pertahankan nilai referensi yang stabil (seperti
endTimeMillisataustartedAtMillis), bukan memperbarui kunciPersistToDataStoresetiap detik atau frame, dan hitung tampilan waktu berlalu atau waktu tersisa secara live di UI. - Debounce input pengguna yang cepat sebelum memperbarui kunci yang dipertahankan: Untuk draf
teks, kueri penelusuran, atau penggeser, tahan input langsung dalam
MutableStatedalam memori (atauStateStoreKeyyang tidak mengimplementasikanPersistToDataStore) dan hanya panggilsetStatepadaStateStoreKeyyang dipertahankan setelah input ditetapkan. - Buat kunci yang dipertahankan tetap ringan: Semua kunci
PersistToDataStoredalamStateStorediserialisasi bersama menjadi satu file pada setiap update. Pertahankan status sesi yang ringkas—seperti ID aktif, pilihan filter, atau draf formulir yang sedang berlangsung—dan simpan koleksi besar atau set data yang dapat dikueri di Room.