在Last Google IO上,Google发布了一些新的拱门组件的预览,其中之一是ViewModel。
在文档中,google展示了这个组件的一个可能用途:
一个Activity中的两个或多个片段需要相互通信是很常见的。这绝不是小事,因为两个片段都需要定义一些接口描述,所有者Activity必须将两者绑定在一起。此外,两个片段都必须处理另一个片段尚未创建或不可见的情况。
这个常见的痛点可以通过使用ViewModel对象来解决。想象一个常见的主从片段的情况,其中我们有一个片段,用户从列表中选择一个项目,另一个片段显示所选项目的内容。
这些片段可以共享一个ViewModel,使用它们的活动范围来处理这种通信。
并示出了一个实现示例:
public class SharedViewModel extends ViewModel {
private final SavedStateHandle state;
public SharedViewModel(SavedStateHandle state) {
this.state = state;
}
private final MutableLiveData<Item> selected = state.getLiveData("selected");
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
@Override
protected void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
model = new ViewModelProvider(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
@Override
protected void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedViewModel model = new ViewModelProvider(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}
我非常兴奋地想到,可能不需要那些用于片段通过活动进行通信的接口。
但是Google的例子并没有确切地说明我应该如何调用master中的detail片段。
我仍然必须使用将由活动实现的an interface,它将调用fragmentManager.replace(...),或者有另一种方法使用新的架构来实现它?
8条答案
按热度按时间xriantvc1#
2017年6月12日更新,
Android Official提供了一个简单、精确的示例来说明ViewModel如何在Master-Detail模板上工作,您应该先看看它。在片段之间共享数据
正如@CommonWare,@Quang Nguyen所理解的,Yigit的目的不是从主到细节的调用,而是更好地使用中间人模式,但如果你想做一些碎片事务,它应该在Activity中完成,此时ViewModel类应该是Activity中的静态类,可能包含一些丑陋的回调,回调Activity来做碎片事务。
我尝试过实现这个,并做了一个简单的项目。你可以看看它。大部分的代码是从谷歌IO 2017引用,也结构. https://github.com/charlesng/SampleAppArch
我没有使用主细节片段来实现组件,而是使用旧的(ViewPager中片段之间的通信)。逻辑应该是相同的。
但我发现使用这些组件很重要
1.你想在中间人中发送和接收什么,它们应该只在视图模型中发送和接收
1.片段类的修改似乎不多,因为它只是将实现从“接口回调”更改为“侦听和响应ViewModel”
1.视图模型初始化看起来很重要,可能会在活动中调用。
1.使用MutableLiveData使源仅在活动中同步。
1.寻呼机活动
2.PagerAgentViewModel(它应该有一个更好的名称)
3.空白片段A
4.空白片段B
zwghvu4y2#
正如在Google官方教程中所写的,现在您可以使用
by activityViewModels()
获得共享视图模型gdx19jrr3#
我已经找到了一个类似的解决方案,因为其他人根据谷歌codelabs的例子。我有两个片段,其中一个等待对象的变化,在另一个,并继续其进程与更新的对象。
对于这种方法,您将需要一个ViewModel类,如下所示:
侦听器片段应该如下所示:
最后,更新程序片段可以是这样的:
值得一提的是,更新程序片段可以是任何形式的片段(不仅仅是DialogFragment),要使用这些架构组件,您应该在应用build.gradle文件中包含以下代码行。source
lmyy7pcs4#
在使用附加到被视为容器的活动的回调之前。
这个回调是两个Fragment之间的中间人。这个解决方案的缺点是:
有了新的ViewModel(支持LiveData),你就有了一个优雅的解决方案,它现在扮演着中间人的角色,你可以将它的生命周期附加到Activity上。
现在,您完全摆脱了与Activity和相关片段紧密耦合的回调。
我强烈推荐你去谷歌的代码实验室,在第五步,你可以找到一个很好的例子。
cpjpxq1n5#
我实现了一些类似于您想要的东西,我的视图模型包含LiveData对象,该对象包含Enum状态,当您想要将片段从master更改为details(或相反)时,您可以调用ViewModel函数来更改livedata值,Activity知道要更改片段,因为它正在观察livedata对象。
测试视图模型:
枚举:
测试活动:
主片段:
细节片段:
kx5bkwkv6#
我最终使用自己的ViewModel来保存将触发Activity方法的侦听器。类似于old way,但正如我所说,将侦听器传递给ViewModel而不是片段。因此,我的ViewModel看起来如下:
在StepMasterActivity中,我获取ViewModel并将其设置为侦听器:
StepMasterActivity.class:
...
...
在片段中,我只检索ViewModel
并拨打:
我对它进行了表面测试,它工作正常。当我着手实现与此相关的其他特性时,我会意识到可能发生的任何问题。
wgx48brx7#
对于那些使用Kotlin的用户,请尝试以下方法:
上述方法是一种很好的做法,因为它可以避免由于空指针异常而导致的崩溃
编辑:作为btraas的补充:activity被编译到getActivity()中,在android SDK中标记为@Nullable。activity和getActivity()都是可访问的,并且是等效的。
byqmnocz8#
你可以像这样设置从细节片段到主片段的值