支持片段管理器.replace()和ViewModel

时间:2017-07-30 18:19:22

标签: android android-architecture-components

看来每当您在支持片段管理器的事务中使用.replace()方法时,都会重新创建ViewModel。这是故意的吗? Fragment实例本身不会更改,并且在旋转/配置更改期间将(部分)保留ViewModel。

我看到以下情况:

  1. 获取视图模型参考(计数= 0),更新计数= 1,旋转,计数= 1,onCreate再次调用 并计数= 0(重新创建视图模型)。
  2. 调用.replace()并重新创建视图模型(活动和片段实例不变)。
  3. 使用支持库26.0.0。

    我的片段的ViewModel正在创建onCreate,其范围限定为Fragment

    viewModel = ViewModelProviders.of(this).get(DashboardViewModel::class.java)
    

    如果这是正常的话,有人会说清楚吗?

2 个答案:

答案 0 :(得分:2)

正如@CommonsWare所提到的,viewmodel中的fragment实例在Activity中应该是相同的。

因此,在Activity中,你应该做这样的事情

MyViewModel vm = ViewModelProviders.of(this).get(MyViewModel.class);

在Fragment中,你应该做这样的事情

MyViewModel vm = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

结果,他们将使用相同的实例。

但是,如果您尝试在片段

中使用它

MyViewModel vm = ViewModelProviders.of(this).get(MyViewModel.class);

旋转设备时,将在片段中重新创建Viewmodel。 由于实例保留在片段内而不是活动中,因此当重新创建活动时,片段也将被重新创建,并且MyViewModel实例将被重新创建。

尝试查看主详细信息片段上的示例(可能很容易解决您的问题)ViewModel in Android Developer

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends LifecycleFragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // update UI
        });
    }
}

我还在github上制作了简单的Master Detail模板

SimpleDetailActivity.java

SimpleDetailFragment.java

答案 1 :(得分:1)

当你制作不同的片段时,会假定

replace()被调用。对于相同的片段,请调用update()

replace()方法意味着您可以用不同的片段替换当前的片段,片段具有不同的布局(物理结构)。您甚至无法保证它从前一个片段使用的内存开始。 ViewModel是整个容器的布局。因此,对于具有不同物理结构的对象(可能具有不同的内存 - 我正在写可能因为您也可以用相同的片段替换),您必须重新创建不同的ViewModel定义它的容器。这是因为一个ViewModel对象指向一个引用Container,下次有不同的片段时,ViewModel定义的片段容器位于其他位置,因此您需要另一个ViewModel对象来指向Fragment Container。

但是当你执行update()rotate()时,你可以保证更新后的片段的内存空间可以减少/增加,但它的启动内存仍然保持不变。因此无需创建ViewModel。这是因为您的旧ViewModel对象引用了相同的旧Fragment容器。

当你执行create()时,它会创建GUI所有内容,因此,显然会再次创建ViewModel

ViewModel count的跟踪基于以上说明。

ViewModel正在my片段的onCreate中创建,并且作用于Fragment。这是片段的权力授权。