There’s nothing better that having clean modular interdependent code. Following design guidelines definitely does help achieve this. In Android, the MVP and MVVM patterns are very popular, they help having a good architecture in our projects. This article is an attempt by me to explain through a simple example the MVVM pattern along with Data binding. Why Data Binding? Because it enhances the MVVM pattern and makes it even better.
The Android default templates encourages the creation of large activities or fragments. These components typically contain both business and UI logic. This makes testing and therefore the maintenance of Android applications harder. Several patterns are popular within the Android community to improve testability.
The most popular architecture choices are:
- Model View Presenter (MVP)
- Model View View Model (MVVM) together with Android Data Binding
The Model View Presenter architecture for Android
The Model View Presenter (MVP) architecture pattern improve the application architecture to increase testability. The MVP pattern separates the data model, from a view through a presenter.
The following demonstrates an example data flow throw the MVP.
1. The view
A view component in MVP contains a visual part of the application.
It contains only the UI and it does not contain any logic or knowledge of the data displayed. In typical implementations the view components in MVP exports an interface that is used by the Presenter. The presenter uses these interface methods to manipulate the view. Example method names would be: showProgressBar, updateData.
2. The presenter
The presenter triggers the business logic and tells the view when to update. It therefore interacts with the model and fetches and transforms data from the model to update the view. The presenter should not have, if possible, a dependency to the Android SDK.
3. The model
Contains a data provider and the code to fetch and update the data. This part of MVP updates the database or communicate with a webserver.
4. Considerations for using the MVP design pattern
MVP makes it easier to test your presenter logic and to replace dependencies. But using MVP also comes with a costs, it makes your application code longer. Also as the standard Android templates at the moment do not use this approach, not every Android developer will find this code structure easy to understand.
5. Comparison to Model View Controller
In the Model View Presenter pattern, the views more separated from the model. The presenter communicates between model and view. This makes it easier to create unit tests Generally there is a one to one mapping between view and Presenter, but it is also possible to use multiple presenters for complex views.
In the Model View Controller pattern the controllers are behavior based and can share multiple views. View can communicate directly with the model. MVP is currently on of the patterns that the Android community prefers.
The Model View View Model architecture for Android
The Model View View Model design pattern is also known as Model View Binder.
1. The view
A view component in MVP contains a visual part of the application.
The view binds to observable variables and actions exposed by the view model typically using the data binding framework.
The view is responsible for handling for example:
- Menus
- Permissions
- Event listeners
- Showing dialogs, Toasts, Snackbars
- Working with Android View and Widget
- Starting activities
- All functionality which is related to the Android
Context
2. The view model
The view model contains the data required for the view. It is an abstraction of the view and exposes public properties and commands. It uses observable data to notify the view about changes. It also allows to pass events to the model. It is also a value converter from the raw model data to presentation-friendly properties)
The view model has the following responsibilities:
- Exposing data
- Exposing state (progress, offline, empty, error, etc)
- Handling visibility
- Input validation
- Executing calls to the model
- Executing methods in the view
The view model should only know about the application context. the application context can:
- Start a service
- Bind to a service
- Send a broadcast
- Register a broadcast receiver
- Load resource values
It cannot:
- Show a dialog
- Start an activity
- Inflate a layout
3. The model
Contains a data provider and the code to fetch and update the data. The data can be retrieved from different sources, for example:
- REST API
- Realm db
- SQLite db
- Handles broadcast
- Shared Preferences
- Firebase
- etc.
Basically the same as the model in the MVP.
4. Differences to MVP
MVVM uses data binding and is therefore a more event driven architecture. MVP typically has a one to one mapping between the presenter and the view, while MVVM can map many views to one view model In MVVM the view model has no reference to the view, while in MVP the view knows the presenter.
Using build flavours as architectural style to improve testability
One way to improve testability in your application is to use build flavours. In your build flavour you define different classes for providing data.
For example, if you have two flavours ‘prod’ and ‘mock’ you could have the following different implementations in your flavors.
This could be a theoretical implementation for the ‘mock’ flavor:
public class Injection {
public static ImageFile provideImageFile() {
return new FakeImageFileImpl();
}
public static NotesRepository provideNotesRepository() {
return NoteRepositories.getInMemoryRepoInstance(new FakeNotesServiceApiImpl());
}
}
This could be a theoretical implementation for the ‘prod’ flavor:
public class Injection {
public static ImageFile provideImageFile() {
return new ImageFileImpl();
}
public static NotesRepository provideNotesRepository() {
return NoteRepositories.getInMemoryRepoInstance(new NotesServiceApiImpl());
}
}
If you application code you can access the provided implementation via Injection.provideNotesRepository(). Depending which flavor you are build you would receive the mocked version or the real version. Your unit test would build again the mock flavor to mock away the external dependencies.
Using dependency injection as architectural style to improve testability
Dependency injection is another way of building testable applications. Android applications are using in most cases Dagger 2 for dependency injection. In case the tests are running mock or fake objects are injected. If the real application is started the correct objects are injected.
Writing tests for the presenter
Typically the presenter has dependencies, for example to the implementation of the view contract. You mock or fake these dependencies away to unit test the presenter.
For example, to test the presenter we do not need to know if the view displays a dialog or progress indicator. But we want to test that presenter calls a method on the view to display the progress information.
Happy coding….. 🙂