If you are reading this article, then you must have some idea about ViewModels. ViewModels are the latest building blocks of an android app.

According to the official documentation:

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations. Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance.

FYI: You can use ViewModel to preserve UI state only during a configuration change, nothing else as explained perfectly in this official doc. This image summarizes this doc perfectly.

After reading all this I assumed that, OK, then this is how ViewModel works and preserve data during configuration change :

ViewModel is a separate class which has an instance of it in the activity and has no reference for view in it. So even though activity onDestroy() and onCreate() happens on configuration change, the instance of ViewModel doesn’t get destroyed or garbage collected.

So it kind of makes sense that ViewModel data persists on screen configuration change.

Then one day I had a Newton and apple moment with me. when I reviewed my assumptions, I found out that there is a huge flaw in my assumption.

Let me explain:

When activity screen configuration changes, then onCreate() is called again. But we initialize viewModel in onCreate() of activity. Like this:

model = ViewModelProviders.of(this)[SharedViewModel::class.java]

So technically there should be a new instance of ViewModel every time there is a screen orientation change. That means the data stored in the ViewModel before orientation change is lost forever.

2. According to official documentation, If ViewModel can retain data during a screen configuration change, then why can’t it survive when activity is restored after low memory scenarios. I mean what’s the difference. onDestroy() and onCreate() methods are called both the time.

Then I did some research about what’s the reason behind it and went through the ViewModel code. This article is about my findings.

If you check the internal code of ViewModelProviders then the of method has below implementation code :

@NonNull

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity,@Nullable Factory factory) {

Application application = checkApplication(activity);

if (factory == null) {

factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);

}

return new ViewModelProvider(activity.getViewModelStore(), factory);

}

it creates a new Instance of ViewModelProvider every time you call the of method.

Ok, then how Activity maintains the same ViewModel on screen configuration change?

let’s debug further.

When a new instance of ViewModelProvider is created, the first parameter is activity.getViewModelStore()

What!!. Activity has a ViewModelStore ? The Answer is Yes. According to the documentation of getViewModelStore() ,

Returns the {@link ViewModelStore} associated with this activity

<p>

Overriding this method is no longer supported and this method will be made

<code>final</code> in a future version of ComponentActivity.

@return a {@code ViewModelStore}

@throws IllegalStateException if called before the Activity is attached to the Application

instance i.e., before onCreate()

it returns a ViewModelStore object. So what is a ViewModelStore ?

/**

* Class to store {@code ViewModels}.

* <p>

* An instance of {@code ViewModelStore} must be retained through configuration changes:

* if an owner of this {@code ViewModelStore} is destroyed and recreated due to configuration

* changes, new instance of an owner should still have the same old instance of

* {@code ViewModelStore}.

* <p>

* If an owner of this {@code ViewModelStore} is destroyed and is not going to be recreated,

* then it should call {@link #clear()} on this {@code ViewModelStore}, so {@code ViewModels} would

* be notified that they are no longer used.

* <p>

* Use {@link ViewModelStoreOwner#getViewModelStore()} to retrieve a {@code ViewModelStore} for

* activities and fragments.

*/

public class ViewModelStore {



private final HashMap<String, ViewModel> mMap = new HashMap<>();



final void put(String key, ViewModel viewModel) {

ViewModel oldViewModel = mMap.put(key, viewModel);

if (oldViewModel != null) {

oldViewModel.onCleared();

}

}



final ViewModel get(String key) {

return mMap.get(key);

}



Set<String> keys() {

return new HashSet<>(mMap.keySet());

}



/**

* Clears internal storage and notifies ViewModels that they are no longer used.

*/

public final void clear() {

for (ViewModel vm : mMap.values()) {

vm.clear();

}

mMap.clear();

}

}

Basically, it’s a class which has a HashMap whose key is DEFAULT_KEY + “:” + canonicalName where DEFAULT_KEY is androidx.lifecycle.ViewModelProvider.DefaultKey and value is the ViewModel

That means every activity and fragment has a ViewModelStore which keeps all the declared ViewModel s in the activity or fragment respectively.

But How ViewModelStore survives orientation change?

In the documentation of ViewModelStore it’s defined that

if an owner of this {@code ViewModelStore} is destroyed and recreated due to configuration

* changes, new instance of an owner should still have the same old instance of

* {@code ViewModelStore}.

So it’s activities responsibility to retain the ViewModelStore during orientation change.

If we go back to activity.getViewModelStore() implementation, then we’ll find the answer.

if (mViewModelStore == null) {

NonConfigurationInstances nc =

(NonConfigurationInstances) getLastNonConfigurationInstance();

if (nc != null) {

// Restore the ViewModelStore from NonConfigurationInstances

mViewModelStore = nc.viewModelStore;

}

if (mViewModelStore == null) {

mViewModelStore = new ViewModelStore();

}

}

The activity does so by using something called NonConfigurationInstances . NonConfigurationInstances is a static final class

static final class NonConfigurationInstances {

Object custom;

ViewModelStore viewModelStore;

}

So it first checks whether there is already an viewmodelstore stored in NonConfigurationInstances if not it creates a new ViewModelStore or returns the existing ViewModelStore .

Then why doesn’t ViewModel survive low memory or finish() scenarios?

ViewModelStore has a clear() method :

/**

* Clears internal storage and notifies ViewModels that they are no longer used.

*/

public final void clear() {

for (ViewModel vm : mMap.values()) {

vm.onCleared();

}

mMap.clear();

}

So this clear() method gets called in onDestroy() of activity or fragment which clears the HashMap except during configuration changes. Here is the code :

if (mViewModelStore != null && !isChangingConfigurations) {

mViewModelStore.clear();

}

Now you know the secret recipe of how ViewModel survives configuration change.

Happy coding…