Android - Viewmodel getting larger - java

Hi am using viewmodel in my application. Since my logic is large in single activity. Am implementing that logic in my viewmodel. Anyway i want to separate this logic from my viewmodel. Any idea how to segregate the logic out my from my viewmodel.

Since it's UI logic, you can isolate each piece of code that has to do with the same behavior (or even UI section) into its own fragment/view and corresponding view model (think Single Responsibility Principle). If it makes sense, you can also share view models between the same UI components. Then, you orchestrate everything in the activity. For code that has nothing to do with the Android framework, you can also extract it to its own independent class, and then use it in the view model through composition.

Related

How to model parent-child relationship in Android MVVM VMs?

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 ViewModels 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.
I think you got a decent answer from Pavlo up there, I'll just clarify what he meant with other words.
KeyStateRepository is a storage for the state of piano keys. There's nothing stopping you from making it to support N number of Pianos at the same time, this would solve the scenario where you have NNN Pianos on Screen, each with different keys pressed.
The PianoView should be contained in a Fragment, that should be your "unit". Why? Because you want a ViewModel to handle the state and events coming to/from the view. And a Fragment is the Android artifact provided for that regard. Think of it as an annoying piece of baggage you need. Android Devs used to call these things "Policy Delegates" because you delegate to these (a Fragment/Activity) some things you cannot do without "the framework" (the Android Framework, that is).
With this in mind, you have an Activity whose viewModel/State is handled independently. What State/Events do this viewModel handle? Things that are not in the PianoFragment/View(s). E.g. if you wanted to handle the back navigation, or a "record" button at the top, this is the activity's domain. What happens inside the "PianoView/Fragment" is not this activity's problem.
Now the Fragment that will contain the actual PianoView can be designed to contain "more than one" or just one. If you go for more than one, then the PianoContainerFragment will be designed with a ViewModel designed to handle more than one PianoView (so each view will have a "name/key") and the KeyStateRepo will be able to handle the "CRUD" operations of any Piano View you throw at. The ViewModel will sit in between, dispatching events for different "subscribed" views.
If you elect to go for "one fragment contains one piano view", then it's a similar architecture, but now handling the multiple "fragments" in one "activity" is now responsibility of the Activity (and its view model). But remember, the PianoViews (via a Fragment either shared or not) talk to a ViewModel that can be shared among piano views, that talks to a common KeyState Repo. The activity coordinates the views and other Android things (navigation, etc.) but the views operate independently, even of each other.
You don't really need a shared viewModel I think, in fact, I wouldn't do it until really needed, the more you separate things, the less the chances of "violating" one of the fancy patterns... but if you elect to use the PianoViewModel as a shared among all views, that's perfectly acceptable, you're going to have to include the Piano "Name" to differentiate whose events are for whom.
In other words (showing with ONE PianoViewModel for ASCII Simplicity),
// One QuizActivityViewModel, Multiple Fragments:
Activity -> PianoFragment (PianoView)|
| <-> PianoViewModel <-> KeyRepo
PianoFragment (PianoView)| /
-> QuizActivityViewModel <----------------------/
Here the QuizActivity creates N fragments (in a list maybe?). These fragments internally initialize their pianoView and connect to a PianoViewModel (can be shared like in the graph above) or each can have its own. They all talk to the same Repo. The repo is your "single source of truth about what each "piano". What keys are pressed, and anything else you can think of (including a name/key to make it unique).
When QuizActivity needs to evaluate the state of these, it will ask (via its own viewModel) for the state of NN pianos.
Or
// 1 Act. 1 Frag. N Views.
Activity -> PianoFragment (PianoView)|
(PianoView)| <-> PianoViewModel <-> KeyRepo
-> QuizActivityViewModel <---------------------------/
With these, the QuizActivity (which created the pianos to begin with as well), also knows the keys of the pianos that will/are displayed. It can talk to its viewModel that talks to the same KeysRepo (you only have one of these and that's fine). So it can still handle the "nav" buttons and it can ask (via its QuizActVM) what the current state of the Keys are (for all involved pianos). When a Piano key event is fired in a PianoView, the PianoViewModel will receive the event (what key was touched, in what piano); the KeyStateRepo will record this, and perhaps update a flow {} with the events coming from the pianos...
The Flow will be expressed in a sealed class which will contain enough information for both QuizActivity + VM (to perhaps perform a real-time validation), and to the PianoViewModel to update the state and push a new state to the PianoFragment (Which will update the state of its view(s)).
This is all common to either method. I hope this clarifies the sequence.
Does this make sense to you?
Edit
In a multiple architecture activity if you wan't PianoViews to have ViewModels and your ActivityViewModel to know about them - don't use Dagger injection with them but create PianoViewModels inside an ActivityViewModel and assign some callback to them on the stage of creation - thus you will have an access to them and will be able to listen to their events and influence their behaviour as well as save their state, from inside the ActivityViewModel. It is not an uncommon and in some cases even a correct approach. Dagger - is a mere instrument that is not intended to be used everywhere, but only there were it is needed. It is not needed to create PianoViewModels - you can inject all the needed stuff into the ActivityViewModel and pass all the needed elements to PianoViewModels constructors.
Also you don't need to wrap your Views into Fragments if you don't want to.
Edit end
You are making wrong assumptions based on a flawed architectural approach.
I am curious why do you need ActivityViewModel at all. View model should exist only for the elements that have some View. Current android development suggests that the Activity should not have a view representation and serve as a mere container of other views(Single activity principle). Depending on your architecture Activity may handle showing the loading state(progress bar) and some errors, but once again it should not contain anything that is being handled by other views. Thus PianoView should be a PianoFragment with its own ViewModel that handles access to its repository on the data layer via interactor on the domain layer.
The shared view model would work in case you would need one, and you would be using the Single activity principle with multiple fragments. Because Jetpack Navigation has the support of the shared view model out of the box. In the case of a shared view model - each fragment would have its own view model along with a shared one for communication. Each navigation graph could have a separate shared view model only for the fragments it contains.
Also regarding KeyStateRepository - you need only one of those(or a Dagger #Scoped multiple copies - but I do not recommend it). The only change should be - the addition of an extra key for each separate PianoView - to distinguish them inside a KeyStateRepository. To easily achieve that you may be using Room or some other file/memory/database cache mechanism.
Hence the initial problem of your app is not an inverted dependency of ActivityViewModel on a PianoViewModel, but a flawed architecture of the app and its inner interactions. If you want to continue work with your current architecture - there is no easy answer to your question, and almost every chosen solution would not be 'clean' enough to justify its usage.
I would do the following, if you don't want to tie the PianoViewModel to your ActivityViewModel, I'd just create an interface, which the ActivityViewModel implements, and the PianoVM could have a nullable reference to that interface. This way neither the implementation, nor the existence of the component would be required for the PianoViewModel to work.
How you get the ActivityViewModel is another question. Check out by activityViewModels() implementation for fragments, you probably can do the same with by viewModels() passing in the viewModelStore of the activity instead

Must every activity has own model?

I have just read the description of MVC desing pattern and I havesome questions: I am Android developer (junior), and I want to make my code more clear. So, should I use MVC for it? And must every activity has own model? Is there any good tutorial for it? Thank you.
It's already implemented. MVC pattern on Android
you need not to do anything, As Android is prebuilt MVC
MVC is kind of an idea more than a specific way of doing things (like a 1-to-1 relation between activities and models). The idea is to separate the model, view, and controller, so that stuff makes sense.
In Android, more than one activity can refer to a single model (for example, an activity with a list of houses you can search on, an "edit house" activity, and a map that shows them as points in their coordinates). So, to answer your second question: no, they don't need to have their own model.
And yes, you should use MVC, if it makes sense. Just think about your models as a separate entity from the actual application, and your activities as "users" of the models.
On Android, I've found the MVP (Model, View, Presenter) pattern to be a more direct correlation with the overall system architecture. Your activities comprise the Views, which in the MVP setup are responsible for managing their own events and controlling their own appearance. The presenter serves as a facilitator between the model and the view, providing the data when the View requests it. Depending on your needs, the presenters may or may not be a service. As for the View/Model ratio, it really depends on what you're trying to show on your screen at any one point. When android was running on phones only, it made sense to have pretty much a one to one correlation between Activities and your model. Now, the normal case is to have a one to one correlation between your model and your fragments, which your activity then marshalls about by showing the appropriate fragments.
If you want to do MVC, though, again, now that fragments are a tool in the toolbox this is much easier than it once was, especially with well developed event system (such as the one included in RoboGuice) - Think of your fragments as your Views, and your activities as controllers - Ordering your views about, providing them data from the model, and handling transitions to other controllers.
The choice of pattern depends on your needs - if one's application is to be heeavily service driven, MVP is probably a better way to go. If, however, the app is just a thin client over a database, then MVC might be easier. It's all up to you :)
'get started' resource for MVP : http://www.jamespeckham.com/blog/10-11-21/MVP_on_Android.aspx

Java Swing GUI code structure

I have a class which extends JFrame and forms the GUI of my program. I want to use the GUI for two main purposes:
I want the user to be able to input values to the program.
I want the GUI to display values created by my program.
Considering my class has a lot of GUI elements, the source file is already rather large and It does not seem like good practice to bundle all the program code in with the GUI code. I'm wondering what is the best way to structure my code? I believe there is an issue where requirement 1 creates a dependency from the GUI to the program code, and the second requirement does the opposite.
So, I want one class for my GUI which contains all my GUI related tasks. I then want another class for my program logic. I should then be able to call methods from the program logic class from the GUI and vice versa.
Sounds like you are looking for a textbook MVC (Model-View-Controller) design pattern. I recommend you google "MVC Design Pattern" for summaries and use cases. That being said, you might want to put your program logic into a "Singleton" class (again, google "Singleton Design Pattern"). A properly implemented Singleton should be accessible from any other class in your code.
Consider also a third middle class which acts solely for data storage, you put values into it for storage, and you fetch values from it for work. This now creates 3 clear segments for your code, the Data (the Model), the GUI (the View), and the logic (the Controller). Voila, you've just implemented the MVC (Model-View-Controller) design pattern...
The business logic should not depend on the GUI logic.
Have your GUI take inputs from the user. Call business logic methods with these inputs as method arguments, and use the values returned by the methods to display the result in the GUI. The GUI thus depends on the business logic, but the reverse is not true.
If the business logic must callback the GUI, it should do so via well-defined GUI-agnostic callback interfaces, or listeners. For example, you could register a ProgressListener on some business logic object, and this object would call back the progress listener. The GUI would have an implementation of the ProgressListener which would in fact update some progress bar or text area. But the business logic only depends on the interface, and not on the specific implementation.
I'm not sure there is one "best" way to structure GUI code. As a general rule though, you should follow MVC. Your program (Model) should never directly depend on your View code. What it's allowed to do is notify the controller that the model (or parts thereof) changed, and that whichever views are currently displaying said part of the model should be updated.
Swing already provides this abstraction layer for some of its types of component, most of the classes are (somewhat confusingly) suffixed with Model. A simple example you could look at would be BoundedRangeModel. There should be only one instance of such a Model for every "unit" of data your program manages, and different views displaying this data should share this instance. Your business code manages this object, and whenever this piece of data changes, the GUI is notified using it by firing off some event listeners.

Utilizing UI abstraction

When utilizing a UI abstraction, then the data you're displaying is protected from implementation changes in the UI layer. Does/should/can this extend to higher-level things, like for example, display as a tree or a grid? I can't work out how to insulate the abstraction from the higher-level details of how the UI is going to display the data garnered through said abstraction.
You want to start with the Model-View-Controller architecture. This allows you to insulate, as much as possible, your user interface from data changes. The Model layer is your data objects. The View layer is your actual Swing components. The Controller layer is your listeners. The Model layer is written independently of the other two, with no knowledge of the classes. The View layer is written with no knowledge of the Controller layer.
If you require more abstraction than that, you can create interfaces for your Model layer so that several different data models can all use the same interface. This way, it doesn't matter what data you give to the View layer, it just displays it through the use of the interface.
Also realize that it's not always possible to do what you're asking. Sometimes a user interface needs to be written specifically for the data being displayed. A tree isn't always a tree, and a grid isn't always a grid. It works well to customize the View layer to match the data being displayed. This way, you can tailor the functionality specifically to the data being manipulated and create a better interface for your users.
Certainly, though, it should be done where it makes sense. This is where experience and judgment play a big factor.

Can Model Observe View?

I am developing an application in Java, in my GUI I have several JPanels with a lot of settings on them, this would be the View. There is only one Model in the background of these several JPanels. Normally, I would Observe the Model from the JPanels.
I was just wondering, is it good practice to Observe View from the Model? Because, the user changes the View, and this change must effect my Model. Or am I missing some important principle here? Thank you for your help..
I think its great you are questioning this.
What part you are missing that could help is a Controller.
Check out http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller for an example.
Basically a controller is the mediator between a model and a view. It "Controls" the application. The only thing that your view should know about is the data that is being passed to it and how to display it. The only thing your Model should know about is data. The Controller ties these two together and contains the business logic that acts on the data and prepares it to pass to the view.
What you get from using this design is a loosley coupled and easy to test application. It really is elegant IMHO.
Cheers,
Mike
That would create unnecessary binding between the model and the view. But also think about an infinite cycle that you could get into.
What if the model was also updated by something other than a view, perhaps a web service? Then a change in the model through the web service will result a change in the view as the view would be observing the model. And also a change in the view will trigger a change in the model as the model is observing the view too. See the recursion here? It's not too difficult to bypass it, but will result in a really bad and unmaintainable design.
To tie your model and view together, one solution as has already been proposed is to add a Controller so that you have the full set of Model-View-Controller components implemented. This introduces a very tight coupling between all three components, which from a unit-test perspective is not really desirable.
An alternative would be to consider the Model-View-Presenter pattern. The Presenter would be the intermediary between the Model and the View, and would update the Model based on any input from the View, and would also be responsible for updating the view based on any changes in the Model. For your unit-tests, you would then be able to substitute a mock-View to test the Model, or a mock-Model to test the view (or mock both to test only the Presenter).

Categories