Implementing MVP pattern on Android with MVP Helpers

There are a lot of posts talking about how to correctly implement MVP pattern over Android. So why another one?

Well, I want to tell you my experience developing a library to simplify MVP implementation for those ones who recently start working on Android and are interested in correctness over code.

About 3 months ago or more, I have released MVP Helpers library. MVP Helpers is aimed to provide a simpler way to develop your Android Apps by following a simple series of concepts around MVP and inherit from a set of helper classes.

MVP Helpers started as an abstraction over an application that I was implementing for a Financial Company. After finish the creation of that App, I realize that parts of the code where similar among different Activities and Fragments.

My interest for cleaner code began since I started to work with Android (About 3 years ago). In the old times we use to do much over the Activities, we used to make hard the apps to scale when new features were requested.

Because of that, I read about different patterns like MVC, MVVM and MVP. Every pattern has different pros and cons. I have implemented all of them, but the one I really like was MVP. That pattern let me decouple easily the code, and also refactor different apps faster, was completely easier to reason, and also easier to follow, improve code modularity, and make unit testing so so simpler.

Well, coming back to MVP helpers, the concepts behind my library are similar to MVP and are the following ones:

  • Model → The model is the way that you have to represent your data, and also the way you use to persist it. Examples of this can be a CRUD, Rest Interface.
  • View → The View is an interface that contains methods related to UI interaction. This interface should be implemented inside an Activity/Fragment.
  • Presenter → The presenter acts as a middle man between the Model and the View.
  • Interactor → The Interactor is the class that do the hard work, all the blocking operations like I/O, Networking, Database Interactions should be done here.
Diagram that shows the approach that MVP helpers follow

Usage of MVP Helpers

Well, you have seen the basis around MVP Helpers, now lets go to the code. Follow this steps to get started:

  • Add jitpack in your root build.gradle file at the end of repositories:
allprojects {
repositories {
...
maven {
url "https://jitpack.io"
}
}
}
  • Add the dependency in the app build.gradle file:
dependencies {
compile "com.github.BlackBoxVision:mvp-helpers:v0.2.0"
}
  • Create a View interface by extending from BaseView interface. BaseView acts as a water mark.
public interface DetailsView extends BaseView {

void onInfoReceived(@NonNull String info);

void onInfoError(@NonNull String error);
}
  • Create an Interactor class by extending from BaseInteractor class. When you extend from BaseInteractor you get a few cool methods to simplify dealing with concurrency:
  • runOnUiThread → use it when you need to post data to the main thread.
  • runOnBackground → use it when you need to make background processing.
  • runOnBackground → use it when you need to make a scheduled task.
  • cancelTask → use it when you want to cancel a scheduled task.
public final class DetailsInteractor extends BaseInteractor {

public void retrieveDetailsFromService(String id, OnSuccessListener<String> sListener, OnErrorListener<String> eListener) {
runOnBackground(() -> {
            final String data = Helpers.findSomeDataById(id);

runOnUiThread(() -> {
if (data != null) {
sListener.onSuccess(data);
} else {
eListener.onError("Ups, something went wrong");
}
});
});
}
}
  • Create a Presenter class by inheriting from BasePresenter<View>. BasePresenter<View> gives to you a few fancy methods to deal with view attach/detach and some callbacks attach/detach is performed so you can do an action over it:
  • isViewAttached → check if you have set the view to the presenter, returns to you a boolean value that you should handle in your presenter implementation.
  • attachView → add the view to the presenter, so you can start to handle the cycle of view — presenter — interactor interaction.
  • detachView → dereference the view, setting it to null. This method should be called in the onDestroy method in case of use in Activity, and onDestroyView in case of Fragment usage.
  • getView → simple getter, to make your access to the view defined more cleaner.
  • onViewAttached → callback fired when the view is attached to the presenter, it gives you the view so you can start doing something like restoring state, instantiating the interactor.
  • onViewDetached → callback fired when the view is detached from the presenter, in this place you can dereference the objects you won’t use anymore.
public final class DetailsPresenter extends BasePresenter<DetailsView> {
private DetailsInteractor interactor;

@Override
protected void onViewAttached(@NonNull DetailsView view) {
interactor = new DetailsInteractor();
}

@Override
protected void onViewDetached() {
interactor = null;
}

public void findRequiredInformation(@NonNull String id) {
if (isViewAttached()) {
interactor.retrieveDetailsFromService(id, this::onSuccess, this::onError);
}
}

private void onSuccess(@NonNull String information) {
if (isViewAttached()) {
getView().onInfoReceived(information);
}
}

private void onError(@NonNull String errorMessage) {
if (isViewAttached()) {
getView().onInfoError(errorMessage);
}
}
}
  • Create a PresenterFactory by inheriting from interface PresenterFactory<Presenter>. The PresenterFactory was an specific API design to deal with Activity recreation. MVP Helpers let you not loose your app state by using Android Loader API to deliver Presenter instance.
class DetailsPresenterFactory implements PresenterFactory<DetailsPresenter> {

@Override
public DetailsPresenter create() {
return new DetailsPresenter();
}
}
  • Finally you have to add connect this classes to your Activity/Fragment. To make that you can inherit from BaseActivity/BaseFragment. With this custom Activity/Fragment you don’t have to take care about Presenter creation/destruction.
  • createPresenterFactory → in this method you have to create an instance of PresenterFactory
  • getLayout → in this method you have pass the id reference to the layout.
  • getPresenter → simple getter, to make your access to the presenter more cleaner.
  • onPresenterCreated → In this method you can start doing something with the presenter. ¡Now the View is attached automatically to the Presenter!
  • onPresenterDestroyed → In this method you can do something, like saving app state.
public final class DetailsFragment extends BaseFragment<DetailsPresenter, DetailsView> implements DetailsView {

@Override
protected DetailsPresenterFactory createPresenterFactory() {
return new DetailsPresenterFactory();
}

@LayoutRes
@Override
protected int getLayout() {
return R.layout.fragment_details;
}

@Override
protected void onPresenterCreated(@NonNull DetailsPresenter presenter) {
//Do something when presenter it's created
getPresenter().getInformationFromId("ssdWRGD132");
}

@Override
protected void onPresenterDestroyed() {
//Do something when presenter is removed, this method is called in onDestroy
}

@Override
void onInfoReceived(@NonNull String information) {
Toast.makeText(getContext(), information, Toast.LENGTH_SHORT).show();
}

@Override
void onInfoError(@NonNull String errorMessage) {
Toast.makeText(getContext(), errorMessage, Toast.LENGTH_SHORT).show();
}
}

That’s all the basic to use this library!

Actually I’m working on a better version of this library using annotations processor to avoid the boilerplate part and optimize performance by deleting the usage of Java Generics.

Hope you have enjoyed this post! If you want to know more about it don’t forget to leave a comment!