Deep dive inside of Android’s ViewModel (Architecture Components)

Ryhan Hasan
AndroidPub
Published in
4 min readAug 4, 2017

--

Google I/O 17 announced some very exciting architecture components all android developers can use. These components help tackle common problems that continue to recur during the Android development process. One common problem in particular includes how data is retained between configuration changes (Activity recreation) while achieving no memory leaks during the process. Google now has a solution for us, the ViewModel. This article dissects the source code of how the ViewModel actually addresses this problem.

What is the ViewModel?

The official documentation describes it as the following:

The ViewModel class is designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations.

Essentially, classes extending ViewModel are expected to contain data elements related to the UI. The reason it is “expected” is because there is nothing enforcing it at the class level:

public abstract class ViewModel {
/**
* This method will be called when this ViewModel is no longer used and will be destroyed.
* <p>
* It is useful when ViewModel observes some data and you need to clear this subscription to
* prevent a leak of this ViewModel.
*/
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
}

So you could extend the class and have data elements unrelated to the UI, but you would just be losing all the great benefits of the ViewModel ;). But assuming we’ve followed the guidelines like the great developers we are, onCleared() method is provided for us to override in case we might have clean up code inside of our ViewModel like unsubscribing from potential subscriptions.

Even though the ViewModel is expected to manage the UI-related data, how the ViewModel survives configuration changes is a different story. Some examples of configuration changes are device language changes, keyboard availability, and one of the most popular being screen rotations. During a configuration change, the activity present on the device will be recreated in case the activity may have code accounting for the device configuration change.

How does a ViewModel survive configuration changes?

Before digging into the source code, first we observe how a ViewModel is obtained. We take a simple LoginActivity with a LoginViewModel as an example:

LoginViewModel model = ViewModelProviders.of(this).get(LoginViewModel.class);

We see the class ViewModelProviders creates a new ViewModelProvider for us:

@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
initializeFactoryIfNeeded(activity.getApplication());
return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}

A ViewModelProvider contains a ViewModelStore and Factory.

private final Factory mFactory;
private final ViewModelStore mViewModelStore;

Factory is an interface which classes implement to describe how to create the ViewModel. The DefaultFactory class passed in the constructor not only accounts for classes extending the regular ViewModel, but also an AndroidViewModel.

@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch { //RuntimeExceptions if we couldn't create }
}
return super.create(modelClass);
}

AndroidViewModels have a reference to the application context, whereas, regular ViewModels do not.

The ViewModelStore simply abstracts a mapping between Strings and ViewModels and acts as the storage mechanism for our ViewModels.

So…how does the implementation retain state?

The secret is exposed within the ViewModelStores.of(activity).

@MainThread
public static ViewModelStore of(FragmentActivity activity) {
return holderFragmentFor(activity).getViewModelStore();
}

A HolderFragment is added behind the scenes for the activity if it hasn’t been previously added already. The activity’s HolderFragment is retrieved to get the associated ViewModelStore corresponding to the Activity. Now we know that a HolderFragment has a ViewModelStore, and ViewModelStores store our configuration surviving ViewModels. The HolderFragment is how the ViewModels retain their instance.

public HolderFragment() {
setRetainInstance(true);
}

setRetainInstance(true) is the method behind how the HolderFragment and all the ViewModels inside the ViewModelStore the fragment contains, retains its instance between configuration changes. Long term android developers are most likely very familiar with this method and how it functions. The docs define the method as follows:

void setRetainInstance (boolean retain)

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

Putting it all together, here is a simple diagram expressing the relationship:

Regardless of the number of LoginActivity instances created, a HolderFragment is added behind the scenes with its setRetainInstance turned on, allowing its ViewModelStore property, and in turn, all the ViewModels in the store to retain its instance.

That is it! Thanks for reading. Feel free to comment, provide feedback or corrections below :)

Follow my twitch! https://twitch.tv/a_buff_nerd

--

--