The Android framework provides a lot of flexibility in deciding how to organize and architect an Android app. While this freedom is very valuable, it can also lead to apps with large classes, inconsistent naming schemes, as well as mismatching or missing architectures. These types of issues can make testing, maintaining and extending your apps difficult.
Thus, the Model-View-Presenter, a.k.a MVP, architecture pattern is here to the rescue.
How it is used to be: MVC Pattern
Before we shift our focus on this awesome advancement, let's just have a quick review on the classic Model-View-Controller architecture used in Android:
Model - the data layer, responsible for managing business logic and network or database API
View - the UI layer, visualization of the data from the Model
Controller - the logic layer, gets notified of the user’s behavior and interactions, and updates the Model as needed
The Model is represented by the Object classes used in the application. The View are responsible for displaying the data from the Models into layouts, fragments or lists. The Controller is responsible for handling user interactions, updating the view and updating the model for changes.
Both the View and Controller depend on the Model: the Controller update the data and the View get the data. When integrated in an application, the Models are the Objects, the Android Activities served as the Controller which is responsible for inflating or setting-up the views and loading and updating the data from the Model, and also be the handler for the user interactions across the views of the application.
Noting the difference: Active vs. Passive Model
When the Controller is the only class that manipulates the Model, it is commonly known as the Passive MVC Model. The Controller has to modify the Model based on the action of the user. The Controller will then notify the View that it needs to be updated and so the View will request data from the Model.
On the other hand, when the Controller is not the only class that modifies the Model, the Model needs a way to notify the View and other linked class about the updates. This is known as the Active MVC Model. It is achieved with the help of the Observer. The Model has a collection of observers that are interested in updates. The View has to implement the observer interface and registers as an observer to the Model, so whenever the Model is updated, it will also iterate through the collection of observers and call the update method. The implementation of this method in the VIew will then trigger the request of the latest data from the Model.
Class structure and behavior of the Active MVC model
The Controller (Activity) will be responsible for setting up the View and providing data from the Model to the View:
String firstName = userModel.getFirstName();
String lastName = userModel.getLastName();
nameTextView.setText(lastName + “, ” + firstName);
This means that it would be the View’s responsibility for handling the UI logic, but this makes the UI logic impossible to unit test.
Another approach is to have the Model expose only the data that needs to be displayed, hiding any business logic from the View, but now the Model will be handling both business and UI logic. It can be unit tested but the Model ends up being implicitly dependent on the View.
String name = userModel.getDisplayName();
Introduction to Model-View-Presenter
MVP is a user interface architectural pattern engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic.
It's fundamental parts are, as you might have guessed it, the model, the view, and the presenter. The model is an interface defining the data to be displayed or otherwise acted upon in the user interface. The view serves as a passive interface that displays data (the Model) and routes user commands (events such as click, drag, etc.) to the presenter to act upon that data, while the presenter acts upon the model and the view; it retrieves data from repositories (the Model), and formats it for display in the view.
Using Model-View-Presenter in Android
In Android developer perspective, the Presenter is responsible to act as middleman between the View and the Model. It retrieves data from the Model and returns it formatted to the View, but unlike MVC, it also decides what happens when the user interacts with the View. The View, usually implemented by an Activity, will contain a reference to the presenter. The only thing that the View will do is to call a method from the Presenter every time there is an interface action. The Model will serve as the gateway to the domain layer or business logic. We can take the Model as the data provider when we want to display data to the View.
The main objectives of this architectural pattern is to increase the separation of concerns in every Android project, to ensure the isolation between the three parts: View and Model cannot communicate directly, therefore, the Presenter intermediates all relations among the parts, and to easily facilitate UI and Unit testing because of the separations
To easily define what the different roles of the three primary components have in Android development, I've provided some key point for each below:
- This layer consists of components responsible for functionalities such as fetching, generating, storing and exposing data.
- The functionalities should be performed on the background thread as they can be time consuming and hence can potentially block the main UI thread.
- Any data fetched or generated in the Model layer is usually returned to the Presenter via callbacks.
- The one responsible for displaying data given to it from its presenter and passing user interactions and inputs to its presenter.
- Each View should ideally have a single Presenter.
- The View should use its Presenter’s interface to communicate with its Presenter so that it is decoupled from any specific implementation of its Presenter and can be tested in isolation.
- The View, ideally, should be lean and have no business logic. It should get data only via its Presenter and not directly from the Model layer.
- In relation to Android, the View can be an Activity, Fragment or Android View.
- The View should notify its Presenter about its background and foreground lifecycle so that its Presenter can reference/unreference the View properly to prevent memory leaks and rendering exceptions. For Activity or Fragment, the Presenter is notified usually from their onResume() and onPause() methods.
- Acts as a controller and sits in the middle between the View and the Model layer.
- Should ideally be paired with a single View.
- Should use its View’s interface to communicate with it’s View so that it is decoupled from any specific implementation of its View and can be tested in isolation.
- Is responsible for calling the Model layer for the data usually at the request of its View and receive that data via callbacks.
- Calls relevant methods in its View to display data.
- Handles any additional business logic and data processing that needs to be done before displaying the data. Any time consuming processing should be done on a background thread.
- Ideally, it should only contain standard Java code and specifically not contain any Android framework code so that it can be reused for other types of views and can be tested easily without an Android device.
- The Presenter should also be notified about its View lifecycle such as whether the VIew is in foreground or background, so that the Presenter can reference/unreference its View. This helps to prevent memory leaks by allowing the View to be garbage collected. In relation to Activity or Fragment, the Presenter can be notified about their lifecycle from their onResume() and onPause() methods. The Presenter should also check if its View is referenced and not null before calling any View method to prevent any exception.
Tale of the Tape: MVC versus MVP
To further emphasize the difference between Model-View-Controller and Model-View-Presenter , let their pros and cons speak in behalf of each architecture pattern.
- Controllers are behavior-based and can share multiple Views
- View can communicate directly with the Model
The Controller accesses the Model and passes it to the View, as well as handle the user interactions on the View
- The View is more separated from Model
- The Presenter is the mediator between the Model and the View.
- Easier to create unit tests
- One to one mapping for View and Presenter, but it is possible to use multiple Presenter for complex Views
The project structure for the two architectural pattern is quite different. In MVC pattern, the folders are distributed according to type, which means all Activities are grouped together and also all adapters, models, fragments, etc. Meanwhile, in MVP pattern, each user “screen” activity has its own folder and all components of the user “screen” which includes the view, user interactions and all business logic are grouped together. In this way, UI and unit testing would me much easier.