Most of the MVVM examples are dealing with very simple user interfaces.
But lets say I have an activity with many views to update (i.e. lots of data)
As I read in other places, multiple ViewModel objects is a bad pattern.
So, as I see it there are two solutions for that:
Create a single object (and single LiveData for it), that wraps all other data objects.
But there's a problem with this - each data object that gets updated will cause the whole UI to update.
Create multiple objects (and multiple LiveData objects for it).
It means that I need to observe each LiveData object. Is there a problem with this pattern?
Thanks in Advance!
First Point you mentioned : Yes this is not optimal Pattern to do but if you have small data then, separating LiveDatas is more work for less gains
Second Point you mentioned : Yes this is more optimal, you can have a LiveData object for each View you want to update and observe them all from your activity or fragment. There are no issues in this Pattern.
About Mutilple ViewModels :
Multiple ViewModels Pattern in same Activty/Fragment is also an option if you have too many things(LiveData objects or funcitions) happening in one ViewModel. This is only recommended to make viewModels lighter. So only use this if you are having a large viewModel class
Create ViewModels for discrete types of information.
You could for example have a UserViewModel that deals with all state regarding a User. This means you can use the same ViewModel in another context, without pulling data that might not be necessary (as you would if you had a single God ViewModel).
Create as many LiveData objects as you need to model your view.
It is better to condense the data into logical objects, where possible. If only to keep things manageable.
If you have a User, you should use that for your LiveData instead of having a LiveData for E-mail address, Display name, Age, etc. That will make things much simpler for your data bindings. Try to keep things logically grouped together.
Related
I'm trying out StateFlow in DataBindings and in all examples I can find, most look like a copy of this one, two variables are used in the ViewModel for one data binding. One private MutableStateFlow and a public StateFlow. And the StateFlow is pretty much just reading the value from the MutableStateFlow. Why is this? Wouldn't it be easier to just have one variable, a MutableStateFlow and skip the StateFlow variable all together?
This is just a simple case of encapsulation (and is unrelated to data binding/Android). From a technical standpoint, this is a redundant step and doesn't make a difference. From a design standpoint however, it restricts modification of the StateFlow value outside of your containing class.
This is quite a common pattern with 'observable data holders' (MutableLiveData and LiveData), which can be thought as similar to having a property with a private setter. In fact, if you only need to collect the flow and not access its value, you could even use Flow as the exposed type (although as #MarkKeen pointed out, this won't work with data binding).
I have one Activity and i have created one View-model for it. I have created different classes like
UiUtil( show, hide view, hide key board ), Network layer , Data Base layer, AppUtil( for common functionality like Collection check, String validation, Date Conversion etc)
My question is, In MVVM design pattern is Activity can use these utility classes directly or it needs to use these classes via View-model, if it via view model then in the view-model i have to write a method that just call utility classes method . like below TimeDateManager is utility class used in view-model
class HomeViewModel: BaseViewModel()
{
fun prepareTimeAmPmToDisplay(context: Context, alarm: Alarm): String
{
return TimeDateManager.prepareTimeAmPmToDisplay(context, alarm)
}
}
Architectures are not obligatory, they are recommendational, thus you can change their usage in quite wide range. The only stopper should be a common sense(if it is present of course).
In this particular case the usage of utility class inside an Activity maybe ok, based on your ViewModel construction and its way of communication with View(read Activity).
For example if you have some LiveData that sends some kind of event(for ex. data loaded from backend or alarm trigger) inside your ViewModel and your View listens to it, I think it is ok to use util classes inside an Observer in Activity. Especially if this utils method doesn't depend on any ViewModel or Repository data. The direct utils usage in Activity is not limited by this usecase, though - there are plenty of others.
I understand that this may be an unpopular opinion in modern time of "clean approach" but I believe that this "clean approach" sometimes complicates stuff where it shouldn't, thus if mixing things a bit does not brake overall architecture but rather makes some thing more readable and easy to maintain - I would go for it.
Hope it helps.
My approach toward MVVM is simple, ViewModel is responsible for business logic, dealing with repositories (Network, Database, etc.) and all of the non-UI codes preparing the required data for UI, just like the documentation:
A ViewModel object provides the data for a specific UI component, such as a fragment or activity, and contains data-handling business logic to communicate with the model. For example, the ViewModel can call other components to load the data, and it can forward user requests to modify the data. The ViewModel doesn't know about UI components, so it isn't affected by configuration changes, such as recreating an activity when rotating the device.
On the other hand, ViewModels should not store a context (ApplicationContext is exceptional) and it's preferred that they do not use android APIs at all, so they become more testable (especially in the case on pure unit tests).
Also we are recommended to make use of LiveData in ViewModels and the UI has to observe the LiveData. For example, in onCreate of your Activity, you will call loadMainContent() method from VM, it calls getMainContent(page=1) from repository, and the repository will decide to load data from DB or network, and the result will be set on a LiveData were the View is listening for changes.
TL;DR
Sometimes it's even better to call these utilities from View rather than the VM. I'm pretty sure about your UiUtil also I think TimeDateManager is more view related rather than logic related. In addition, Network and DB layers are more efficient if called through a repository (which is responsible for caching, etc.) and VM can use that repo.
LiveData seems very useful since it only notifies the view when the view is in an active state. It also stores and returns the last value to new subscribers right after subscribe.
My question is how to achieve the same thing with only RxJava?
Since Rx is a fully functional reactive solution combining it with another reactive solution doesn't seem right. I prefer if I could just remove LiveData from the project.
I know about https://github.com/trello/RxLifecycle and https://github.com/uber/AutoDispose but what they do is unsubscribing from the stream. I don't want that. I want my stream to exist as longs as view model is alive but my activities to start and stop listening to the steam base on lifecycle.
any suggestion will be appreciated
You can definitely do the whole thing with only RxJava. That's what I did with my team in many apps:
Regarding life-cycle management, we do two things:
We use the ViewModel from the Architecture Components to retain the ViewModel's states when the View gets destroyed https://developer.android.com/topic/libraries/architecture/viewmodel
We subscribe to our ViewModel's RxJava-Properties in our View/Fragment and dispose the subscription e.g. in onStop/onDestroy. RxLifecycle as you mentioned is actually of great help there. You cannot or rather should not retain the subscriptions when the View gets destroyed. It creates a memory leak since the subscription still has a hard reference on your View/Fragment. Also, the whole thing will crash if your ViewModel's RxProperties fire when the View was destroyed (e.g. when a server request returns after closing the app). So you need to dispose your subscriptions, no way around that in Android.
As #Samuel mentioned a BehaviourSubject/PublishSubject (depending on the case) is a great fit to provide Inputs to a ViewModel. The Outputs will be Observables which you subscribe to. Your ViewModel could have an interface with Outputs and Inputs like this:
interface TasksViewModel {
// inputs
Observer<Task> taskAddedTrigger();
Observer<Task> taskClickedTrigger();
Observer<Task> taskCompletedTrigger();
// outputs
Observable<Boolean> isLoading();
Observable<List<Task>> tasks();
}
Your ViewModel then just uses RxJava to map inputs to outputs in a very functional style. You Fragment supplies Inputs to the ViewModel whenever User input is received. It subscribes to Outputs and updates the user interface accordingly when the ViewModel's Output changes.
Here is a compact article where I summarize this whole Architecture (MVVM+RxJava)
Let me know if you run into trouble with any details of this approach. I used this architecture in many apps.
You can go with 2 solutions:
first one you can use LiveDataReactiveStreams to convert from a livedata stream to a rx stream and vice versa.
second one you may definitely get rid of livedata and use BehaviourSubject (a rx stream that store last value as live data), but as you said you'll have to subscibe/unsubscribe when your view resume/pause
Hi I am reading this post https://news.realm.io/news/eric-maxwell-mvc-mvp-and-mvvm-on-android/ where they explained very well about mvc, mvp, mvvm. I undertood how mvp design pattern works.
I don't find any drawback in MVP over MVVM. As they suggested this is issue
Presenter Concerns -> Maintenance - Presenters, just like Controllers, are prone to collecting additional business logic, sprinkled in, over time. At some point, developers often find themselves with large unwieldy presenters that are difficult to break apart.
Can anyone explain what does it means with an example & how it can be resolved using MVVM ?
I'm a big advocate of MVP and haven't really tried MVVM. The drawback of the possibility of a Presenter getting out of control is something I've had experience with but it can be mitigated.
In the example from the post the business logic will be relatively simple. There is likely only one model to deal with and not too much complex logic.
Let's think of a more complicated example though. Say you have an app that sells flowers. Once the user has chosen their bunch of flowers they get taken to the order options screen where they can:
add a message to the flowers
choose a gift vase
select postage addresses
choose a delivery date
Then add some domain requirements:
you can't add a message if they're delivering abroad
some areas have different lead times on delivery
some vases are only available with some flowers
This might not be the best UX but putting that aside you now have a Presenter that has to deal with many different Models (account, address, vases, orders) and can very quickly start taking on many responsibilities beyond simply telling the View what to display and passing events to the Model. This violates the Single Responsibility Principle. Also any time a class starts getting beyond 500 lines I start getting upset.
The solution is relatively simple though. You separate all your separate bits of logic out into UseCase classes. I use a relatively simple base class as follows:
public abstract class UseCase<I, O> {
public static final int NO_STATUS = -1;
public Observable<Integer> getStatus() {
return Observable.just(NO_STATUS);
}
public abstract Observable<O> getAction(I input);
}
You specify an input & output type and inject all the models you need in the constructor in the concrete implementation class. The Presenter takes events and input from the View passes this to the appropriate UseCase, this then does the complex logic with the Model and returns the appropriate data to the Presenter to update the View.
You can send periodic status updates back to your Presenter using the status if needed to update the UI state.
This way your Presenter returns to being a simple conduit for transferring data & events between the View and the Model and the business logic is nicely contained in a separate class for each action.
As in the MVVP introduction in the article said:
MVVM with Data Binding on Android has the benefits of easier testing
and modularity, while also reducing the amount of glue code that we
have to write to connect the view + model.
Main differences of MVP and MVVP are:
View layer: In MVP, your View is totally a dumb and passive View. But in MVVP, your View is more flexible because it can bind to observable.
In MVP, your Presenter takes care almost everything because of dumb View, so it will become really big and complicated gradually. Meanwhile, in MVVP, ViewModel have support from View (its a little bit smart :D), especially Data Binding, you can reduce a part of logic codes.
Therefore, you will write a lot of codes for Presenter and they are logically related in which you will find it difficult to break down.
However, many developers prefer MVP because they do not want some business logic codes being part of XML layout.
I'm learning MVP structure and I trying to figure out:
How to pass data between models?
Each model represents one action and if I need to send data from one
model to another one, how can I properly make it? Should I pass data
through presenter, like
firstModel -> commonPresenter -> secondModel
OR
send data between models, like
firstModel -> secondModel?
And what if these models interact with different presenters?
The Model View Presenter pattern, like most architectural patterns, is quite open to experimentation. The important thing to keep in mind is to separate the View from the domain logic and data handling.
Particularly in Android, it's useful to keep the code as far as possible from Framework specific classes like Activities and Fragments.
In my experience, it's best to let Models communicate amongst themselves, as Observers of each other. The same goes for Views and Presenters, or, in general, any component in the same architectural layer.
AFAIK you have to convert your Domain models to your Ui models in presenter so you have to call a method or a constructor like this in presenter:
ModelOne modelOne = new ModelOne(modelTwo);
please consider DRY principals and do NOT assign each field in presenter itself like this
modelOne.title = modelTwo.title;
modelOne.id = modelTwo.id;
but if you want convert a Domain layer model to another Domain layer model you have to do it in other layers. read this for more info:
http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/
"the presenter communicates with model layer, converts the data to UI friendly format, and updates the view"
also you can find above sentence in this link:
http://iyadagha.com/using-mvp-ios-swift/