I have a container Fragment, call it ContainerFragment
holding two fragments, FragmentA
and FragmentB
. Both, FragmentA
and FragmentB
create a ViewModel
in the onCreate()
method using the ViewModelProviders.of(this)
approach.
Let's assume that container can only show one fragment at a time and I'm using the FragmentTransaction.replace()
method to switch between FragmentA
and FragmentB
. In my case, I show FragmentA
, which creates the FragmentA
ViewModel and then an action triggers FragmentB
to replace FragmentA
. Now, when I'm done with FragmentB
, I call replace again to show FragmentA
. Here is the check I do in that method that replaces the fragments:
if (fragmentA == null) {
fragmentA = FragmentA.newInstance();
}
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.container_content, fragmentA, "my-tag");
ft.commit();
Since the FragmentA
was created the first time it ran, it doesn't go into the if block. But what I noticed that the onCreate()
of FragmentA
returns a different instance of the ViewModel. I have the following code in FragmentA
:
public void onCreate(Bundle sI) {
super.onCreate(sI);
mViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
Log.i("test", "ViewModel-> " + mViewModel.toString());
}
The log prints:
ViewModel-> com.myapp.MyViewModel@ed93f63
the first time I create FragmentA
and then
ViewModel-> com.myapp.MyViewModel@ff3eee4
after I call ft.replace()
.
So, I'm confused as to why would ViewModelProviders
return a different instance of the ViewModel
the second time around even though FragmentA
is not null (since it doesn't enter the if block, I assume it is not null)?
According to the doc:
A ViewModel is always created in association with a scope (an fragment or an activity) and will be retained as long as the scope is alive. E.g. if it is an Activity, until it is finished.
The scope of ViewModel
is bound to the scope of input Fragment / Activity.
FragmentManager
)In other words, the FragmentA
is destroyed when you replace it with FragmentB
, so its associated ViewModel
instance is removed.
When you call ViewModelProviders.of(fragment)
to get a ViewModel
, at the end it hands off this task to ViewModelStore
, which stores our ViewModel
instances.
And let us deep dive into the source code of androidx.fragment.app.Fragment-1.0.0
@CallSuper
public void onDestroy() {
mCalled = true;
FragmentActivity activity = getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (mViewModelStore != null && !isChangingConfigurations) {
mViewModelStore.clear();
}
}
Therefore the ViewModel
instance is removed because of this call mViewModelStore.clear();