Basically, in order to retrieve a ViewModel
in Activity
one should call ViewModelProviders.of(this).get(SomeViewModel.class)
. Now, if we look into of
it looks like below:
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);
}
So, the important part is this method - activity.getViewModelStore()
because it returns a wrapper object (HashMap
holder) for all of your ViewModel
objects and if it can survive config changes so can all of your ViewModel
objects:
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
mViewModelStore
will be either restored from NonConfigurationInstances
or created from scratch. Pretty much, NonConfigurationInstances
is the object that survives config changes and hence is used to store the ViewModelStore
. That's why the same ViewModelStore
object is returned after rotation - it's stored in the config change independent NonConfigurationInstances
:
If you look into onRetainNonConfigurationInstance()
, you will actually that your ViewModelStore
is saved there:
public final Object onRetainNonConfigurationInstance() {
...
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
Also, it will be cleared only if onDestroy
for a non-config change reason is called:
...
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
...
A similar trick is used for storing a ViewModel
for a Fragment
.