Android 在调用 ft.replace 时为同一片段返回不同的 ViewModel 实例
Android returning different instance of ViewModel for the same fragment when calling ft.replace
我有一个容器 Fragment,称它为 ContainerFragment
,其中包含两个片段,FragmentA
和 FragmentB
。 FragmentA
和 FragmentB
都使用 ViewModelProviders.of(this)
方法在 onCreate()
方法中创建了一个 ViewModel
。
假设容器一次只能显示一个片段,我使用 FragmentTransaction.replace()
方法在 FragmentA
和 FragmentB
之间切换。在我的例子中,我显示了 FragmentA
,它创建了 FragmentA
ViewModel,然后一个动作触发 FragmentB
来替换 FragmentA
。现在,当我完成 FragmentB
后,我再次调用 replace 以显示 FragmentA
。这是我在替换片段的方法中所做的检查:
if (fragmentA == null) {
fragmentA = FragmentA.newInstance();
}
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.container_content, fragmentA, "my-tag");
ft.commit();
由于 FragmentA
是第一次创建它 运行,所以它不会进入 if 块。但是我注意到 FragmentA
return 的 onCreate()
是 ViewModel 的不同实例。我在 FragmentA
中有以下代码:
public void onCreate(Bundle sI) {
super.onCreate(sI);
mViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
Log.i("test", "ViewModel-> " + mViewModel.toString());
}
日志打印:
ViewModel-> com.myapp.MyViewModel@ed93f63
我第一次创建 FragmentA
然后
ViewModel-> com.myapp.MyViewModel@ff3eee4
我打电话后 ft.replace()
.
所以,我很困惑为什么 ViewModelProviders
return 第二次 ViewModel
的不同实例,即使 FragmentA
不为空(因为它没有进入 if 块,我假设它不为空)?
根据 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.
ViewModel
的范围与输入Fragment/Activity的范围绑定。
- Activity:当它销毁且不是由配置更改引起时
- 片段:销毁且不是由配置更改引起的(即从
FragmentManager
中删除)
换句话说,当您将 FragmentA
替换为 FragmentB
时,FragmentA
将被销毁,因此其关联的 ViewModel
实例将被删除。
当您调用 ViewModelProviders.of(fragment)
获取 ViewModel
时,它最终将此任务交给 ViewModelStore
,它存储了我们的 ViewModel
个实例。
让我们深入探讨 androidx.fragment.app.Fragment-1.0.0
的 source code
@CallSuper
public void onDestroy() {
mCalled = true;
FragmentActivity activity = getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (mViewModelStore != null && !isChangingConfigurations) {
mViewModelStore.clear();
}
}
因此 ViewModel
实例因为这个调用被移除 mViewModelStore.clear();
我有一个容器 Fragment,称它为 ContainerFragment
,其中包含两个片段,FragmentA
和 FragmentB
。 FragmentA
和 FragmentB
都使用 ViewModelProviders.of(this)
方法在 onCreate()
方法中创建了一个 ViewModel
。
假设容器一次只能显示一个片段,我使用 FragmentTransaction.replace()
方法在 FragmentA
和 FragmentB
之间切换。在我的例子中,我显示了 FragmentA
,它创建了 FragmentA
ViewModel,然后一个动作触发 FragmentB
来替换 FragmentA
。现在,当我完成 FragmentB
后,我再次调用 replace 以显示 FragmentA
。这是我在替换片段的方法中所做的检查:
if (fragmentA == null) {
fragmentA = FragmentA.newInstance();
}
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.container_content, fragmentA, "my-tag");
ft.commit();
由于 FragmentA
是第一次创建它 运行,所以它不会进入 if 块。但是我注意到 FragmentA
return 的 onCreate()
是 ViewModel 的不同实例。我在 FragmentA
中有以下代码:
public void onCreate(Bundle sI) {
super.onCreate(sI);
mViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
Log.i("test", "ViewModel-> " + mViewModel.toString());
}
日志打印:
ViewModel-> com.myapp.MyViewModel@ed93f63
我第一次创建 FragmentA
然后
ViewModel-> com.myapp.MyViewModel@ff3eee4
我打电话后 ft.replace()
.
所以,我很困惑为什么 ViewModelProviders
return 第二次 ViewModel
的不同实例,即使 FragmentA
不为空(因为它没有进入 if 块,我假设它不为空)?
根据 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.
ViewModel
的范围与输入Fragment/Activity的范围绑定。
- Activity:当它销毁且不是由配置更改引起时
- 片段:销毁且不是由配置更改引起的(即从
FragmentManager
中删除)
换句话说,当您将 FragmentA
替换为 FragmentB
时,FragmentA
将被销毁,因此其关联的 ViewModel
实例将被删除。
当您调用 ViewModelProviders.of(fragment)
获取 ViewModel
时,它最终将此任务交给 ViewModelStore
,它存储了我们的 ViewModel
个实例。
让我们深入探讨 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();
}
}
因此 ViewModel
实例因为这个调用被移除 mViewModelStore.clear();