Android MVVM:具有多个片段的活动 - 将共享 LiveData 放在哪里?

Posted

技术标签:

【中文标题】Android MVVM:具有多个片段的活动 - 将共享 LiveData 放在哪里?【英文标题】:Android MVVM: Activity with multiple Fragments - Where to put shared LiveData? 【发布时间】:2018-05-07 15:46:15 【问题描述】:

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

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

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

这看起来像这样:

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

这被暗示了 here 例如,但这不是一个好习惯,因为 relationship in MVVM 通常是

视图 n - 1 ViewModel n - 1 模型

但我不确定在我的情况下此类共享 LiveData 的正确位置在哪里?

【问题讨论】:

在我看来,您应该为每个需要执行“业务逻辑”操作的 Activity/Fragment 拥有一个 ViewModel。基本上是在 ViewModel 中操作数据,并显示在 View 中或保存到数据库中。 @joao86 是的,我知道。但是如何处理同一活动内同一级别的多个 Fragment 所必需的状态呢? 您可以将一个 ViewModel 用于多个 Fragment/Activity,否则您将不必要地重复代码和行为。 我在我的问题中提到了这一点,并将这两个方面联系起来。虽然有可能,但通常认为这是一种不好的做法,在 MVVM 中,视图应该只有一个 ViewModel。请参阅我的问题中的链接和文本。 这可能被认为是一种不好的做法,但重复代码和行为也被认为是一种不好的做法,这就是为什么它在 JAVA 中存在超类的概念。那么应该遵循哪一种良好的行为呢? :) 【参考方案1】:

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

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

希望这能回答您的问题。

更新:我找到了a link to a sample fragment in 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();

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

【讨论】:

嗨@karithik,您提供的示例是另一种情况,如果您进一步检查代码,您会看到有一个名为AddEditTaskActivity 的单独活动,它有一个片段@987654324 @ 和单个视图模型绑定到这两个类,这不是问题指定的内容。 我认为这是一个更通用的问题 - 我可以在 Activity 和 Fragment 之间共享一个 viewModel 吗?如果他们有共同的代码或共同的“状态”,似乎可以这样做。我粘贴的代码只是一个例子。因此,理论上,您可以使用来自 Activity 的 ViewModel 的通用“状态”或代码拥有多个片段。这回答了你的评论吗?【参考方案2】:

迟到的答案,但我问了自己同样的问题,并在 Google 指南中找到了答案。 尤其是片段,谷歌文档中明确提到了here

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
        )
    

【讨论】:

以上是关于Android MVVM:具有多个片段的活动 - 将共享 LiveData 放在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

Android MVVM在哪里存储数据?

具有多个片段的活动的 MVP

是否有在单个活动中处理多个片段的 Android 设计模式?

使用Architecture Components构建的应用程序是否使其成为“MVVM”,如果是,应用程序的哪些部分与哪个MVVM层相关?

在android活动中设置片段的形状和透明度

具有多个 Activity 的 Android 导航抽屉