Teeps

An Introduction to Model-View-Presenter

14 August 2015 by Daniel Sprowls

9ce61261faeff968d703832523980c76eb61c1b6

Model-view-presenter (MVP) is a software architectual pattern used in web, mobile, and other domains that incorporate UI. MVP aims to remove business logic from the UI and Model classes, making code more readable and easier to understand. It evolved from the more commonly used pattern, model-view-controller (MVC), in the early 1990s and because of this it is similar in design.

So before we get into any examples, let’s define each component.

Model View presenter diagram
Model View presenter diagram

The model is an interface for the data to be displayed in the UI. This is identical to what a model is in MVC.

The view is an interface that is used to display the data stored in the model. The view will usually have some form of listener to obtain user input and direct that to the presenter.

The presenter is the middle man between the view and any models necessary for logic. Typically there is a single presenter for each view. The view will notify the presenter when a certain user input occurs and the presenter will then obtain any data necessary from any models, format it into exactly what the view needs, and ship it to the view.

Android almost seems designed around closely coupled data and UI considering how activities and fragments can so easily merge both. MVP allows us to decouple this by utilizing interfaces between the view and the presenter. Because of this we can then create test presenters that pull their data from test sources as long as we implement the view’s interface. This makes unit testing very clean and easy to implement.

Let’s go through a simple example.

First we define a standard activity that will act as our view. Notice that the activity implements the interface ExampleView.

public class ExampleActivity extends Activity implements ExampleView {

   // ...

   private ExamplePresenter examplePresenter;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       // ...

       examplePresenter = new ExamplePresenterImpl(this);

       addButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {

               // ...

               examplePresenter.addValuesClicked(valueOne, valueTwo);
           }
       });
   }

   @Override
   public void displayAddedValues(String addedValue) {
       totalView.setText(addedValue);
   }
}

This is the interface for our view. Here we define all necessary methods that will need to be called to update any UI.

public interface ExampleView {
   void displayAddedValues(String addedValue);
}

Next we will define what methods the presenter will need to compute any logic necessary for the view through another interface.

public interface ExamplePresenter {
   void addValuesClicked(float valueOne, float valueTwo);
}

The presenter class then implements its interface and performs the necessary logic. Notice how the presenter formats the data before returning it to the view.

ExamplePresenter {

   private ExampleView exampleView;

   private ExampleModel exampleModel;

   public ExamplePresenterImpl(ExampleView view) {
       this.exampleView = view;
       this.exampleModel = new ExampleModel();
   }

   @Override
   public void addValuesClicked(float valueOne, float valueTwo) {
       exampleView.displayAddedValues(String.valueOf(valueOne + valueTwo));
   }
}

The downside to MVP is that it can take some time to fully implement and separate all of the components. This con is made up for during testing and larger projects especially benefit from it due to the its organized nature.

Removing the logic from the UI in Android development can be challenging which is why the MVP pattern is so appealing. MVP allows us to decouple views and models by forcing them to communicate through interfaces and can help shrink the sizes of classes throughout a project. Because of these well separated layers it is also easy to swap out necessary components with ones built specifically for testing. This speeds up the testing process and grants cleaner code and a faster testing phase.

Let's build your next big thing.

Contact Us