MVVM Architecture, ViewModel, MutableLiveData and LiveData
MVVM Architecture
MVVM is one of the architectural patterns which enhances separation of concerns, it allows separating the user interface logic from the business (or the back-end) logic. Its target (with other MVC patterns goal) is to achieve the following principle “Keeping UI code simple and free of app logic in order to make it easier to manage”.MVVM has mainly the following layers:
Model
- Model represents the data and business logic of the app. One of the recommended implementation strategies of this layer, is to expose its data through observables to be decoupled completely from ViewModel or any other observer/consumer.
The interaction of UI logic is done in View Model, because View Model is holding all the properties that binding to the View. All the view change can be done in View Model through data binding. So it's the best place to do UI components interaction.
View Model is only doing UI logic, not business logic, don't put the business logic here also.
ViewModel
- ViewModel interacts with model and also prepares observable(s) that can be observed by a View. ViewModel can optionally provide hooks for the view to pass events to the model.
- One of the important implementation strategies of this layer is to decouple it from the View, i.e, ViewModel should not be aware about the view who is interacting with.
The interaction of UI logic is done in View Model, because View Model is holding all the properties that binding to the View. All the view change can be done in View Model through data binding. So it's the best place to do UI components interaction.
View Model is only doing UI logic, not business logic, don't put the business logic here also.
View
- Finally, the view role in this pattern is to observe (or subscribe to) a ViewModel observable to get data in order to update UI elements accordingly.
Instead, in addition to providing properties to expose data to be displayed or edited in the view, the view model defines actions that can be performed by the user and typically expose these as commands.
The reason that don't put these event handlers in View layer is because normally inside even handler, you will be inevitable to do some UI logic. But for MVVM, all the UI logic should go to View Model.
LiveData
As said above, LiveData is one of the newly introduced architecture components. LiveData is an observable data holder. This allows the components in your app to be able to observe LiveData objects for changes without creating explicit and rigid dependency paths between them. This decouples completely the LiveData object producer from the LiveData object consumer.
Adding to this, there is also a great benefit in LiveData, LiveData respects the lifecycle state of your app components (activities, fragments, services) and handles object life cycle management which ensures that LiveData objects do not leak.
Since LiveData respects Android Lifecycle, this means it will not invoke its observer callback unless the LiveData host (activity or fragment) is in an active state (received onStart() but did not receive onStop() for example). Adding to this, LiveData will also automatically remove the observer when the its host receives onDestroy().
View and View Model are mapping together. When you have a Label on view, you might need a string property in View Model. When you have a Table on view, you might need a list property in View Model. When the view is changed by using, the property in View Model is changed automatically, if you already implement the data binding.
View Model -> View:
If you set the data binding to bi-direction, View can be updated when View Model property is changed. Data binding has the mechanism to send notifications when the View Model property is changed. In WPF, you need to implement INotifyPropertyChanged to enable this function.
Or in another way, use observable property (normally an ObservableCollection), and implement the event listener in View layer (This is the only way in JavaFX application).
Because View Model is holding the reference of Modeling, View Model can change the Model data directly.
In simple application, you may don't need even consider this problem. Because all the UI logic is done in View Model, and View Model record the change in Model layer, you don't need the Model to change View Model.
In some complicated application, especially multiple views sharing the same modeling, we still need it. In this case, we can use some messaging framework (PRISM, OSGi EventAdmin).
Or in another way, use observable property (normally an ObservableCollection), and implement the event listener in View layer (This is the only way in JavaFX application).
View Model->View:
Model->View Model:
In some complicated application, especially multiple views sharing the same modeling, we still need it. In this case, we can use some messaging framework (PRISM, OSGi EventAdmin).
How this design formed:
Originally the MVVM pattern was used and the project started as a single project, with a separate folder and namespace for Model-View-ViewModel times.As the application progressed, this design was created as separation of concerns were applied to each layer and as items were broken out into separate projects/dlls.
Why the Controller became a separate layer
Initially it seems that the View or the ViewModel (either) could handle being the Controller. However, we found that neither the View or the ViewModel acting as the Controller was a good idea for a couple of reasons. First, if the View or the ViewModel were also the Controller then they became dependent on too many items. It became clear quickly that the ViewModel was a better choice of the two and so it was chosen at first. However, with references to the View available to the ViewModel, developers began to cheat and couple the View to the ViewModel, until the ViewModel could not build without that exact View and the View was supposed to be dynamic and interchangeable.So to keep the View decoupled from the ViewModel and visa-versa, a separate Controller project was created and no reference between the View or ViewModel was allowed.
Note: Actually the Business and Controller layers are in the same dll.
Why the Business layer was separated from the ViewModel
Initially the Business layer and the ViewModel layer were the same layer. Some of the business existed directly in the ViewModel and some were in separate classes. It quickly became apparent that the ViewModels were 1) getting too large, and 2) breaking the single responsibility principle. It became apparent that in order to maintain small class files and the single responsibility principle that the Business needed to exist outside of the ViewModel and the ViewModel would simply call the a single Business object or method when needed.
Future architecture changes
As the product continued to grow, other changes are seen as necessary even though they haven’t yet been implemented.Separation of the Controller from the Business layer
A few of the business objects were for the Controller only and the rest of the business objects are for the ViewModel only. Since the Controller and Business layers are still in the same dll, this doesn’t yet matter. However, it was becoming clear as the project grew that the Controller has its business and the ViewModel/functionality had it Business and there is little overlap if any. It is likely that the Controller and Business layer will see a separation and decoupling where the Controller no longer references the Business layer and the business classes used by the Controller is just part of the Controller.
View communication with the DataContext without binding
There arose instances where binding was not supported or did not exist. In many cases we used attached properties or an inherited object and added the missing bindings, however, in some instances this didn’t make sense. What if the View needed to send a message to the DataContext or pass and event to the code behind and neither inheriting the object to add the binding or using an attached property made sense. What made sense was an interface.I recently posted an article on Creating an Interface for data binding in Views with WPF. Imagine a new layer that exists between the View and the ViewModel called IViewModel. Both the View and the ViewModel reference it and they still don’t reference each other. An interface in the IViewModel project/dll would mainly include properties that help the ViewModel know what is needed for binding. However, in such rare circumstances that it makes sense to communicate to the DataContext, the View can check if the DataContext implements an interfaces and calls a method the interface defines.
Comments
Post a Comment