How do View Models know how to survive configuration changes?
If you close an Android app, you will destroy its Activities and ViewModels. If you rotate your device, your Activity will be destroyed and recreated, yet, your ViewModel survives. But in both cases, your Activity was destroyed, so how does your app know when to keep or when to destroy a ViewModel? That’s what we will find out below!
Basic usage
Consider a simple app with one MainActivity
that references a MainViewModel
. As usual, we extend MainActivity
from AppCompatActivity
, which gives us access to a handy delegated property to access our view model: viewModels()
.
The viewModels()
delegate above does the job of a typical lazy property, it makes sure that MainViewModel
is initialized only upon the first time you reference it and remembers the result for upcoming usages.
In a way, this describes the behavior we want from a viewModel. For as long as the Activity lives, we would not like to reinitialize the viewModel. For example, let’s say we open MainActivity
for the first time, then press the home button in our Android device, then click again to open MainActivity
.
MainActivity
will be created, will enter the started and then resumed states. After pressing the home button, MainActivity
will be put in the created state but will still be in memory, meaning that the next time we use MainViewModel
, we will get the same original reference, and thus any state that existed before leaving the Activity.
What if we kill the entire app?
Our lazy initialization of MainViewModel
makes sure we always get the same viewModel reference for as long as MainActivity
is in memory. But what if we manually close the app, thus removing MainActivity
from memory?
When we manually close the app, MainActivity
is destroyed and the Activity is removed from memory. As expected, MainViewModel
is also removed from memory and will be reinitialized when we reopen the app.
This then begs the question: When we have a configuration change (i.e. rotate the device), MainActivity
is also destroyed (before being recreated) and the Activity is removed from memory, but as we know, viewModels survive configuration changes. How do they do that?
The ViewModelStore class
To answer this we need to dive into how the viewModels()
lazy property works. Notice that viewModels()
is an extension function from ComponentActivity
, which is accessible from MainActivity
following the hierarchy below:
Now take a look at the extension function itself. For simplicity, we will abstract some details about its implementation.
But the important part for our discussion is that the function returns a lazy delegate to provide access to the viewModel itself. This delegate is exactly how we access the viewModel from MainActivity
, and it receives a viewModelStore
parameter, which is accessible from the extension function since it is a property of ComponentActivity
.
Now, viewModelStore
does what its name suggests: It stores and manages the viewModels for its owner, which in this case is the MainActivity
itself. In a nutshell,
ViewModelStore maintains a HashMap of ids to ViewModels for its owner, which is a subclass of
ComponentActivity
. Instances of ViewModelStore are retained through configuration changes and clear its ViewModels if its owner is destroyed and is not going to be recreated.
The ComponentActivity class
Great, we have a viewModelStore
to manage the viewModels for our MainActivity
. But the managing code itself is part of the parent ComponentActivity
class.
From the excerpt above, you can see that ComponentActivity
‘s constructor adds a lifecycle event listener that executes a callback when the Activity is destroyed. The getViewModelStore.clear()
call, which basically clears the HashMap maintained by the viewModelStore
only occurs if the onDestroy
was called not due to configuration changes.
And this wraps it up, since if the Activity is destroyed due to configuration changes, line 14
above won’t execute, viewModelStore
won’t be cleared and thus the viewModel will retain its state.
Thanks for reading! If you like the content don’t forget to clap and follow for more!