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)
// ...
}
}

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2025年02月10日 UTC.