Android 在调用 ft.replace 时为同一 fragment 返回不同的 ViewModel 实例

标签 android android-fragments android-architecture-components android-viewmodel

我有一个容器 Fragment,称它为 ContainerFragment,它包含两个 fragment ,FragmentAFragmentBFragmentAFragmentB 使用 ViewModelProviders.of 在 onCreate() 方法中创建一个 ViewModel (这个) 方法。

假设容器一次只能显示一个 fragment ,我正在使用 FragmentTransaction.replace() 方法在 FragmentAFragmentB 之间切换。在我的例子中,我展示了 FragmentA,它创建了 FragmentA ViewModel,然后一个 Action 触发 FragmentB 来替换 FragmentA .现在,当我完成 FragmentB 时,我再次调用 replace 以显示 FragmentA。这是我在替换 fragment 的方法中所做的检查:

if (fragmentA == null) {
    fragmentA = FragmentA.newInstance();
}
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.container_content, fragmentA, "my-tag");
ft.commit();

由于 FragmentA 是在第一次运行时创建的,因此它不会进入 if block 。但我注意到 FragmentAonCreate() 返回了 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 会第二次返回 ViewModel 的不同实例,即使 FragmentA 是不为空(因为它没有进入 if block ,我假设它不为空)?

最佳答案

根据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 的范围绑定(bind)到输入 Fragment/Activity 的范围。

  • Activity:当它被销毁且不是由配置更改引起
  • Fragment:当它被销毁且不是由配置更改引起时(即从 FragmentManager 中删除)

换句话说,当您将 FragmentA 替换为 FragmentB 时,该 FragmentA 将被销毁,因此其关联的 ViewModel 实例将被删除。


当您调用 ViewModelProviders.of(fragment) 获取 ViewModel 时,最后它会将此任务交给 ViewModelStore,它存储我们的 ViewModel 实例。

让我们深入研究 source code 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(); 而被删除

关于Android 在调用 ft.replace 时为同一 fragment 返回不同的 ViewModel 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51977021/

相关文章:

android - 在通过 fragment 导航时正确处理 DrawerLayout 动画

android - 如何通过单击选项菜单更改 MainActivity 中 webview 的 url

Android与房间表模型的双向数据绑定(bind)

android - Android开发中如何正确处理View State

java - 列表 fragment 中的项目没有改变颜色

javascript - Cordova - 为什么 $http get 请求在 android 设备上失败但在 chrome 上工作

android - 使用 ViewPager 在单个页面上显示两个屏幕

android - 通过获取 mediaPlayer 的幅度来制作进度条动画

java - Eclipse 无法将我的类(class)识别为 fragment

android - 导航时 Navigation Host 变为 null(Android 导航组件)