ViewModel overview (Views)

Concepts and Jetpack Compose implementation

The ViewModel class is a business logic or screen level state holder. It exposes state to the UI and encapsulates related business logic. Its principal advantage is that it caches state and persists it through configuration changes. This means that your UI doesn't have to fetch data again when navigating between activities, or following configuration changes, such as when rotating the screen.

ViewModel benefits

The alternative to a ViewModel is a plain class that holds the data you display in your UI. This can become a problem when navigating between activities or Navigation destinations. Doing so destroys that data if you don't store it using the saved instance state mechanism. ViewModel provides a convenient API for data persistence that resolves this issue.

The key benefits of the ViewModel class are essentially two:

  • It lets you persist UI state.
  • It provides access to business logic.

Scope

When you instantiate a ViewModel, you pass it an object that implements the ViewModelStoreOwner interface. This may be a Navigation destination, Navigation graph, activity, fragment, or any other type that implements the interface. Your ViewModel is then scoped to the Lifecycle of the ViewModelStoreOwner. It remains in memory until its ViewModelStoreOwner goes away permanently.

A range of classes are either direct or indirect subclasses of the ViewModelStoreOwner interface. The direct subclasses are ComponentActivity, Fragment, and NavBackStackEntry. For a full list of indirect subclasses, see the ViewModelStoreOwner reference.

Implement a ViewModel

The following is an example implementation of a ViewModel for a screen that allows the user to roll dice.

Kotlin

dataclassDiceUiState(
valfirstDieValue:Int?=null,
valsecondDieValue:Int?=null,
valnumberOfRolls:Int=0,
)
classDiceRollViewModel:ViewModel(){
// Expose screen UI state
privateval_uiState=MutableStateFlow(DiceUiState())
valuiState:StateFlow<DiceUiState>=_uiState.asStateFlow()
// Handle business logic
funrollDice(){
_uiState.update{currentState->
currentState.copy(
firstDieValue=Random.nextInt(from=1,until=7),
secondDieValue=Random.nextInt(from=1,until=7),
numberOfRolls=currentState.numberOfRolls+1,
)
}
}
}

Java

publicclass DiceUiState{
privatefinalIntegerfirstDieValue;
privatefinalIntegersecondDieValue;
privatefinalintnumberOfRolls;
// ...
}
publicclass DiceRollViewModelextendsViewModel{
privatefinalMutableLiveData<DiceUiState>uiState=
newMutableLiveData(newDiceUiState(null,null,0));
publicLiveData<DiceUiState>getUiState(){
returnuiState;
}
publicvoidrollDice(){
Randomrandom=newRandom();
uiState.setValue(
newDiceUiState(
random.nextInt(7)+1,
random.nextInt(7)+1,
uiState.getValue().getNumberOfRolls()+1
)
);
}
}

You can then access the ViewModel from an activity as follows:

Kotlin

importandroidx.activity.viewModels
classDiceRollActivity:AppCompatActivity(){
overridefunonCreate(savedInstanceState:Bundle?){
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same DiceRollViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
valviewModel:DiceRollViewModelbyviewModels()
lifecycleScope.launch{
repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.uiState.collect{
// Update UI elements
}
}
}
}
}

Java

publicclass MyActivityextendsAppCompatActivity{
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
DiceRollViewModelmodel=newViewModelProvider(this).get(DiceRollViewModel.class);
model.getUiState().observe(this,uiState->{
// update UI
});
}
}

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 2026年05月28日 UTC.