ViewModel Scoping APIs Part of Android Jetpack.
Scope is key to using ViewModels effectively. Each ViewModel is scoped to an
object that implements the ViewModelStoreOwner interface. There are
several APIs that allow you to more easily manage the scope of your ViewModels.
This document outlines some of the key techniques you should know.
The ViewModelProvider.get() method lets you obtain an instance of a ViewModel
scoped to any ViewModelStoreOwner. For Kotlin users, there are different
extension functions available for the most common use cases. All Kotlin
extension function implementations use the ViewModelProvider API under the hood.
ViewModels scoped to the closest ViewModelStoreOwner
You can scope a ViewModel to an Activity, Fragment, or destination of a
Navigation graph. The
viewModels() extension
functions provided by the Activity, Fragment and Navigation libraries, and the
viewModel() function in Compose allows you to get an instance of the ViewModel
scoped to the closest ViewModelStoreOwner.
Views
importandroidx.activity.viewModels classMyActivity:AppCompatActivity(){ // ViewModel API available in activity.activity-ktx // The ViewModel is scoped to `this` Activity valviewModel:MyViewModelbyviewModels() } importandroidx.fragment.app.viewModels classMyFragment:Fragment(){ // ViewModel API available in fragment.fragment-ktx // The ViewModel is scoped to `this` Fragment valviewModel:MyViewModelbyviewModels() }
Views
importandroidx.lifecycle.ViewModelProvider; publicclass MyActivityextendsAppCompatActivity{ // The ViewModel is scoped to `this` Activity MyViewModelviewModel=newViewModelProvider(this).get(MyViewModel.class); } publicclass MyFragmentextendsFragment{ // The ViewModel is scoped to `this` Fragment MyViewModelviewModel=newViewModelProvider(this).get(MyViewModel.class); }
Compose
importandroidx.lifecycle.viewmodel.compose.viewModel @Composable funMyScreen( 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, the host Fragment, // or the host Activity. viewModel:MyViewModel=viewModel() ){/* ... */}
ViewModels scoped to any ViewModelStoreOwner
The ComponentActivity.viewModels() and Fragment.viewModels() functions in
the View system and the viewModel() function in Compose take an optional
ownerProducer parameter that you can use to specify to which
ViewModelStoreOwner the instance of the ViewModel is scoped to.
The following sample shows how to get an instance of a ViewModel scoped to the
parent fragment:
Views
importandroidx.fragment.app.viewModels classMyFragment:Fragment(){ // ViewModel API available in fragment.fragment-ktx // The ViewModel is scoped to the parent of `this` Fragment valviewModel:SharedViewModelbyviewModels( ownerProducer={requireParentFragment()} ) }
Views
importandroidx.lifecycle.ViewModelProvider; publicclass MyFragmentextendsFragment{ SharedViewModelviewModel; @Override publicvoidonViewCreated(Viewview,BundlesavedInstanceState){ // The ViewModel is scoped to the parent of `this` Fragment viewModel=newViewModelProvider(requireParentFragment()) .get(SharedViewModel.class); } }
Compose
importandroidx.lifecycle.viewmodel.compose.viewModel @Composable funMyScreen( context:Context=LocalContext.current, // ViewModel API available in lifecycle.lifecycle-viewmodel-compose // The ViewModel is scoped to the parent of the host Fragment // where this composable function is called viewModel:SharedViewModel=viewModel( viewModelStoreOwner=(contextasFragment).requireParentFragment() ) ){/* ... */}
Getting an Activity-scoped ViewModel from a Fragment is a common use case. When
doing so, use the activityViewModels()
Views extension function is available. If you're not using Views and Kotlin,
you can use the same APIs as above and by passing the right owner.
Views
importandroidx.fragment.app.activityViewModels classMyFragment:Fragment(){ // ViewModel API available in fragment.fragment-ktx // The ViewModel is scoped to the host Activity valviewModel:SharedViewModelbyactivityViewModels() }
Views
importandroidx.lifecycle.ViewModelProvider; publicclass MyFragmentextendsFragment{ SharedViewModelviewModel; @Override publicvoidonViewCreated(Viewview,BundlesavedInstanceState){ // The ViewModel is scoped to the host Activity viewModel=newViewModelProvider(requireActivity()) .get(SharedViewModel.class); } }
Compose
importandroidx.lifecycle.viewmodel.compose.viewModel @Composable funMyScreen( context:Context=LocalContext.current, // ViewModel API available in lifecycle.lifecycle-viewmodel-compose // The ViewModel is scoped to the Activity of the host Fragment // where this composable function is called viewModel:SharedViewModel=viewModel( viewModelStoreOwner=(contextasFragment).requireActivity() ) ){/* ... */}
ViewModels scoped to the Navigation graph
Navigation graphs are also ViewModel store owners. If you're using
Navigation Fragment or
Navigation Compose, you can get an instance of a
ViewModel scoped to a Navigation graph with the
navGraphViewModels(graphId)
Views extension function.
Views
importandroidx.navigation.navGraphViewModels classMyFragment:Fragment(){ // ViewModel API available in navigation.navigation-fragment // The ViewModel is scoped to the `nav_graph` Navigation graph valviewModel:SharedViewModelbynavGraphViewModels(R.id.nav_graph) // Equivalent navGraphViewModels code using the viewModels API valviewModel:SharedViewModelbyviewModels( {findNavController().getBackStackEntry(R.id.nav_graph)} ) }
Views
importandroidx.lifecycle.ViewModelProvider; publicclass MyFragmentextendsFragment{ SharedViewModelviewModel; @Override publicvoidonViewCreated(Viewview,BundlesavedInstanceState){ NavControllernavController=NavHostFragment.findNavController(this); NavBackStackEntrybackStackEntry=navController.getBackStackEntry(R.id.my_graph); // The ViewModel is scoped to the `nav_graph` Navigation graph viewModel=newViewModelProvider(backStackEntry).get(SharedViewModel.class); } }
Compose
importandroidx.lifecycle.viewmodel.compose.viewModel @Composable funMyAppNavHost(){ // ... composable("myScreen"){backStackEntry-> // Retrieve the NavBackStackEntry of "parentNavigationRoute" valparentEntry=remember(backStackEntry){ navController.getBackStackEntry("parentNavigationRoute") } // Get the ViewModel scoped to the `parentNavigationRoute` Nav graph valparentViewModel:SharedViewModel=viewModel(parentEntry) // ... } }
If you're using Hilt in addition to Jetpack Navigation, you can use the
hiltNavGraphViewModels(graphId)
API as follows.
Views
importandroidx.hilt.navigation.fragment.hiltNavGraphViewModels classMyFragment:Fragment(){ // ViewModel API available in hilt.hilt-navigation-fragment // The ViewModel is scoped to the `nav_graph` Navigation graph // and is provided using the Hilt-generated ViewModel factory valviewModel:SharedViewModelbyhiltNavGraphViewModels(R.id.nav_graph) }
Views
importandroidx.hilt.navigation.HiltViewModelFactory; importandroidx.lifecycle.ViewModelProvider; publicclass MyFragmentextendsFragment{ SharedViewModelviewModel; @Override publicvoidonViewCreated(Viewview,BundlesavedInstanceState){ NavControllernavController=NavHostFragment.findNavController(this); NavBackStackEntrybackStackEntry=navController.getBackStackEntry(R.id.my_graph); // The ViewModel is scoped to the `nav_graph` Navigation graph // and is provided using the Hilt-generated ViewModel factory viewModel=newViewModelProvider( backStackEntry, HiltViewModelFactory.create(getContext(),backStackEntry) ).get(SharedViewModel.class); } }
Compose
importandroidx.hilt.navigation.compose.hiltViewModel @Composable funMyAppNavHost(){ // ... composable("myScreen"){backStackEntry-> valparentEntry=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 valparentViewModel:SharedViewModel=hiltViewModel(parentEntry) // ... } }
Recommended for you
- Note: link text is displayed when JavaScript is off
- Layouts and binding expressions
- ViewModel overview