Jetpack Compose State<T> و
MutableState<T> نگهدارندههای مقدار با کاربرد عمومی هستند که توسط
سیستم عکس آنی Compose پشتیبانی میشوند. اگرچه این حالتها بیشتر برای هدایت بازترکیب رابط کاربری استفاده میشوند، سیستم عکس آنی بهخودیخود به پردازش رابط کاربری وابسته نیست.
با کتابخانههای AppState—Transform
و StateStore—میتوانید
Compose State را در ViewModel، مدیران، مخزنها، و سرویسهای پسزمینه
نگه دارید، مشتق کنید، مشاهده کنید، و حفظ کنید.
Why use Compose State beyond the UI?
وقتی Compose State را در یک بلوک مشاهدهکننده وضعیت میخوانید—مانند یک UI
composable، transform، یا
derivedStateOf—زمان اجرای Compose دو مزیت کلیدی
در هر لایه از معماری شما ارائه میدهد:
- ردگیری وابستگی خودکار و پویا: خواندن
.valueیک حالت (یا استفاده از واگذاری ویژگیby) بهطور خودکار آن حالت را بهعنوان وابستگی بلوک ثبت میکند. چون ردیابی پویا است، وابستگیها در زمان اجرا براساس اینکه کدام مسیرهای کد اجرا میشوند تعیین میشوند. اگر شاخه شرطی اجرا نشود (برای مثال، پساز بررسیifیاreturnزودهنگام)، حالتهای داخل آن شاخه خوانده نمیشوند و تغییرات در آنها باعث بازمحاسبههای غیرضروری نمیشود. - ثبات و دانهبندی: میتوانید ویژگیهای
MutableStateجداگانه و با دانهبندی ریز را اعلام کنید و نوشتنهای چندویژگی را درSnapshot.withMutableSnapshotقرار دهید. بهروزرسانیهای میانی به عکس آنی تغییرپذیر محدود میشوند و وقتی بلوک تکمیل میشود، بهصورت اتمی اعمال میشوند، بنابراین ناظرانی که داخل عکس آنی را میخوانند هرگز وضعیت میانی ناسازگار را نمیبینند و فقط زمانی دوباره محاسبه میکنند که ویژگیهای خاصی که میخوانند تغییر کند. برخلافStateFlow، لازم نیست بین یکStateFlow<UiState>یکپارچه (که با تغییر هر فیلد، همه جمعآورندهها را نامعتبر میکند) و ویژگیهای جداگانهStateFlow(که نمیتوانند باهم در یک تراکنش اتمی بهروز شوند) یکی را انتخاب کنید.
انتخاب میانای برنامهسازی کاربردی وضعیت مناسب در سراسر معماری
انتخاب کنید که چگونه Compose State را براساس مدتزمان ماندگاری یک قطعه از
وضعیت و اینکه کدام مؤلفهها باید به آن دسترسی داشته باشند، نگه دارید و حفظ کنید:
| دستهبندی ایالت | طول عمر و دامنه | مثالها | میاناهای برنامهسازی کاربردی توصیهشده Compose State |
|---|---|---|---|
| وضعیت زنده | همیشه در حافظه ذخیره میشود؛ در زمان راهاندازی بهصورت تازه پُرسمان میشود و درطول مرگ پردازش باقی نمیماند. | وضعیت اتصال شبکه، وضعیت اتصال بلوتوث، وضعیت موقت واسط کاربر مانند انتخاب مورد. |
|
| وضعیت میانای کاربر گذرا | دربرابر تغییرات پیکربندی و مرگ پردازش آغازشده توسط سیستم دوام میآورد، بهطور نامحدود ذخیره نمیشود؛ محدود به یک صفحه یا فعالیت است. | عناصر میانای کاربر گسترده یا جمعشده، موقعیت پیمایش، پرسمان جستجوی صفحه، یا کلیدهای فیلتر. |
|
| وضعیت جلسه گذرا | پساز مرگ فرایند پسزمینهای باقی میماند، بهطور نامحدود ذخیره نمیشود؛ در فعالیتها، سرویسها، یا ابزارهها همرسانی میشود. | زمانسنج تمرکز فعال، سبد خرید چندمرحلهای، یا پیشنویس فرم درحال تکمیل. |
|
| وضعیت دائمی | بهطور نامحدود در دیسک نگهداری میشود. | اولویتها و تنظیمات کاربر (DataStore)، دادههای ساختاریافته برنامه و کتابخانههای رسانه (Room). | جریانهای DataStore یا Room جمعآوریشده در transform بااستفاده از collectAsState |
استفاده از «وضعیت Compose» در ViewModel
درون ViewModel، میتوانید ورودیهای مستقل صفحهنمایش را بهعنوان ویژگیهای دانهای MutableState اعلام کنید، آنها را در سراسر مرگ پردازش با SavedStateHandle.saveable حفظ کنید، چندین ویژگی را بهصورت اتمی با Snapshot.withMutableSnapshot بهروز کنید، و آنها را با جریانهای مخزن Flow درون transform ترکیب کنید:
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, ) } }
الگوهای کلیدی در این ViewModel:
- استفاده از
SavedStateHandle.saveableبرای حالت ذخیرهشده واکنشی: واگذاریsearchQueryبهSavedStateHandle.saveableباmutableStateOf(ازandroidx.lifecycle:lifecycle-viewmodel-compose) مقدار را در سراسر مرگ پردازش بهعنوانMutableStateحفظ میکند، بنابراینtransformخواندنها را بهطور خودکار ردیابی میکند. ازSavedStateHandle.savedخالی که بهجای ComposeStateیک ویژگی Kotlin ساده برمیگرداند و درصورت تغییر، ترکیببندی مجدد را راهاندازی نمیکند، اجتناب کنید. - نوشتنهای اتمی چندویژگی با
Snapshot.withMutableSnapshot: بهروزرسانیsearchQueryوselectedTaskIdsدرSnapshot.withMutableSnapshotنوشتنها را جدا میکند و هر دو تغییر را در یک تراکنش عکس آنی اتمی واحد ثبت میکند، بنابراین ناظران (ازجملهtransform) هر دو بهروزرسانی را باهم در یک گذر بازترکیب میبینند، بهجای اینکهsearchQueryجدید را جفتشده باselectedTaskIdsقدیمی مشاهده کنند. - استفاده مجدد از جریانها در ترکیببندیهای مجدد با
remember(key): پیچیدنtasksRepository.getTasks(searchQuery)درrememberباsearchQueryبهعنوان کلید تضمین میکند که وقتیselectedTaskIdsتغییر میکند و بلوکtransformرا مجدداً ترکیببندی میکند، Compose از پایگاه داده موجودFlowاستفاده مجدد میکند بهجای اینکه پُرسمان را بازراهاندازی کند.
همرسانی وضعیت سیستم زنده در سراسر برنامه
برای وضعیت سیستم زنده که در چندین ViewModel، فعالیت، یا سرویس همرسانی میشود (مانند وضعیت اتصال شبکه یا بلوتوث)، نمیخواهید وضعیت قدیمی را درصورت مرگ پردازش در دیسک حفظ کنید. درعوض، وضعیت فعلی سیستم را در زمان راهاندازی پرسمان کنید، آن را در یک ویژگی خصوصی mutableStateOf در داخل یک سینگلتون با محدوده برنامه نگه دارید، و یک State<T> فقط خواندنی را نمایش دهید:
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 از خواندن و بهروزرسانیهای سازگار از هر رشتهای پشتیبانی میکند، بنابراین
NetworkCallback میتواند _isOnline.value را مستقیماً از رشته فراخوانی پسزمینهاش بهروز کند. اگر یک فراخوانی پسزمینه چندین ویژگی MutableState را باهم بهروز میکند، نوشتنها را در Snapshot.withMutableSnapshot قرار دهید تا بهصورت اتمی اعمال شوند.
هر مؤلفهای در برنامهتان میتواند networkMonitor.isOnline.value را بخواند—چه بهعنوان بررسی یکباره، چه در UI composable، یا در بلوک مشاهده وضعیت مانند listener، derivedStateOf، یا transform. برای مثال، TaskListViewModel میتواند
networkMonitor.isOnline.value را در بلوک transform خود بخواند:
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 networkMonitor.isOnline.value را درکنار
searchQuery، selectedTaskIds، و مخزن Flow ردیابی میکند، هرگونه تغییر در
اتصالپذیری بهطور خودکار TaskListState.Success را بدون
پرسوجوی مجدد از پایگاه داده دوباره محاسبه میکند.