Surviving Configuration Change - ViewModel

Android Applications

Android apps are Java programs that run on a special runtime - ART, itself running on top of a linux kernel. As such, they run in a process, have an entry point (main method), threads, resources, native code calls via JNI etc. I enjoy digging around to find out how 'things' are implemented and invoked. In this article, I trace how the ViewModel is created and survives configuration change.

ViewModel

It is an architectural component that prepares and manages data for the view e.g. a fragment. We can thus use it to invoke business logic calls such as updating user profile or calculating the distance to Jupiter.

viewmodel_diagrams.001.png

As we already know, the current activity instance only gets a reference to a view model but doesn't actually instantiate it. So where does it come from? Enter the ViewModelProvider class.

ViewModelProvider

This class creates a view model for a particular activity and maintains it as long as the activity is alive. We can create an instance of this class with the following call:

val provider = ViewModelProvider(this)

And then subsequently ask for a view model using:

val viewModel = provider.get(ViewModel::class.java)

Everything is set and we can happily use our view model instance resting assured if we repeat the above call we'll get the same instance as long as our view e.g. activity is not finished.

viewmodel_diagrams.002.png

The API discussed thus far is sufficient for you to use ViewModels in your application.

What follows are implementation details -- which of course can change anytime.

Exposé

If an activity owns the ViewModelProvider, and the ViewModelProvider creates and maintains a view model for us, that instance should be garbage collected if the activity were to be killed from a configuration change, such as a rotation. So how come the view model survives this process? There must be more. There's something that's surviving the configuration change of the activity. The application class? 🤔Could be. Let's check again where the ViewModelProvider stores the view model instance it makes.

ViewModelStore

The ViewModelStore is the actual storage of the view models. Internally, it uses a table where these instances are stored in referenced through a key. We had the impression that the ViewModelProvider creates and stores the view models. The creation part is correct, but it uses the ViewModelStore for storage and keeps a reference to the store. Subsequent retrievals are delegated to this store reference.

viewmodel_diagrams.003.png

But still, if the activity is torn down from a configuration change, we'll lose the provider, store and view model references. Nevertheless, the framework ensures that the view model, through the store instance, survives configuration changes.

Back to this:

val provider = ViewModelProvider(this)

Carefully analyzing the this parameter, we find that its type is a ViewModelStoreOwner. And this is our activity instance, thus an activity is a store owner! It implements the store owner SAM interface to provide a store. It's the responsibility of the store owner to retain the store during configuration changes.

viewmodel_diagrams.004.png

Navigating up the activity hierarchy, we reach the ComponentActivity which is the implementation of the ViewModelStoreOwner.

ComponentActivity

This class encloses a static final class NonConfigurationInstances. This class has 2 fields:

  • Object -- custom non-config storage
  • ViewModelStore -- our store

ComponentActivity returns an instance of this class when the system calls onRetainNonConfigurationInstance -- called when an activity configuration change happens (see retainNonConfigurationInstances method for extra info). It's usage is disapproved, I presume to allow the framework developers to use it for features such as what we're discussing here.

viewmodel_diagrams.005.png

When the new instance of the activity is later created with the requested configuration, the system gives us the object saved through getLastNonConfigurationInstance. As you remember, the ComponentAcivity had passed an instance of NonConfigurationInstances class that had a reference of our view model store. We can therefore, in onCreate, retrieve the view model we had previously created.

NB: It is important to note that the ViewModelStoreOwner represents a scope that maintains a store with ViewModels in it. Once this scope is destroyed, for example when the Activity is finished, the store and the view models contained therein are destroyed as well. onCleared is called in the view model to help you do clean up before the view model is gone.

Class Diagram

I went out on a limb to create a high level class diagram for the explanation above (I omitted fields and methods non-essential to our discussion)

viewmodel.png

Conclusion

This architectural component by the folks at Android is a welcomed addition to apps development. It fits well in the MVVM presentation pattern and can make application architecture a breeze.

We didn't cover how the view model factory fits into all this dance but that shouldn't be hard to trace.

Hopefully this sheds some light on how the view model is created, stored and survives configuration changes. Happy coding!

References

No Comments Yet