APIهای تعیین محدوده ViewModel بخشی از Android Jetpack هستند.
محدوده (scope) کلید استفاده موثر از ViewModelها است. هر ViewModel به یک شیء که رابط ViewModelStoreOwner را پیادهسازی میکند، محدود میشود. چندین API وجود دارد که به شما امکان میدهد محدوده ViewModelهای خود را راحتتر مدیریت کنید. این سند برخی از تکنیکهای کلیدی را که باید بدانید، شرح میدهد.
متد ViewModelProvider.get() به شما امکان میدهد نمونهای از ViewModel را که به هر ViewModelStoreOwner محدود شده است، دریافت کنید. برای کاربران Kotlin، توابع الحاقی مختلفی برای رایجترین موارد استفاده در دسترس است. همه پیادهسازیهای توابع الحاقی Kotlin از API ViewModelProvider در زیر کاپوت استفاده میکنند.
ViewModelها به نزدیکترین ViewModelStoreOwner محدود میشوند
شما میتوانید یک ViewModel را به یک composable ، Activity یا destination از یک Navigation graph محدود کنید. تابع viewModel() در Compose به شما این امکان را میدهد که یک نمونه از ViewModel را که به نزدیکترین ViewModelStoreOwner محدود شده است، دریافت کنید.
import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( modifier: Modifier = Modifier, // ViewModel API available in lifecycle.lifecycle-viewmodel-compose // The ViewModel is scoped to the closest ViewModelStoreOwner provided // via the LocalViewModelStoreOwner CompositionLocal. In order of proximity, // this could be the destination of a Navigation graph // or the host Activity. viewModel: MyViewModel = viewModel() ) { /* ... */ }
ViewModelها به هر ViewModelStoreOwner محدود میشوند
تابع viewModel() یک پارامتر اختیاری viewModelStoreOwner دریافت میکند که میتوانید از آن برای مشخص کردن اینکه نمونه ViewModel به کدام ViewModelStoreOwner محدود شده است، استفاده کنید.
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.ViewModelStoreOwner @Composable fun MyScreen( // A custom owner passed in, such as a parent NavBackStackEntry customOwner: ViewModelStoreOwner, // The ViewModel is now scoped to the provided customOwner viewModel: MyViewModel = viewModel(viewModelStoreOwner = customOwner) ) { /* ... */ }
ViewModelها به یک composable محدود شدهاند
شما میتوانید از rememberViewModelStoreOwner() برای دسترسی مستقیم به یک ViewModel در محل فراخوانی یک composable استفاده کنید. این امر به ویژه برای کامپوننتهای رابط کاربری که به صورت پویا بر اساس وضعیت به صفحه نمایش اضافه یا از آن حذف میشوند، مانند آیتمهای یک صفحه یا lazy list، مفید است. هنگامی که composable که مالک ViewModelStoreOwner است، ترکیب را ترک میکند، ViewModelStore مرتبط پاک شده و ViewModel از بین میرود.
از rememberViewModelStoreOwner() برای ایجاد یک فروشگاه آگاه از چرخه حیات که از تغییرات پیکربندی جان سالم به در میبرد، استفاده کنید.
@Composable
fun RememberViewModelStoreOwnerSample() {
// Create a ViewModelStoreOwner scoped to this specific call site.
// When this composable leaves the composition,
// the associated ViewModelStore will be cleared.
val scopedOwner = rememberViewModelStoreOwner()
CompositionLocalProvider(LocalViewModelStoreOwner provides scopedOwner) {
// This ViewModel is scoped to `scopedOwner`.
// It will survive configuration changes but will be cleared when
// the composable is removed from the UI tree.
val viewModel = viewModel { TestViewModel("scoped_data") }
// Use the ViewModel
}
}
برای پیادهسازیهای پیچیدهتر، مانند HorizontalPager یا مواردی که به چندین scope مستقل نیاز دارند، از rememberViewModelStoreProvider() استفاده کنید. این به شما امکان میدهد نمونههای ViewModelStoreOwner متمایزی برای کلیدهای مختلف (مانند اندیسهای صفحه) ایجاد کنید. به این ترتیب، هر صفحه حالت ViewModel مستقل خود را حفظ میکند.
@Composable
fun RememberViewModelStoreProviderSample() {
val storeProvider = rememberViewModelStoreProvider()
val pages = listOf("Page 1", "Page 2", "Page 3")
HorizontalPager(pageCount = pages.size) { page ->
// Create a ViewModelStoreOwner for the specific page using the provider.
val pageOwner = rememberViewModelStoreOwner(provider = storeProvider, key = page)
CompositionLocalProvider(LocalViewModelStoreOwner provides pageOwner) {
val pageViewModel = viewModel { TestViewModel(pages[page]) }
// Use pageViewModel
}
}
}
ViewModelها به گراف ناوبری محدود میشوند
گرافهای ناوبری (Navigation Graphs) همچنین مالکین فروشگاه ViewModel هستند. اگر از Navigation Compose استفاده میکنید، میتوانید با تابع getBackStackEntry() نمونهای از ViewModel را که به یک گراف ناوبری (Navigation Graph) محدود شده است، دریافت کنید.
viewModel() نمونه را از نزدیکترین ViewModelStoreOwner ارائه شده توسط LocalViewModelStoreOwner CompositionLocal بازیابی میکند. در یک برنامه Compose معمولی که از Jetpack Navigation استفاده میکند، این مالک، ورودی فعلی Navigation در پشته پشتی است. این بدان معناست که ViewModel تا زمانی که آن مقصد در پشته پشتی وجود داشته باشد، در حافظه باقی میماند.
import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyAppNavHost() { // ... composable("myScreen") { backStackEntry -> // Retrieve the NavBackStackEntry of "parentNavigationRoute" val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("parentNavigationRoute") } // Get the ViewModel scoped to the `parentNavigationRoute` Nav graph val parentViewModel: SharedViewModel = viewModel(parentEntry) // ... } }
اگر علاوه بر Jetpack Navigation از Hilt نیز استفاده میکنید، میتوانید از API hiltNavGraphViewModels(graphId) به شرح زیر استفاده کنید.
import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyAppNavHost() { // ... composable("myScreen") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("parentNavigationRoute") } // ViewModel API available in hilt.hilt-navigation-compose // The ViewModel is scoped to the `parentNavigationRoute` Navigation graph // and is provided using the Hilt-generated ViewModel factory val parentViewModel: SharedViewModel = hiltViewModel(parentEntry) // ... } }
منابع اضافی
برای کسب اطلاعات بیشتر در مورد ViewModelها و دامنه، به منابع اضافی زیر مراجعه کنید: