40

我有一个关于 android ViewModels 的架构问题:

假设在我的应用程序中,我有一个 Activity,里面有两个 Fragment(使用 Viewpager)。这两个片段做不同的事情(因此可能有自己的 ViewModel?),但它们也都需要各种相似的数据。

例如,如果网络连接可用或不可用(如果没有连接,则两个片段显示不同的错误 UI),或者通过来自服务器的推送并同等影响两个片段的某些用户设置。

这看起来像这样:

在此处输入图像描述

现在我的问题是在使用 ViewModels 时如何处理这种情况?一个视图观察多个 ViewModel 是否很好,就像我有一个用于 Activity 的 ViewModel(保持两者都需要的状态)和一个用于每个 Fragment 的 ViewModel,如下所示:

在此处输入图像描述

例如,这里暗示了这一点,但这不是一个好的做法,因为MVVM 中的关系通常是

视图 n - 1 视图模型 n - 1 模型

但我不确定在我的情况下,这种共享 LiveData 的正确位置在哪里?

4

2 回答 2

13

迟到的答案,但我问了自己同样的问题,并在 Google 指南中找到了答案。特别是对于片段,在 Google 文档中明确提到了这里

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
            // Update the UI
        })
    }
}
于 2019-09-15T07:11:28.293 回答
12

我认为 ViewModel 背后的概念是它应该与单个“屏幕”而不是“视图”相关。所以按照这个逻辑,如果多个片段引用同一个 ViewModel,我认为你可以使用同一个 ViewModel,因为它们在技术上属于同一个“屏幕”。

在片段中,您可以请求 ViewModel 的活动,该 ViewModel 包含 LiveData 的实例,并可以根据需要为您提供更新。

希望这能回答你的问题。

更新:我在 Google samples 中找到了一个示例片段的链接。查看 onCreateView() 方法。粘贴以下代码以供参考:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    final View root = inflater.inflate(R.layout.addtask_frag, container, false);
    if (mViewDataBinding == null) {
        mViewDataBinding = AddtaskFragBinding.bind(root);
    }

    mViewModel = AddEditTaskActivity.obtainViewModel(getActivity());

    mViewDataBinding.setViewmodel(mViewModel);

    setHasOptionsMenu(true);
    setRetainInstance(false);

    return mViewDataBinding.getRoot();
}

PS如果您找到了更好的解决方案/答案/实践,请让我知道。

于 2018-03-14T14:46:12.763 回答