【发布时间】:2021-01-28 00:26:28
【问题描述】:
我正在开发一款 Android 钢琴“测验”应用程序 - 用户点击钢琴键,然后单击黄色的“检查”按钮提交答案以供评估,并查看在钢琴上绘制的正确答案。主要的QuizActivity 有这样的布局:
屏幕的上部有几个控件(文本、提交按钮等)。
屏幕的下半部分被一个自定义的PianoView 组件占据,该组件处理钢琴键盘的绘制。
根据MVVM原则,PianoView 应该有自己的PianoViewModel,它将其状态(即当前按下的键、突出显示的键等)存储在@987654331 中@。
封闭的QuizActivity 还应该有一个QuizActivityViewModel,用于处理各种控件(提交答案、跳过问题......)。
QuizActivityViewModel 需要能够从PianoView(或者更确切地说从它的KeysStateRepository)查询选定的键,将它们提交给域层进行评估,然后将结果发送回PianoView 用于可视化。
换句话说,QuizActivity 的ViewModel 应该拥有/成为PianoView 的ViewModel 的父级,以促进通信和数据共享。
如何建模这种父子关系以在 ViewModel 之间进行通信?
AFAIK ViewModel 不能依赖于另一个 ViewModel (我会通过什么作为 ViewModelStoreOwner 来获得另一个 ViewModel 中的 Viewmodel?)。我认为至少用 Dagger-Hilt 是不可能实现的。
想到了解决此问题的三个解决方案,但都无法使用:
1 - 视图之间共享数据的官方方式
Android 开发文档recommend 使用shared ViewModel 来促进两个片段/视图之间的数据共享。但是,这不适合我的用例。 PianoView(或其 ViewModel)应该是其状态的唯一所有者,Repository 的作用域为 ViewModel。否则,PianoView 组件将无法重用。例如考虑另一个Activity,我希望有两个独立的PianoView 实例可见:
从测验活动中重用共享 ViewModel 显然是错误的,因为它包含不相关的方法和逻辑(即提交测验答案)并且不适合双键盘场景。
2 - 应用程序范围的存储库
Reddit 解决了类似的问题,提出了使用存储库共享实例的解决方案。但是,使用@SingletonKeyStateRepository 会再次阻止两个独立的键盘显示不同的数据。
3(EDIT) - 由事件总线复制的 2 个重复存储库
理论上我可以创建 2 个独立的 ViewModels 和 2 个 KeyStateRepository 实例。 ViewModels 将订阅事件总线。每次 ViewModel 在其存储库上调用可变操作时,它也会触发一个事件,并且该操作将通过订阅同一事件总线的另一个 ViewModel 进行复制。
但是,这感觉就像是一个脆弱而复杂的 hack。我想要一个简单的 MVVM 兼容解决方案。我不敢相信两个 UI 组件的简单父子关系在 MVVM 中是无法实现的。
【问题讨论】:
标签: java android mvvm android-viewmodel dagger-hilt