Introduction to the Model View Presenter Pattern for Android

When creating software applications, separating our code into smaller, simpler units helps in maintaining the codebase, making it easier to understand and thus quicker to make future changes.

When creating an Android application, there isn't a forced way on how to structure one's application as is the case with iOS development. The developer creates an Activity from which all the application logic can be housed, including responding to user interaction, making service calls, accessing the phone's various storage media, etc. This often results in very large Activity files, which are hard to understand (even for the developer who wrote it), and therefore difficult to change.

To simplify the complexity of having all the application functions in one file, one can start separating the different functions of the application into separate modules (which can be classes, layout files, etc.). A design pattern that is often used by Android developers in carefully separating or modularizing their Activity code is the Model View Presenter pattern. The pattern consists of three elements:

  • The View handles user interaction: how information is displayed to the user, and how information is received from the user. It is not concerned with where that information comes from, or where it is finally stored. Within and Android application, an Activity is an example of a view.

  • The Model handles data storage. This can either be temporary data storage, such as state held by objects in the application, or more permanent data storage, such as shared preferences or services that call an API.

  • The Presenter glues these pieces together and handles the application logic. This handles receiving information from user interactions from the view, transforming it if necessary, and persisting it within the model mentioned above. It also retrieves data from the model, and gives it to the view for displaying to the user.

How might this look in practice?

First of all, imagine the case of creating an app that displays a library of books. Let's start with the presenter that coordinates all the other pieces of the pattern:

public class BookListPresenter {  
    private BookListView view;
    private BookStore store;

    BookListPresenter(BookListView view, BookStore store) {
        this.view = view;
        this.store = store;
    }

    initializeView() {
        List<Book> bookList = store.getAllBooks();
        view.displayBooks(bookList);
    }
}

Here, a class outlining the presenter has been created which takes in the view (which is an interface), and the model which is represented by the BookStore object. When the presenter initializes the view (represented by the initializeView() method), it gets the data from the model, and passes it to the view for storage.

One may ask why we don't pass in the Activity directly as a view, and instead use an interface? Because the presenter is only concerned with coordinating the view and the model, it shouldn't need to know how the data is displayed to the user. So, instead of using an Activity, we could use a Fragment, and the presenter shouldn't need to change if we change the implementation of the view. The information about how it is implemented (e.g. whether it is an Activity or a Fragment) is hidden by whatever implements the BookListView interface. (Read more about the Dependency Inversion Principle here.

Now to the view.

The interface of the view can look as follows:

public interface BookListView {  
    void displayBooks(List<Book> books);
}

As we said, the Activity in Android can represent the view. This can look as follows:

public class BookListActivity extends AppCompatActivity implements BookListView {  
    private BookListPresenter presenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book_list);

        BookListStore store = BookListStore.instance();
        presenter = new BookListPresenter(this, store);
        presenter.initializeView();
    }

    @Override
    public void displayBooks(List<Book> books) {
        // do the things here to display the books.
    }
}

Within the onCreate hook of the activity, the presenter is created, passing in the activity as the view, and the store. After creation, control of the application is then given to the presenter by calling the initializeView() method of the presenter. The presenter will then call the methods on the view that it needs to fulfill the application logic, such as the displayBooks method.

When handling user interaction, the implemented listener (such as the OnClickListener of a button) gives control to the presenter again by calling a method on the presenter to handle the user interaction.

Using this MVP design pattern to structure the code, it becomes easier and simpler to make changes to the code. When one wants to change how data is presented to the user (e.g. colour), there is one place to change it. When one wants to change how data is stored and retrieved, they can go to the Model without being confused by other logic that has nothing to do with the storage and retrieval of data. Lastly, when one wants to change the actual application logic, they can look within the presenter without being overwhelmed by the details such as the changing of colours the user sees, and REST service calls.

Patrick Kayongo

I create and maintain software. Pan-African.

Johannesburg, South Africa