Internals of Android Architecture Components Part I — The ViewModel

On this post series I’ll try to shed light on how Android Architecture Components (AAC) work in order to better leverage them, starting on the ViewModel.

You can see the other posts here:

  1. The ViewModel
  2. LiveData

Why should we understand how AAC works?

First of all, let’s cover the motivation for this series. I consider best practice to decouple the logic of your application from the platform it runs upon (see Ports and Adapters), that involves decoupling it from any API it may consume, the storage solutions (SQLite, Realm, SharedPreferences, the file system,…), and more importantly, the Android runtime.

Some of the reasons to it is that:

  1. Platform dependencies will hamper the testability of your solution, making it either harder to unit test, slower, or impossible.
  2. The platform dependencies will evolve over time, outside of your control. A change on these dependencies, should not imply a change on your business logic. This is driven by the Single Responsibility Principle (a class should have a single reason to change), and the Stable Dependencies Principle (a package should depend on packages less likely to change than itself).

With AAC, Google is offering a set of libraries that drive Architectural decisions that target the business logic of your app, but at the same time, coupling it onto the Android SDK.

What are the AAC ViewModels?

On Android’s documentation page it states that ViewModels can be used to keep …

“Store UI-related data that isn’t destroyed on app rotations.”

But how does it manage to do so? Let’s reveal the magic tricks.

How AAC ViewModels are retained across configuration changes

First, let’s visit the Android documentation to see how the ViewModel is consumed. The following code is the example of how a Fragment uses the SDK in order to provide a ViewModel that is retained on configuration changes:

The line we want to focus on right now is:

ViewModelProviders.of(this).get(MyViewModel.class);

we can infer that it’s retrieving a ViewModel of type MyViewModel. Let’s look into how each of these methods work, starting with ViewModelProviders.of:

It looks like ViewModelProviders.of is just a factory of ViewModelProvider, who depends upon a ViewModelStore and a ViewModelFactory. We’ll have to dig deeper to fully understand how ViewModels work.

The ViewModelStore

If we look into the dependencies, the ViewModelStore seems to be a simple store with a HashMap<String, ViewModel>, where the key is the classname of the view model and the Object the ViewModel itself:

ViewModelFactory

On the other hand, the ViewModelFactory is using reflection to instantiate the ViewModel we need. The AndroidViewModelFactory used in ViewModelProviders.of overrides a generic ViewModelFactory in order to provide a reference to the Application Context to the ViewModel:

If the ViewModel class is of type AndroidViewModel, then it will create a new instance passing the application as a single parameter in the constructor, otherwise, it calls the parent implementation, which is:

This is a simple factory implemented via reflection that provides no arguments to the ViewModel object.

How it all ties together

Now that we understand the ViewModelProvider creation and its dependencies, we will look into how it creates and retrieves theViewModel instances, retaining them throughout configuration changes. Let’s look into the get(MyViewModel.class) method call.

This works as one would expect, it tries to retrieve a ViewModel from the store, if none is there, it uses the factory to create it and stores it. In order to retrieve the already created ViewModel, it generates a key from the class qualified name.

Surviving configuration changes

So far we’ve seen how the ViewModelStore is the object responsible to keep the references of ViewModel to be reused, but how is the ViewModelStore surviving configuration changes itself? Let’s go back to the implementation of ViewModelProviders.of:

ViewModelStores.of seems to be a similar method to ViewModelProviders.of, creating new instances of the ViewModelStore as required. Let’s look into how this is implemented:

Apparently, we can provide the ViewModelStore in three ways:

  • Using the android.support.v4.app.Fragment which implements ViewModelStoreOwner.
  • Implementing ViewModelStoreOwner in our Fragment, and owning the responsibility of creating and disposing the store.
  • Let AAC create a HolderFragment, who already implements ViewModelStoreOwner, and the AAC library and Android SDK will do the heavy lifting.

How HolderFragment retains the state

This raises the question of what is a HolderFragment and how it maps to our Fragment stack. Let’s look now at how holderFragmentFor(Fragment) works:

The HolderFragment has a couple of ways of looking for the HolderFragment associated with your Fragment, and if not found, it will create new HolderFragment and add it on the FragmentManager of our own Fragment. Now, how does this fragment in our stack survive rotation changes while the rest of the fragments die in their regular lifecycle? The answer is in the constructor:

By setting retain instance to true and not providing a view, the HolderFragment becomes essentially a headless Fragment that is retained for as long as the Activity is not destroyed.

How android.support.v4.app.Fragment retains state

On the other hand, if you opt for using the support Fragment, the state will be retained, however it becomes more complex to follow the code that manages it.

In order to understand the flow of control of this classes, we looked at the onDestroy method of the Fragment:

The condition to call clear on the ViewModelStore is that mHost.mFragmentManager.mStateSaved is false.

By adding a breakpoint on the mStateSaved instance variable we managed to identify when it is set to true, and by whom:

Isn’t Android’s code “beautiful”?

By navigating the resulting stack trace, we end up on discovering that the FragmentManager.saveAllState method is called by FragmentActivity.onSaveInstanceState.

Summary

To summarise, the reasons it is able to create and retain the ViewModel are:

  1. A ViewModelProvider creates with Reflection the ViewModel with a ViewModelFactory.
  2. A ViewModelProvider retains the ViewModel across configuration changes with a ViewModelStore, provided by a ViewModelStoreOwner, this can be done with a HolderFragment, leveraging android.support.v4.app.Fragment or implementing our own.
  3. An android.support.v4.app.Fragment will use the FragmentManager.saveAllState as called by FragmentActivity.onSaveInstanceState to retain the ViewModelStore using theflag mStateSaved on onDestroy.
  4. A HolderFragment is a headless Fragment (without UI) that is added to the Fragment stack with setRetainInstance(true).

References

Other sources that go into more depth onto how AAC works in depth are: