Android MVP basics with sample app

Sagar Nilesh Shah
AndroidPub
Published in
7 min readApr 3, 2017

--

There are two de-facto patterns for architecting an Android app — MVP (Model-View-Presenter) and MVVM (Model-View-ViewModel). My article focuses on MVP as it is more mature, since it has been around for a while. There are many articles on how to architect an Android app using MVP pattern. My article uses them as a reference to provide basic understanding of the MVP pattern with a sample app.

Why architect anything?

It is always a good practice to think about code architecture. An optimal architecture pays attention to the following core principles:-

  • Single Responsibility Principle: As the name suggests, a component , such as a class, should be responsible for only one single task. This makes the code more maintainable and hence readable.
  • Dependency Injection Principle: A fancy term that simply means a component, such as as a class, should not seek or create any external components (dependencies) on its own and must rely on its container to provide it with its dependencies. This decoupling makes the code more testable and extensible.

Android as a system doesn’t enforce the above two core architectural principles. It doesn’t enforce decoupling of the UI component, such as an Activity, and the corresponding business logic that populates the UI component with data. This means you can end up with a problematic Activity, like the one below, that is difficult to test and manage!

The fact that Android does not enforce the above architectural principles, does not make it flawed! Android simply delegates the task of architecting the apps well to the app creator.

How do I architect?

This is where MVP architectural pattern shines. MVP enforces both the Single Responsibility Principle and Dependency Injection Principle.

MVP stands for Model, View and Presenter. I am going to explain this pattern with the help of a sample app I created.

The sample app fetches and displays the interesting photos and their comments for the most recent day from the Flickr API

The Model

  • The Model is a layer that consists of components responsible for functionalities such as fetching, generating, storing and exposing data.
  • These 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.

In the context of the sample app, these functionalities are assigned to relevant components as follows:-

Fetching/Generating data:-

  • RemoteDataSource: the class for fetching data from Flickr API on a background thread and returning data via callbacks on the main UI thread.
  • LocalDataSource: the class for fetching data from a local SQLite DB on a background thread and returning data via callbacks on the main UI thread.

Storing data:-

  • LocalDataSource: the class for storing data into a local SQLite DB on a background thread.
  • Photo: a class to store photo data.
  • Comment: a class to store comment data.

Exposing data:-

  • DataSource: the interface that exposes fetching and storing data through helper methods. This is to be implemented by all data sources such as the above RemoteDataSource and LocalDataSource.
  • DataRepository: the primary class for any Presenter to interact with for fetching and storing data. It is the middleman in front of all data sources such as RemoteDataSource and LocalDataSource and delegates the work to them depending on conditions such as network availability, etc.

The View

  • The View is a component responsible for displaying data given to it from its Presenter and passing user input to its Presenter.
  • Each View should ideally have a single Presenter.
  • The View should use itsPresenter’s interface to communicate with its Presenter so that it is decoupled from any specific implementation of itsPresenter 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 a 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.

In the context of the sample app, the following are the relevant View components:-

  • MainActivity: the container class responsible for rendering the relevant Fragment and managing global state. This is based on the Fragment Oriented Architecture (FOA) which is outside the scope of this blog. One benefit of using Fragment is that it can easily preserve state on configuration changes such as screen orientation. I do plan on writing a post about FOA in the future. Happy to discuss more about it on the side :)
  • PhotoFragment: the Fragment that receives photo data from its PhotoContract.Presenter, which is implemented by thePhotosPresenter, and renders a list of photos and also handles user actions, such as clicks on photos, and passes it to the PhotoContract.Presenter.
  • PhotosRecyclerAdapter: the Adapter that renders and populates each photo in the photos list.
  • PhotoContract.View: the interface that exposes functionalities of the view, PhotoFragment, to be used by the view’s Presenter.
  • PhotoDetailFragment: the Fragment that receives photo data from the PhotosFragment on its creation and comment data from its PhotoContract.Presenter. It eventually renders the photo and its list of comments.
  • CommentsRecyclerAdapter: the Adapter that renders and populates each comment in the comments list.
  • PhotoDetailContract.View: the interface that exposes functionalities of the view, PhotoDetailFragment, to be used by the views’s Presenter.

The Presenter

  • The Presenter acts as a controller and sits in the middle between theView and the Model layer.
  • Each Presenter should ideally be paired with a single View.
  • The Presenter should use its View’s interface to communicate with its View so that it is decoupled from any specific implementation of its View and can be tested in isolation.
  • The Presenter is responsible for calling the Model layer for data usually at the request of its View and receive that data via callbacks.
  • The Presenter calls relevant methods in its View to display data.
  • The Presenter 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.
  • The Presenter, ideally, 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.

In the context of the sample app, the following are the relevant Presenter components:-

  • PhotosPresenter: the Presenter responsible for PhotosContract.View which is implemented by PhotosFragment. It fetches photo data by calling DataRepository at the request of its PhotoContract.View and delivers that data back to its PhotosContract.View. The Presenter also calls other relevant PhotosContract.View methods such as for showing/hiding progress bar and for showing Toast messages. The Presenter subscribes to itsPhotosContract.View lifecycle by allowing its PhotosContract.View to call its own onViewActive() and onViewInactive() to reference/unreference its PhotosContract.View. The Presenter also checks if its PhotosContract.View is active and not null before calling any of its PhotosContract.View methods.
  • PhotosContract.Presenter: the interface that exposes functionalities of the presenter, PhotosPresenter, to be used by the presenter’s View
  • PhotoDetailPresenter: the Presenter responsible for PhotoDetailContract.View which is implemented by PhotoDetailFragment. It fetches photo data by calling DataRepository at the request of its PhotoDetailContract.View and delivers that data back to its PhotoDetailContract.View. The Presenter also calls other relevant PhotoDetailContract.View methods such as for showing/hiding progress bar and for showing Toast messages. The Presenter subscribes to its PhotoDetailContract.View lifecycle by allowing its PhotoDetailContract.View to call its own onViewActive() and onViewInactive() to reference/unreference its PhotoDetailContract.View. The Presenter also checks if its PhotoDetailContract.View is active and not null before calling any of its PhotoDetailContract.View methods.
  • PhotoDetailContract.Presenter: the interface that exposes functionalities of the presenter, PhotoDetailPresenter, to be used by the presenter’s View.

Folder Structure

Choosing a relevant folder structure for an app is important as it is the first step to architecting an app properly. A relevant folder structure acts as a guide and reference for a particular architecture as you develop the app.

In the context of the sample app which is using the MVP architectural pattern, the following is a relevant folder structure:-

  • data/: contains the components that make up the Model layer. This includes any class and interface that is responsible for fetching, storing and exposing data.
  • ui/: contains the Views and Presenters. They are usually grouped by feature/screen.
  • ui/photos/: contains Fragment, Presenter, Adaper and interface responsible for displaying a list of photos and handling user input on the photos screen.
  • ui/photodetail/: contains Fragment, Presenter and Adapter responsible for displaying a photo and its comments on the photo detail screen.
  • util: contains generic base and helper components to be used across the project.

Conclusion

This article is based on my interpretation of the MVP pattern. There are articles that state that MVP pattern is solely for the presentation layer based on the Clean Architecture pattern. I have read about the Clean Architecture pattern and though I believe that it is a more powerful concept, I also think that it can be complex to start off with. I think being able to refactor or create an app based on the MVP pattern is taking a step in the right direction and a good stepping stone towards Clean Architecture pattern.

I hope you enjoyed the article and found it useful. I do want to level-up as an Android Engineer so I am constantly researching and learning about different constructs everyday.
If you have any feedback or suggestion, please do comment below.
Any criticism is highly appreciated :)

References

--

--

Sagar Nilesh Shah
AndroidPub

Android + Full-stack | Tech | Sports | EDM | Diving | Travel | Food