MVP, in a nutshell, is a design pattern that achieves proper layering and separation of concerns of your presentation layer, business logic and data model. Following this design would result in your application being much more maintainable and testable.

This is what MVP looks like in Android:

The View layer, usually an activity or fragment, will be responsible for any interaction or changes happening to the user interface. This layer communicates with the Presenter.  Common scenarios for View-Presenter communications are during changes in its life cycle (e.g. the view was created) or user interactions (a button was clicked).

The Model layer only worries about retrieving the data from the data source and passing this information through to the Presenter.

The Presenter layer controls the View, whether to show a loading spinner while waiting on an asynchronous call to the Model or present requested data, for example.  The Presenter communicates with the Model to retrieve data and then passes it to the View. This class should not contain any references to Android libraries at all.

Google has created an open source repo for examples of different Android architectures and how they compare using a simple to-do app.

screen-shot-2016-09-16-at-8-55-36-am

In a ranking from Low -> Medium -> Very High, MVP rated the lowest in terms of complexity / learning cost.  Out of the samples compared, it is easiest for a developer to learn and implement a Model View Presenter design.

MVP score high in testability of the sample code. This is achieved by decoupling all the layers in the application to remove dependencies and allow testing in isolation.

The Presenter and View layers communicate via interfaces, this binds them to a contract.  This falls in line with the dependency inversion principle of SOLID.

Below is an example of what a contract interface for a Transfers View might look like:

public interface TransferContract {

    interface Presenter extends BasePresenter {                                                

        void fetchFromAccounts();

        void fetchToAccounts();

        boolean validate(Transfer transfer);

        void submitTransfer(Transfer transfer);
 
    }

    interface View extends BaseView {

        void populateFromAccounts(List fromAccounts);

        void populateToAccounts(List toAccounts);

        void showPopUpErrorMessage(String errorMessage);

        void challengeUser();

        void navigateToConfirmTransfer();

    }
}

Here we add all the method signatures that might be needed for the Presenter to tell the View how to behave. Similarly we have all the method signatures that are needed for the View to inform the presenter of interactions like submitTransfers. 

The View and the Presenter will implement the interface of the contract. Dependency injection could be used to give the Presenter a reference of the View and, conversely, the View a reference of the Presenter.  Another method is to create the Presenter during the View’s lifecycle, onCreate() for example, and then pass the View to the Presenter.

“Communication is strictly via the interface and should never be concrete”

Unit Testing

Going with the above architecture would make your code a lot more testable. In addition to higher testability, we are able to test our Presenter without an Android device or emulator like instrumented tests require. 

This is because our Presenter (Which contains most of the “How our View should behave” + Business logic) is completely devoid of any Android-specific code.  By calling and referencing only the contract interface, we are using pure Java and thus giving us the ability to mock any dependencies and test the logic.

Here is an example of what a JUnit test of a Presenter would look like:

@Test
public void presenterCallsFetchFromAccounts_andUpdatesViewWithSuccessfulFromAccounts() {
  presenterUnderTest.fetchFromAccounts();
  verify(view).showLoading();

  verify(accountRepository).retrieveFromAccounts(accountRepositoryCallbackArgumentCaptor.capture());
  accountRepositoryCallbackArgumentCaptor.getValue().successfulFromAccounts(new ArrayList());

  verify(view).hideLoading();
  verify(view).populateFromAccounts(anyListOf(Account.class));
}

With this test, and regardless of what our View looks like, we can verify that this method in the presenter always tells ANY view to show loading.  It calls the model (we’re assuming the model returns results synchronously for the purpose of example), and then hides the loading spinner.

Conclusion:

We hope the above information is convincing enough to persuade you to use this design pattern.  Its all rather simple and straightforward and has the lowest learning curve out of the architecture patterns from Google’s samples.

One downside is that devs will need to create more classes and distribute their code in different places and layers.  Not a bad trade-off for the benefits gained.

MVP also helps us separate the development work between devs or teams.  Once the contract is defined, one dev can work solely on the Presenter and Model while the other focuses on the View.

Image courtesy of Lachlan Hardy

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s