片段的视图模型而不是访问活动视图模型?

Posted

技术标签:

【中文标题】片段的视图模型而不是访问活动视图模型?【英文标题】:ViewModel for Fragment instead accessing Activity ViewModel? 【发布时间】:2018-02-26 08:52:05 【问题描述】:

问题很简单。问题在于使用 ViewModels、LiveData 和其他相关的 Lifecycle 感知拱方法。 我有一个带有 NavDrawer 的 Activity,它在内部切换片段。 而且我还遇到过两个片段同时出现在屏幕上的情况——这将是主要的痛苦。 一个 Fragment 有一个带有嵌套 Fragments不要问为什么)的 ViewPager。 当用户执行某些操作时,另一个片段只是从第一个片段获取信息。这仅通过共享活动视图模型来实现。但是应用程序本身有很多业务逻辑,并且随着它的进一步发展,视图模型变得越来越大。 我想问的是——不是收据或规则如何解决这个问题,或者如何通过修复项目的整个结构来克服这个问题。我想请教如何在 android.arch.lifecycle 样式中应用 MVVM 方法来挖掘用例。 我还没有看到比在 Fragment 之间共享 Activity ViewModel 更复杂的东西。但通常,这不是治愈方法。

你在这里看到的——实际上是一团糟。关键是所有人都在共享ActivityViewModel。来自 FirstFragment 的连接(聚合)意味着 ViewPager 内部 FirstFragment 正在启动 ChildFragments 并且它们也在使用相同的 ActivityViewModel(杀死我)。因此,每个人都在使用一个共享的 ViewModel。 我的建议是为每个层添加一个 ViewModel。这样 Activity/Fragments/ChildFragments 就有了自己的 ViewModel。 但是这里出现了什么 - 我们应该如何沟通? 可能的解决方案:

每个组件有两个 ViewModel。一个 ViewModel 将处理/委托业务逻辑,另一个将进行通信。 每个组件有两个视图模型 - 不太好,是吗? 老旧的界面(请不要!

其他解决方法 - 例如 DB/SharedPrefs/Realm 更改侦听器和事件总线(我太老了 :( )。

您的解决方案在这里!

我会说以上所有这些都违反了很多设计原则,那我该怎么办? 我该如何走出这个烂摊子?有没有Uncle Bob 或其他superhero 来帮忙?

P.S. - 好吧,创建 UML 或其他图表并不是我的强项。对此感到抱歉。 P.P.S. - 我知道google samples。

【问题讨论】:

每个组件有多个 ViewModel 有什么问题?出于某种原因,它们以类名为键。 @ianhanniballake 嗯,我的想法是有争议的。总是试图将一个虚拟机绑定到一个组件。让我们说每个组件的 VM。 github.com/googlesamples/android-architecture-components/issues/… - 不一样,但每个屏幕的视图模型。 当我有许多视图模型时,我通过流进行的所有通信以及共享管理器/模型中的变量更改。第一个片段将输入更改为 6 并将其设置在管理器(模型)和管理器中,使用可观察模式(在您的情况下它可能是 mutablelivedata)通知观察者(观察实时数据变量的其他片段)该值已更改 @V-master 当然,但在这种情况下,我需要参考模型/经理。所以我将在我的片段中引用两个视图模型。 你的结论是什么? 【参考方案1】:

我的建议您可以为整个用例处理两个ViewModel

制作一个ViewModel

假设 MyActivityViewModel 来处理与 activity 级别相关的所有逻辑。因此,如果任何 fragment 逻辑与您的 activity 直接相关,请分享您的 ViewModel,如下所示:

ViewModelProviders.of(getActivity()).get(MyActivityViewModel.class); // Like this in fragment.

&

ViewModelProviders.of(this).get(MyActivityViewModel.class); // Like this in activity.

这将在您的activityfragment之间共享共同的ViewModel


如果您必须在您的 ChildFragment 之间共享逻辑,则另一个 ViewModel 会选择 FirstFragment

您可以在这里分享ViewModel,比如说FragmentViewModel,如下所示:

ViewModelProviders.of(this).get(FragmentViewModel.class); // Like this in FirstFragment which is having view pager.

&

ViewModelProviders.of(getParentFragment()).get(FragmentViewModel.class); // Like this in View pager fragments, getParentFragment() is First fragment in our case.

尽管如此,我们仍然可以在 FirstFragment 的子片段中使用我们的活动级别 MyActivityViewModel,例如:

ViewModelProviders.of(getActivity()).get(MyActivityViewModel.class);

【讨论】:

【参考方案2】:

首先,多个 ViewModel 用于单个 视图并没有什么坏处。

我会考虑我的 ViewModel 正在获取和操作什么样的数据,并以一种看起来很自然的方式对它们进行分组。

对于您的情况,如果片段和活动的逻辑非常相似,我认为您可以使用单个 ViewModel,但我会避免这样做。

我要做的是将活动的ViewModel 分解成更小的部分,并在我的Fragments 中重复使用正确的ViewModel,这样我就没有上帝视图模型,在不同的 ViewModel 中也没有大致相同的代码。

【讨论】:

【参考方案3】:

这是 Jeel Vankhede 给出的答案的更新版本。 Kotlin 也实现了相同的功能。

由于现在不推荐使用 ViewModelProviders,我们必须使用 ViewModelProvider。

这是您在 Activity 中的操作方式:

ViewModelProvider(this).get(MyActivityViewModel::class.java)

这是你在 Fragment 中的做法:

ViewModelProvider(requireActivity()).get(MyActivityViewModel::class.java)

【讨论】:

这是我们都在寻找的答案:简单,有效。 [掌声]【参考方案4】:

要解决FirstFragment与其子片段共享其视图模型的问题,您可以使用此代码从任何子片段访问FirstFragmentViewModel

    // in ChildFragment1
    val firstFragmentViewModel: FirstFragmentViewModel by viewModels(
         requireParentFragment() 
    )

【讨论】:

以上是关于片段的视图模型而不是访问活动视图模型?的主要内容,如果未能解决你的问题,请参考以下文章

使用 mvvmcross 显示视图模型时无法解析当前的***活动

我如何使用视图模型从另一个片段访问函数

LiveData 没有观察具有共享视图模型的子视图页面片段

未解决的对视图模型的引用

使用backbone.js 从视图访问模型数据

WPF - 如何从视图而不是视图模型显示自定义异常