This page describes the principle of Model-View-Presenter (MVP) and how to use Mosby to create MVP based applications.
- The model is the data that will be displayed in the view (user interface).
- The view is an interface that displays data (the model) and routes user commands (events) to the Presenter to act upon that data. The view usually has a reference to its Presenter.
- The Presenter is the “middle-man” (played by the controller in MVC) and has references to both, view and model. Please note that the word “Model” is misleading. It should rather be business logic that retrieves or manipulates a Model. For instance: If you have a database storing
Userin a database table and your View wants to display a list of users, then the Presenter would have a reference to your database business logic (like a DAO) from where the Presenter will query a list of Users.
A concrete workflow of querying and displaying a list of users from a database could work like this:
The workflow Image shown above should be self-explaining. However here are some additional thoughts:
Presenteris not a
Viewis responsible for handling user input and invoking the corresponding method of the Presenter. Why not eliminating this “forwarding” process by making the
OnClickListener? If doing so the Presenter needs to have knowledge about views internals. For instance, if a View has two buttons and the view registers the
OnClickListeneron both, how could the
Presenterdistinguish which button has been clicked on a click event (without knowing views internals like the references to the button)? Model, View and Presenter should be decoupled. Furthermore, by letting
OnClickListenerthe Presenter is bound to the android platform. In theory the Presenter and business logic could be plain old java code, which could be shared with a desktop application or any other java application.
Viewis only doing what the
Viewto do like you can see in step 1 and step 2: After the user has clicked on the “load user button” (step 1) the view doesn’t show the loading animation directly. It’s the Presenter (step 2) who explicitly tells the view to show the loading animation. This variant of Model-View-Presenter is called Passive View. The view should be as dumb as possible. Let the Presenter control the view in an abstract way. For instance: Presenter invokes
view.showLoading()but Presenter should not control view specific things like animations. So Presenter should not invoke methods like
- By implementing MVP Passive View it’s much easier to handle concurrency and multithreading. Like you can see in step 3 the database query runs async an the Presenter is a Listener / Observer and gets notified when data is ready to display.
MVP on Android
So far so good. but how do you apply MVP on your own Android app? The first question is, where should we apply the MVP pattern? On an Activity, Fragment or a ViewGroup like a RelativeLayout? Let’s have a look at the Gmail Android tablet app:
From our point of view, there are four independent MVP candidates on the screen. With MVP candidate we mean UI element(s) displayed on the screen that logically belongs together and therefore can be seen as a single UI unit where we could apply MVP.
It seems that Activities and especially Fragments are good candidates. Usually a Fragment is responsible to just display a single content like a ListView. For example
InboxView, controlled by an
InboxPresenter which uses
MailProvider to get a List of
Mails. However, MVP is not limited to Fragments or Activities. You can also apply this design Pattern on
ViewGroups like shown in
SearchView. In many apps Fragments are good MVP candidates. However it’s up to you to find MVP candidates. Just ensure that the view is independent so that one Presenter can control that View without getting in conflict with another Presenter.
Why should you implement MVP?
How would you implement the inbox view in a traditional Fragment without MVP to display a list of mails that needs to be merged from two sources like a local sql database (on your device) and an IMAP mail server connected over internet. How would your code of the fragment looks like? You would start two
AsyncTasks and have to implement a “wait mechanism” (wait until both tasks have finished) to merged the loaded data of both tasks to a single list of mails. You also have to take care of displaying a loading animation (ProgressBar) while loading and replace that one with a ListView afterwards. Would you put all that code into the Fragment? What about errors while loading? What about screen orientation changes? Who is responsible to cancel
AsyncTasks? This kind of problems can be addressed and solved with MVP. Say goodbye to activities and fragments with 1000+ lines of spaghetti code.
But before we dive deeper in how to implement MVP on Android we have to clarify if an Activity or Fragment is a
View or a
Presenter. Activity and Fragment seems to be both, because they have lifecycle callbacks like
onDestroy() as well as responsibilities of View things like switching from one UI widget to another UI widget (like showing a ProgressBar while loading and then displaying a ListView with data). You may say that these sounds like an Activity or Fragment is a Controller. However, we came to the conclusion that Activity and Fragment should be treated as part of a (dumb) View and not as a Presenter. You will see why afterwards.
With that said, we want to introduce
Mosby a library for creating MVP based apps on android.
Some people find it hard to understand what the Presenter exactly is if you try to explain that MVP is a variant or enhancement of MVC (Model-View-Controller). Especially iOS developer having a hard time to understand the difference of Controller and Presenter because they “grew up” with the fixed idea and definition of an iOS alike
UIViewController. From our point of view MVP is not a variant or enhancement of MVC because that would mean that the Controller gets replaced by the Presenter. In our opinion MVP wraps around MVC. Take a look at your MVC powered app. Typically you have your View and a Controller (i.e. a
Fragment on Android or
UIViewController on iOS) which handles click events, binds data and observers ListView (or implements a
UITableView on iOS) and so on. If you have this picture in mind now take a step back and try to imagine that the controller is part of the view and not connected directly to your model (business logic). The Presenter sits in the middle between controller and model like this:
Let’s have a look at a concrete example: The example app displays a list of users queried from a database. The action starts when the user clicks on the “load button”. While querying the database (async) a
ProgressBar is displayed and a
ListView with the queried items afterwards.
In our opinion the Presenter does not replace the Controller. Rather the Presenter coordinates or supervises the View which the Controller is part of. The Controller is the component that handles the click events and calls the corresponding Presenter methods. The Controller is the responsible component to control animations like hiding ProgressBar and displaying ListView instead. The Controller is listening for scroll events on the ListView i.e. to do some parallax item animations or scroll the toolbar in and out while scrolling the ListView. So all that UI related stuff still gets controlled by a Controller and not by a Presenter (i.e. Presenter should not be an OnClickListener). The Presenter is responsible to coordinate the overall state of the view layer (composed of UI widgets and Controller). So it’s the job of the Presenter to tell the view layer that the loading animation should be displayed now or that the ListView should be displayed because the data is ready to be displayed.
MvpView and MvpPresenter
The base class for all views is
MvpView. Basically it’s just an empty interface. Later on this page you will see that you define methods for your custom view in your own interface that extends from
MvpView. The interface provides a public API for the Presenter to invoke View related methods. The base class for Presenters is
The idea is that a
MvpView (i.e. Fragment or Activity) gets attached to and detached from his
MvpPresenter. Mosby takes Activities and Fragments lifecycle for doing so (more about that below in “Delegate” section). So initializing and cleaning up things (like canceling async running tasks) should be done in
MvpBasePresenter, a Presenter implementation which uses
WeakReference to hold the reference to the view (which is a Fragment or Activity) to avoid memory leaks. Therefore when your Presenter wants to invoke a method of the view you always have to check if the view is attached to the Presenter by checking
isViewAttached() and using
getView() to get the reference.
Alternatively, you could use
MvpNullObjectBasePresenter class that implements Null Object Pattern for the
MvpView. So whenever
MvpNullObjectBasePresenter.onDetach() gets called the View will not be set to
MvpBasePresenter does. Instead an empty View gets created dynamically by using reflections and gets attached as view to the Presenter. This avoids
view != null checks since either the real view is attached or the null object pattern view is attached that simply does nothing on method invocation.
MvpActivity and MvpFragment
As already mentioned before we treat Activities and Fragments as Views.
MvpView can be used as base classes in your application if you simply want an Activity or Fragment that gets controlled by an Presenter. To ensure type safety generics are used:
MvpActivity<V extends MvpView, P extends MvpPresenter> and
MvpFragment<V extends MvpView, P extends MvpPresenter>
Often you find yourself writing the same things in an app over and over again: Load data in background, display a loading view (i.e ProgressBar) while loading, display the loaded data on screen or display an error message if loading has failed. Nowadays supporting pull to refresh is easy as
SwipeRefreshLayout is part of android’s support library. To not reimplementing this workflow again and again Mosby provides
You can use
MvpLceActivity implements MvpLceView and
MvpLceFragment implements MvpLceView for that kind of view. Both assume that the inflated xml layout contains views with
In the following example (hosted on Github ) we are loading a list of
Country by using
CountriesAsyncLoader and display that in a
RecyclerView in a Fragment.
Let’s start by defining the view interface
Why do I need to define interfaces for the View?
- Since it’s an interface you can change the view implementation. You can simple move your code from something that extends Activity to something that extends Fragment.
- Modularity: You can move the whole business logic, Presenter and View Interface in a standalone library project. Then you can use this library with the containing Presenter in various apps.
- You can easily write unit tests since you can mock views by implement the view interface. One could also introduce a java interface for the Presenter to make unit testing by using mock Presenter objects even more easy.
- Another very nice side effect of defining a interface for the view is that you don’t get tempted to call methods of the activity / fragment directly from Presenter. You get a clear separation because while implementing the Presenter the only methods you see in your IDE’s auto completion are those methods of the view interface. From our personal experiences we can say that this is very useful especially if you work in a team.
Please note that we could also use
MvpLceView<List<Country>> instead of defining an (empty, because inherits methods) interface
CountriesView. But having an dedicated interface
CountriesView improves code readability and we are more flexible to define more View related methods in the future.
Next we define our views xml layout file with the required ids:
CountriesView and starts the
CountriesFragment which implements
CountriesView looks like this:
Not that much code to write, right? It’s because the base class
MvpLceFragment already implements the switching from loading view to content view or error view for us. At first glance the list of generics parameter of
MvpLceFragment may discourage you. Let me explain that: The first generics parameter is the type of the content view (something extending from android.view.View). The second is the Model that is displayed with this fragment. The third one is the View interface and the last one is the type of the Presenter. To summarize:
MvpLceFragment<AndroidView, Model, View, Presenter>
If you want to avoid Fragments in general you can do that. Mosby offers the same MVP scaffold as for Activities and Fragments for ViewGroups. The API is the same as for Activity and Fragment. Some default implementation are already available like
You may be wondering how Mosby can provide the same API for all kind of Views (Activity, Fragment and ViewGroup) without having code clones (copy & paste the same code). The answer is delegation. The methods of the delegates has been named to match the Activities or Fragments lifecycle method names (inspired by the latest AppCompatDelegate from appcompat support library) for better understanding which delegate method should be called from which Activity or Fragment lifecycle method:
MvpDelegateCallback: Is an interface every
MvpViewin Mosby has to implement. Basically it just provides some MVP related methods like
createPresenter()etc. This methods are internally called by
ActivityMvpDelegate: It’s an interface. Usually you use
ActivityMvpDelegateImplwhich is the default implementation. All you have to do to bring Mosby MVP support to your custom Activity is to call the corresponding delegate method from Activities lifecycle method like
onDestroy()etc. and to implement
FragmentMvpDelegate: Same as
Fragments. To bring Mosby MVP support to your custom Fragment all you have to do is the same as shown above for Activities: Create a
FragmentMvpDelegateand call the methods from the corresponding Fragment lifecycle method. Your Fragment has to implement
MvpDelegateCallbackas well. Usually you use the default delegate implementation
ViewGroupMvpDelegate: This delegate is used for
FrameLayoutetc. to bring Mosby MVP support to your custom
ViewGroup. The lifecycle methods are simpler compared to Fragments ones:
onDetachedFromWindow(). The default implementation is
Another advantage of delegation is that you can integrate Mosby in any other third party library or framework. Just implement
MvpDelegateCallback and instantiate a delegate and call the corresponding delegate methods along lifecycle events.
In a perfect world we would get the data (Model) exactly the way optimized for displaying it in our GUI (View). Quite often we retrieve data from a backend over a public API that can’t be changed to fit the needs of your UI. In fact, it’s not a good idea that the backend provides an API depending on your UI because if you change your UI you may also have to change the backend. Therefore you have to transform the model into something your GUI can display easily. A typically example is to load a list of Items, let’s say a List of Users, from a REST json API and display them in a
ListView. In a perfect world with MVP this works like this:
Nothing new here.
List<User> gets loaded and the GUI displays the Users in a
ListView by using
UserAdapter. I’m pretty sure that you have used
Adapter million times before, but have you ever thought about the idea behind
Adapter? Adapter makes your model displayable through android UI widgets. This is the adapter design pattern, hence the name. What if we want to support phones and tablets but both display items in a different way? We implement two adapters:
TabletUserAdapter and we pick the right one at runtime.
That is the “perfect world” scenario. What if we have to sort the user list or display some things that has to be calculated in a more complex (and CPU intensive) way? We can’t do that in
UserAdapter because you will notice scroll performance issues because the hard work is done on the main UI thread. Therefore, we do that in a separated thread. There are two questions: The first is how do we transform the data? Do we take our User class and add some additional fields to User class? Do we override values of the User class?
Let’s assume that our
UserView wants to display the full name and calculates a ranking the list get sorted accordingly:
While introducing a method
getFullname() is ok adding a field
ranking may cause problems, because we assume that
User is retrieved from backend and has no
ranking in it’s json representation. So first it may cause confusion if you look at your json api feed and compare that to our
User class and last but not least ranking will be zero as default value because we haven’t computed the ranking yet. If we would have used an object instead of an integer then the default value would be null and it’s likely that we run into NullPointerException.
The solution is to introduce a Presentation Model. This model is just a class optimized for our GUI:
By doing so we are sure that
ranking is always set to a concrete value and that fullname doesn’t get computed while scrolling the ListView (PresentationModel gets instantiated in separated thread). UserView now displays
List<UserPresentationModel> instead of
The second question is: Where to do that async transformation? View, Model or Presenter? It would be obvious that the View does that transformation because the View knows best how things get displayed on screen.
PresentationModelTransformer is the component that takes a
List<User> and “transforms” that to
List<UserPresentationModel> (adapter pattern, so we have two adapters: one to convert to presentation model and UserAdapter to display them in ListView). The advantage on integrating
PresentationModelTransformer in the view is that the view knows how to display things and could easily internally change between phone and tablet optimized presentation models (maybe the tablet UI has other requirements then the phone UI). However, the big disadvantage is that now the view has to control the async thread and the view state (displaying ProgressBar while transformation is in progress?!?) which clearly is the job of the Presenter. Therefore, it’s not a good idea to let the transformation be part of the View. Including the transformation in the Presenter is the way to go:
As we have already discussed before, the
Presenter is responsible to coordinate the View and therefore the Presenter tells the view to display the ListView after
UserPresentationModel transformation is finished. Also the Presenter has control of all async threads (transformation runs async) and cancels them if needed. By the way: With RxJava you can use operations like
flatMap() to do this transformation painless (regarding threading). If we want to support phones and tablets we could define two Presenters
TabletUserPresenter with different
PresentationModelTransformer implementations. In Mosby the View creates the Presenter. Since the View knows at runtime if the View is a phone or tablet it can choose at runtime Presenter to instantiate (
TabletUserPresenter). Alternatively you could use a single
UserPresenter for phone and tablet and just replace
PresentationModelTransformer implementation i.e. by using dependency injection.