To demonstrate that how we can use ViewModel in Activity scope, we will use this SampleProject3 from this GitHub repository. The project idea/requirement is simple and that is to show a random number in a text view, and there will be a button, if user clicks on the button, then the random number will be changed or reinitialized. Initially there will be no random number. And we are going to see that how the random number survives activity configuration changes by using ViewModel.
Assume you already know that Android Activity doesn't survive configuration changes from this blog post, and we handled the scenario by using Android onSaveInstanceState method in this post. You may have fun by handling the scenario using onSaveInstanceState but using onSaveInstanceState method is little bit outdated and need more code. That's why we should use Android ViewModel.
Also, ViewModel has other many facilities, like it will help to remove business logic from Activity or UI class, but we are not going to describe what facilities does Android ViewModel provided. Instead, we will directly dive into How can we use Android ViewModel in our Activity class so that we can handle the configuration change scenario.
We can define Android Viewmodel in such a way that it will be attached to an Activity, in that case even if the activity gets reinitialized after being restored due to a configuration change, the ViewModel object will still be the same as previous. And the ViewModel will be completely destroyed when the activity will be destroyed completely (meaning no restoration).
First of all, we have to add below dependency to access ViewModel class from our Activity class. You should add the dependency in module level build.gradle file.
implementation 'androidx.activity:activity-ktx:1.4.0'And we have declared our view model class like below
class MainActivityViewModel: ViewModel() {
var actualNumber: Int? = null
private set
fun generateNewNumber() {
actualNumber = Random().nextInt(1000)
}
}we made the actualNumber public so that it can be accessed from the Activity, however we make the setter private so that the Activity won't be able to update the variable, instead we exposed a method to update the actualNumber variable. so, whenever user clicks on the button, we have to invoke this generateNewNumber method.
And this is how we have initialized our ViewModel object.
class MainActivity : AppCompatActivity() {
private val viewModel: MainActivityViewModel by viewModels()
// other code
}Remember to import the correct package for initializing viewmodel. Cause If you want to initialize your viewModels with Activity scope then you must have to import-
import androidx.activity.viewModelsAlso to display the latest number we declared a method in a null safe way, so that when the activity first launched or restored, in both cases we can directly call the method to display the number.
private fun displayTheNumber() {
viewModel.actualNumber?.let {
numberTextView.text = it.toString()
}
}You can check the code that this function gets invoked from the activity onCreate() and from the button click listener. When the activity will be first launched then calling this method won't have any effect, cause in that time our ViewModel will also be created newly, so the actualNumber variable will contains null.
Also, we call generateNewNumber() of the viewmodel from the button click listener. cause when the button will be clicked then we have to change the number (that is our core requirement).
private fun handleNextButtonClicked() {
viewModel.generateNewNumber()
displayTheNumber()
}So, all setups done, you can test the app now and you will find that it survives the configuration change scenario since we have used ViewModel.