The flexibility of Android allows you to design application the way you feel comfortable. It gives developers both significant power to create great apps and issues with the difference in approach. So, the need to use some architecture pattern is obvious.

MVP (Model View Presenter) pattern is a derivative from the well known MVC (Model View Controller), which is gaining popularity and importance in the development of Android applications. We set out to determine the main reasons why we can and should use this architectural pattern.

First of all, we need to define the difference from the MVC pattern, and we can show it schematically:

The main differences of MVP from MVC are:

View is separated from Model , Presenter is an intermediary between View and Model;

is separated from , is an intermediary between View and Model; easier to create Unit tests;

tests; usually, we are able to use several Presenters for complex Views.

Let’s look at each item in details, and highlight its main advantages:

Following one of the main concepts of Clean Architecture, “Divide and rule”, the MVP pattern allows to separate the presentation layer from the logic. In this case the main functions of each element are:

The View. Activity or fragment will be deprived of data processing and just display. For example, a fragment here implements a certain interface with functions:

public interfece ListInterface { void showError(); void showItems(List<Object> someItems); } 1 2 3 4 5 6 public interfece ListInterface { void showError ( ) ; void showItems ( List < Object > someItems ) ; } The Presenter takes a full charge of business logic. Requests for obtaining data from a server or database (communication with the model) are implemented here. After receiving the data, all data processing is also on the presenter. After processing, the information is passed to the view through the same interface: //If the result is a mistake getView.showError(); //If the result is successful - we pass the data getView.showItems(someitems); 1 2 3 4 5 6 //If the result is a mistake getView . showError ( ) ; //If the result is successful - we pass the data getView . showItems ( someitems ) ; This process is displayed on the scheme below: Unit tests coverage. The main advantage is the ability to test each part separately. We can also select the unit testing technology and approach.

For the view it is convenient to use Mockito, Robolectric with annotations @Before, @Test, @After. Example: @Before public void setUp() { TestHelper.getTestClassInjector() .inject(this); Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache); Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit); Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP); } @Testpublic void testWebPage() { viewModel.loadWebPage(SOME_URL) .toBlocking(). forEach(s -> { Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)& & s.contains(SOME_URL)); }); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @ Before public void setUp ( ) { TestHelper . getTestClassInjector ( ) . inject ( this ) ; Assert . assertTrue ( TestHelper . getBaseComponent ( ) . getLocalDataCache ( ) instanceof MockLocalDataCache ) ; Assert . assertTrue ( TestHelper . getBaseComponent ( ) . getRetrofit ( ) instanceof MockRetrofit ) ; Assert . assertTrue ( TestHelper . getBaseComponent ( ) . getOkHTTP ( ) instanceof MockOkHTTP ) ; } @ Testpublic void testWebPage ( ) { viewModel . loadWebPage ( SOME_URL ) . toBlocking ( ) . forEach ( s -> { Assert . assertTrue ( s . contains ( MockRetrofit . MOCKED_STRING ) & & s . contains ( SOME_URL ) ) ; } ) ; }

it is convenient to use with annotations @Before, @Test, @After. Example: We will test the presenter the same way we tested the model, with a simple JUnit test. However, this time, we will provide a modified view to make sure the presenter is correctly linked to the view.

Our presenter will get the view and will receive data from the model to display it in the view. @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(interactor.getUserProfile()).thenReturn(Observable.just(newUserProfile())); presenter = new ProfilePresenter(interactor);presenter.attachView(view); } @Test public void testDisplayCalled() { verify(interactor).getUserProfile(); verify(view).display(any()); } public void fetchAndDisplay() { interactor.getUserProfile().subscribe(userProfile -> view.display(userProfile)); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @ Before public void setUp ( ) throws Exception { MockitoAnnotations . initMocks ( this ) ; when ( interactor . getUserProfile ( ) ) . thenReturn ( Observable . just ( newUserProfile ( ) ) ) ; presenter = new ProfilePresenter ( interactor ) ; presenter . attachView ( view ) ; } @ Test public void testDisplayCalled ( ) { verify ( interactor ) . getUserProfile ( ) ; verify ( view ) . display ( any ( ) ) ; } public void fetchAndDisplay ( ) { interactor . getUserProfile ( ) . subscribe ( userProfile -> view . display ( userProfile ) ) ; }

Independence from the life cycle of the application. A case in point is when we make a request and a user folds an app, or changes the screen’s orientation. Our query is not related to the activity and doesn’t fail, the data can be obtained, and displayed when the view changes the state to inResume() again. Null Activity check is necessary: if (getActivity != null) { // working with ui… getView.showResult(result); } 1 2 3 4 5 6 if ( getActivity != null ) { // working with ui… getView . showResult ( result ) ; }

Ability to use one presenter by multiple views. When we use the same logic for several screens, e.g. receiving and updating a list of messages, we can use just one presenter containing all the logic for these two views.For example, there is a presenter and 2 fragments of receiving messages: MessageUpdatePresenter;

SentMessagesFragment implement MessageUpdatePresenter;

DraftsMessagesFragment implement MessageUpdatePresenter; In each fragment we implement the interface MessageUpdatePresenter, let it be the method showMessages(List <Message> messages). During the development of Android application for a major German marketing company, we were challenged to create the architecture of a multifunctional complex app. After discussing this with the team, we settled on using MVP, and it allowed us: to separate business logic from presentation, structurize everything and divide the load;

to considerably increase the quality of the product with the help of convenient test coverage, which is much easier and faster to write;

to decrease the number of repetitions in the code, since the presenter can be reused.

About Redwerk

Redwerk has been in mobile application development business since 2005. For the last thirteen years, we successfully developed many iOS and Android apps that gathered hundred thousands of users all over the world. We provide full-cycle development of mobile apps from idea to launch and guarantee high-quality solutions for our customers.