How do View Models know how to survive configuration changes?

Joao Foltran
CodeX
Published in
4 min readAug 2, 2022

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!

Photo by cottonbro

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.

image by author

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:

image by author

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!

--

--