I'm working on an Android piano "quiz" app - users tap on the piano keys and then click the yellow "check" button to submit the answer for evaluation and see the correct answer drawn on the piano. The main QuizActivity
has this layout:
The upper part of the screen hosts a couple of controls (Text, submit buttons, etc.). The lower part of the screen is occupied by a custom PianoView
component, that handles drawing of the piano keyboard.
According to the MVVM principles, the PianoView
should have its own PianoViewModel
, that stores its state (i.e. currently pressed keys, highlighted keys, etc...) in a KeysStateRepository
. The enclosing QuizActivity
should also have a QuizActivityViewModel
, that handles the various controls (submitting an answer, skipping a question...). The QuizActivityViewModel
needs to be able to query the selected keys from the PianoView
(or rather from its KeysStateRepository
), submit them to the Domain layer for evaluation and then send the results back to the PianoView
for visualization.
In other words, the QuizActivity
's ViewModel
should own/be a parent of the PianoView
's ViewModel
to facilitate communication and data sharing.
How can I model this parent-child relationship to communicate between the ViewModels?
AFAIK a ViewModel
cannot depend on another ViewModel
(What would I pass as the ViewModelStoreOwner
to obtain a ViewModel
in another Viewmodel
?). I don't think it's possible to achieve with Dagger-Hilt at least.
Three solutions to work around this problem came to mind, all of them unusable:
1 - The official way of sharing data between Views
The Android dev docs recommend using a shared ViewModel
to facilitate sharing of data between two Fragments / Views. However, this does not fit my use-case. The PianoView
(or its ViewModel) should be the sole owner of its state with a Repository
scoped to its ViewModel
. Otherwise, the PianoView
component would not be reusable. Consider for example another Activity
, where I'd like to have two independent PianoView
instances visible:
Reusing a Shared ViewModel from the quiz activity would be obviously wrong, because it contains irrelevant methods and logic (i.e. submitting quiz answers) and would not fit the two-keyboard scenario.
2 - Application-scoped repository
A similar problem was tackled on Reddit with a proposed solution of using a shared instance of the repository. However, using a @Singleton
KeyStateRepository
would once again prevent the two independent keyboards to display different data.
3(EDIT) - 2 duplicate repositories replicated by an Event Bus
I could in theory create 2 independent ViewModel
s and 2 KeyStateRepository
instances. The ViewModels
would subscribe to an event bus. Each time a ViewModel
invokes a mutable operation on its repository, it would also fire an event and the operation would get replicated via the other ViewModel
subscribed to the same event bus.
However, this feels like a fragile & complicated hack. I'd like to have a simple MVVM-compatible solution. I can't believe a simple parent-child relationship for two UI components is something unattainable in MVVM.
from How to model parent-child relationship in Android MVVM VMs?
No comments:
Post a Comment