Going Clean With MVP | A Guide To Model-View-Presenter On Android- 13 mins
Let’s face it! All of us wrote tons and tons of code inside
MainActivity.java, many still do…
Writing code that “works” is fine and acceptable as you start working with a new language or framework. After all, the whole point is to get the work done, right? Not exactly!
We all start from the same place where every “hello world” marks an accomplishment. However, as you grow as an experienced developer, you start to realize that object-oriented programming is more than just writing the code that works.
Almost every project requires some level of testing and maintenance throughout its lifecycle. This makes it a strict requirement to write modular code that is easy to read, modify, test and maintain for future collaborators.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. - John Woods
Obviously, our "I love
MainActivity" guy won’t find this an easy task. Why? Because when you write every single piece of code in the class where it is needed. You end up with a codebase which of course, gets the job done, but makes it almost impossible to test and maintain in the longer run.
MVP is an architectural pattern that attempts to decouple the business logic from the views by providing simpler activities with all the important work behind separate presentation layers. This results in a highly readable, maintainable and most importantly testable code.
Some might argue that MVP is not an architectural pattern per se as it is only responsible for managing the presentation of the data. However, we leave the debate here and move on to the “why?” aspect.
Need for MVP?
Android activities are cluttered with closely coupled components where everything is structured in a “throw the code on the wall” manner. This makes it an intrinsic problem for android code to be hard to test and extend. Anyone who went through the pain of learning android application testing can tell you that in the beginning it almost feels impossible to test android activities due to unmockable (is this even a word?) SDK components and lifecycle management complexities.
When you separate the business logic away from the activity in a separate presentation layer, it automatically makes it trivial to mock and test your code the way you would test any other java class.
The other difficulty apart from code testing is the maintenance of existing codebase. If you are reading this post and understand what I have said so far, I am assuming that you are at that point where you are familiar with the SOLID principles of object oriented design by Robert C. Martin a.k.a Uncle Bob. The last part of the five principles refers to the Dependency Inversion Principle (DIP) which encourages the programmers to write code in a way that it depends upon abstractions instead of the concrete implementations.
The way MVP is implemented nowadays (or at least they way I learned to) is through
Contract interfaces that describes the responsibilities of
Views and the
Presenters, making the maintenance of code as simple as adding a new method to the interface and its implementation in the corresponding class. Note that this decoupling also allows us for interchangeable views for the same business logic.
Now let’s put a full-stop to the theoretical stuff and explore the implementation details of Model, View and Presenter by building a very basic hello world MVP app.
Before we go ahead, it’s important that you understand that there is no “ultimate” or “best” way of implementing MVP. Most people use their own implementations with some modifications, which is completely acceptable as long as the end goal is achieved. Which is to structure your code to decouple the implementation logic from the presentation layer. The way I’m doing it is only the way I like it, if you find another variation of it, don’t confuse and use the style that suits you.
Model is an interface responsible for managing data. Model’s responsibilities include using APIs, caching data, managing databases and so on. The model can also be an interface that communicates with other modules in charge of these responsibilities.
For the sake of simplicity, I’m not using any model classes in this example but I hope you got the idea.
Do not confuse this with your
XML views. Views in MVP are simply the components responsible for managing the user interface. This includes all the UI manipulation operations such as setting text to some
TextView, toggling visibility of
Views, displaying animations etc. Basically, everything that has to do with the User Interface, goes into this place.
Keep your views as dumb as possible.
The idea is to keep your
Presenters unaware of “how” to present data to the user. All they have is a
View instance that takes this data as input and performs the presentation tasks. So if you were to display an error to the user in case he forgets to fill a field in the form, all your presenter has to do is call the
view.displayError(errorMessage) method on the
Now realize that the
Presenter doesn’t know what happens next, whether the error is displayed as a
Toast, or as a
Dialog or a
Snackbar or what color is the message etc. The
View on the other hand does not know anything about the data it is provided and its origins, it is only interested in accepting the supplied data and manipulate the UI accordingly. This makes it very easy to mock
Views while testing your business logic so you can focus on the stuff that is important.
The way I like to define my
Views is through a View interface which resides inside the Contract Interface for that particular activity.
Now all I have to do is create a new class and make it implement this interface and we have a candidate that can serve as View for our activity. I guess you might have guessed that we can provide multiple implementations of View as well for different use cases.
Think of the presenters as the Boss here. Similar to how you used to manage everything from your activity in the
I Love MainActivity era, Presenters now handles all the management tasks and keeps your activities/fragments less busy. So instead of throwing your
PeanutButterMaker and instances of whatnot in the activity class and make it look like a huge pile of crappy code, you just provide it with the
Presenter instance and place all the other important stuff inside your
Now just like the Views, presenters are also defined through a child interface inside the contract interface of the activity that owns it.
Now all I need to do is to make my activity/fragment implement this interface and provide implementations for the defined operations.
So you might be wondering what did we achieve apart from dividing our activity into 3 pieces?
The first benefit of using this approach is that we achieved a more modular and scalable architecture. If you were to add subtract functionality to this activity, all you would do is define a new method
void performSubtraction(String numberOne, String numberTwo) in the
Presenter interface and provide its implementation. Your contracts are the documentation for your code itself.
The second and most important change is that our activity is now fully testable. You could simply mock the View and test all the application logic using your
Presenter. Below are a couple of tests for the activity we implemented earlier. I’m using
Mockito for mocking dependencies.
At this point, it may make sense to your or it won’t, but sooner or later, you’ll realize that you need some level of modularization in your code if it requires proper testing and be able to remain maintainable for long-term. If not MVP, you might go with one of the several other architectural patterns that are available. For me, MVP makes more sense than any other in the context of Android.
Image rights belong to macoscope.