MVP: An Android implementation using RxJava2

From the time Android was first presented to the world, developers were taught to work with the View-Model architecture, putting all the logic and delegating all the responsibilities of each screen to the Activity/Fragment.

Since then, different architecture patterns were adopted (MVC, MVP, MVVM) and integrated inside the Android’s app structure, providing more and better ways to develop good applications.

This article serves to introduce the MVP architecture and integration with one of the most influential code patterns that is used nowadays, RxJava.

Model-View-Presenter

What is MVP? MVP stands for Model-View-Presenter, it’s an architecture pattern that allows to structure the code in a way that decouples the view from the model, using a presenter as it’s middle-man and main communication channel between them.

The main advantage of adopting this pattern into your applications is that allows you to split the View complexities usually associated with the simple View-Model pattern used in standard Android apps, and grants your code easier scalability.

Interaction between the Model, View and Presenter

Model: it’s responsible for getting data from a remote API, managing and caching data.

View: is the layer that displays data and provides interaction between the user and the app through actions (ex: Activity or Fragment).

Presenter: is the middle-man between the Model and View, acting as the main communication channel and owning all the logic from querying the data from the model, transforming it if needed and sending it to the view.

So, after understanding the theory behind MVP, we can start to put it into code building our core structure composed by a Fragment (or Activity), a presenter and a callback.

public class BaseFragment<T extends BasePresenter> extends Fragment { 
protected T mPresenter;
}

Our BaseFragment contains the Presenter, allowing the communication between both. Even tough we don’t explicitly implement it, every Fragment extending from this one must implement a Callback extending the BaseCallback in order for the Presenter to communicate with it.

public class BasePresenter<T extends BaseCallback> {

protected T mCallback;
    public BasePresenter(T callback) {
mCallback = callback;
}
}

The BasePresenter will handle all the work and deliver the results to it’s corresponding Fragment, using the Callback reference that he got when it was created.

Views nowadays have different or complex components that have to be “fed” with information in real time or in big quantities, which could cause make our UI less responsive to user interactions due to the amount of work that it’s asked of the Presenter, sometimes making our own code messy. One way to address this problem is to write code in a way the flow of the request is easier to handle and distribute work using other threads than the Android’s main one. Hence comes RxJava to the rescue.

Introducing RxJava

ReactiveX, also called Reactive Extensions, is a library for composing asynchronous and event-based programs by using observable sequences. RxJava is its Java VM implementation, currently in its second version (RxJava2).

RxJava has many advantages like a more readable code, error handling, custom operators, thread management, etc. We could further these more, but I’ll only refer to the operators and the thread management (RxAndroid) for the purpose of this article.

Operators

RxJava allows us to compose our code using different operators. These are used to transform the streams, manipulate, filter, combine different observables and so on. The main advantage for using operators is that we don’t have to create many different functions and can simply replace different calls for one stream. We can also develop our own custom operators creating an ObservableTransformer and using the compose operator, also provided by the RxJava framework.

RxAndroid

RxAndroid adds some features to RxJava and complements it making the writing of reactive components in Android applications easier. The main feature is the Scheduler that it provides to enable work in or out of the Android’s main thread (UI thread), making the thread management easier and hassle-free.

Connecting MVP and RxJava

Now, after having introduced MVP and RxJava, we can finally proceed with our implementation.

We established that for each Fragment there’s a Presenter, however one has a defined lifecycle while the other will live even after it’s fragment it’s destroyed. One way for this not to happen and both be active at the same time is binding them using the concept of attach/detach.

public class BasePresenter<T extends BaseCallback> {

protected T mCallback;
    public void onViewAttached() {}
    public void onViewDetached() {}
}

So, besides the callback, the Presenter now has two new methods, that will be called by the Fragment (for now we’ll leave them empty and add some logic later).

public class BaseFragment<T extends BasePresenter> extends Fragment {
protected T mPresenter;

@Override
public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (mPresenter != null) {
mPresenter.onViewAttached();
}
}

@Override
public void onDestroyView() {
super.onDestroyView();
if (mPresenter != null) {
mPresenter.onViewDetached();
}
}
}

Our BaseFragment is a little more complex now, because it contains the logic to bind the Fragment’s lifecycle to the presenter’s. As we can see, after the view is created we attach the presenter and detach it when it’s destroyed.

But wait, what does RxJava have to do with all of this?

As said before, RxJava (and RxAndroid) allows us to handle lots of work in background threads, and we would only need to pass the final result to the main thread at the end. So what would happen if, during an HTTP request, the fragment was destroyed? Well, the most frequent outcome is that the app would crash, because when the presenter tried to send the response to the fragment, it wouldn’t exist anymore and a NullPointerException would be raised. We could solve this problem by just checking if the callback is null:

public void doSomething() {
Observable.doSomethingOperator()
.subscribe(new Observer<T>() {
@Override
public void onNext(final T value) {
if(mCallback != null) {
mCallback.doSomethingUI(value);
}
});

This is probably the easiest and simpler solution, but it’s also the laziest and dumber one. With this, you create a new dependency every time you want to write code, the developer himself. He is now responsible to always check if the callback is null or not.

RxJava enters here, as it provides a way to keep all the subscriptions inside a dedicated list with all the subscriptions, that will allow us to subscribe and unsubscribe automatically, saving us some resources and avoiding the constant callback checking to see if it’s null.

public void onViewAttached() {
mCompositeDisposable = new CompositeDisposable();
}

public void onViewDetached() {
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();
}
}

Our lifecycle methods (onViewAttached and onViewDetached) would now control the list with all the subscriptions. When the presenter is attached to the fragment, a new list will be created and when it detaches (the fragment’s view is destroyed) we would clear the list, immediately unsubscribing all the subscriptions inside of it. To add a subscription we can simply call the add method for the CompositeDisposable:

protected void bindToLifecycle(Disposable d){
mCompositeDisposable.add(d);
}

A Disposable object is the reference we get when we subscribe to a stream and can be used to unsubscribe rapidly of a subscription by just clearing the CompositeDisposable list of its content (disposables).

protected <T> ObservableTransformer<T, T> applyBinding() {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(final Observable<T> upstream) {
return upstream
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
bindToLifecycle(disposable);
}
});
}
};
}

We just created a new custom operator named applyBinding that can be composed together with any observable, making it lifecycle-aware. So let’s take a look at our final code.

public class BasePresenter<T extends BaseCallback> {

protected T mCallback;
private CompositeDisposable mCompositeDisposable;

public BasePresenter(T callback) {
mCallback = callback;
}

public void onViewAttached() {
mCompositeDisposable = new CompositeDisposable();
}

public void onViewDetached() {
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();
}
}

/**
* Binds the observable to the fragment lifecycle
*/
protected <T> ObservableTransformer<T, T> applyBinding() {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(final Observable<T> upstream) {
return upstream
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
bindToLifecycle(disposable);
}
});
}
};
}

/**
* Binds a disposable to this presenter lifecycle
*
*
@param d Disposable to be added
*/
protected void bindToLifecycle(Disposable d) {
mCompositeDisposable.add(d);
}
}

Our BasePresenter and all the presenters extending from this one are now lifecycle-aware, as long as all of them compose their observables with the applyBinding method (which is way more easy than an if-else verification everytime we get a value from a stream).

public void doSomething() {
Observable.doSomethingOperators()
.compose(this.<T>applyBinding())
.subscribe(new Observer<T>() {
@Override
public void onNext(final T value) {
mCallback.doSomethingUI(value);
});

Conclusion

RxJava can be used together with MVP, not only for code readibility or making flows clearer, but also to make it easier to adopt the pattern without having to make lots of checking and verifications between the presenter and the view.

With the new architecture components, this lifecycle awareness won’t be necessary but RxJava can still provide background processing of different tasks, improving your app’s performance.

Feel free to check my code and to comment anything you want :)