Java 如何在Android MVVM中建模父子关系?
我正在开发一个Android钢琴“测验”应用程序——用户点击钢琴键,然后点击黄色的“检查”按钮提交答案供评估,并查看钢琴上绘制的正确答案。主Java 如何在Android MVVM中建模父子关系?,java,android,mvvm,android-viewmodel,dagger-hilt,Java,Android,Mvvm,Android Viewmodel,Dagger Hilt,我正在开发一个Android钢琴“测验”应用程序——用户点击钢琴键,然后点击黄色的“检查”按钮提交答案供评估,并查看钢琴上绘制的正确答案。主quizaActivity具有以下布局: 屏幕的上部有两个控件(文本、提交按钮等)。 屏幕的下部由一个定制的PianoView组件占据,该组件处理钢琴键盘的绘图 根据MVVM原则,PianoView应该有自己的PianoViewModel,该模型将其状态(即当前按下的键、突出显示的键等)存储在KeyStateRepository中。 随附的QuizActi
quizaActivity
具有以下布局:
屏幕的上部有两个控件(文本、提交按钮等)。
屏幕的下部由一个定制的PianoView
组件占据,该组件处理钢琴键盘的绘图
根据MVVM原则,PianoView
应该有自己的PianoViewModel
,该模型将其状态(即当前按下的键、突出显示的键等)存储在KeyStateRepository
中。
随附的QuizActivity
还应具有一个QuizActivityViewModel
,用于处理各种控件(提交答案、跳过问题…)。
QuizActivityViewModel
需要能够从PianoView
(或者更确切地说是从其keystateRepository
)查询所选密钥,将它们提交到域层进行评估,然后将结果发送回PianoView
,以便可视化
换句话说,quizaActivity
的ViewModel
应该拥有/是PianoView
的ViewModel
的父级,以促进通信和数据共享
如何对这种父子关系建模,以便在ViewModels之间进行通信?
一个ViewModel
不能依赖另一个ViewModel
(在另一个ViewModel
中,作为ViewModelStoreOwner
获得ViewModel
,我应该传递什么?)。我认为至少用匕首柄是不可能实现的
我想到了解决这个问题的三种解决方案,它们都无法使用:
1-视图之间共享数据的官方方式
Android开发人员使用共享的视图模型来促进两个片段/视图之间的数据共享。但是,这不适合我的用例。PianoView
(或其ViewModel)应该是其状态的唯一所有者,其存储库的作用域为其ViewModel
。否则,PianoView
组件将无法重用。例如,考虑另一个<代码>活动< /代码>,在这里我想有两个独立的<代码> PiaOnVIEW/COD>实例可见:
重用测验活动中的共享视图模型显然是错误的,因为它包含不相关的方法和逻辑(即提交测验答案),不适合双键盘场景
2-应用程序范围的存储库
通过使用存储库的共享实例的建议解决方案,解决了类似的问题。但是,使用@Singleton
KeyStateRepository
将再次阻止两个独立的键盘显示不同的数据
3(编辑)-2个由事件总线复制的重复存储库
理论上,我可以创建2个独立的ViewModel
s和2个KeyStateRepository
实例。ViewModels
将订阅事件总线。每次ViewModel
调用其存储库上的可变操作时,它也会触发一个事件,该操作将通过订阅到同一事件总线的另一个ViewModel
进行复制
然而,这感觉像一个脆弱而复杂的黑客。我想要一个简单的MVVM兼容解决方案。我不敢相信两个UI组件的简单父子关系在MVVM中是无法实现的。如果您不想将PianoViewModel
绑定到您的ActivityViewModel
,我会创建一个接口,由ActivityViewModel
实现,而PianoVM
可以有一个对该接口的可空引用。这样,PianoViewModel
就不需要实现,也不需要存在组件
如何获得活动视图模型是另一个问题。查看by activityViewModels()
实现中的片段,您可能可以通过by viewModels()
传递活动的viewModelStore
来执行相同的操作
在多体系结构活动中,如果您不想让PianoViews
拥有ViewModels
和您的ActivityViewModel
了解它们,请不要对它们使用Dagger
注入,而是在ActivityViewModel
中创建PianoViewModels
,并在调用阶段为它们分配一些回调创建-这样,您就可以从ActivityViewModel
中访问他们,并能够倾听他们的事件、影响他们的行为以及保存他们的状态。这并非罕见,在某些情况下甚至是正确的方法<代码>匕首
-仅仅是一种工具,不打算在任何地方使用,但只有在那里才需要它。不需要创建PianoViewModels
——您可以将所有需要的内容注入ActivityViewModel
,并将所有需要的元素传递给PianoViewModels
构造函数
如果不想,也不需要将视图包装成片段
编辑结束
基于有缺陷的体系结构方法,您做出了错误的假设
我很好奇为什么您需要ActivityViewModel
。视图模型应仅存在于具有某些视图的图元中。当前的android开发表明,活动不应该有视图表示,而应该仅仅作为其他视图的容器()。根据您的架构,活动可能会处理显示l
// One QuizActivityViewModel, Multiple Fragments:
Activity -> PianoFragment (PianoView)|
| <-> PianoViewModel <-> KeyRepo
PianoFragment (PianoView)| /
-> QuizActivityViewModel <----------------------/
// 1 Act. 1 Frag. N Views.
Activity -> PianoFragment (PianoView)|
(PianoView)| <-> PianoViewModel <-> KeyRepo
-> QuizActivityViewModel <---------------------------/