RX + MVP + Android = ❤

Mihail Bohnearschi
AndroidPub
Published in
6 min readMar 24, 2017

--

Hello everyone and welcome back!

Today we’re gonna create a small application that will consume the REST API from the previous article.

This app will be based on the MVP architectural approach enhanced by RX.

If you never used RX before you’re probably wondering now — “What the hell is this?”, so here is a short definition.
RxJava is a Java VM implementation of ReactiveX (Reactive Extensions): a library for composing asynchronous and event-based programs by using observable sequences.

In our project we’ll be using a whole stack of technologies from Square so the first one will be Retrofit. This is the library that will help us consume our API

This article will not cover basic project setup and will not go too much into implementation details, all the code from this example application will be linked at the bottom of the article and it contains all the code needed. If you’re more kind of a “gimme teh codz” person, here is the link for you.

So for consuming our REST API the interface must have this two methods

@GET("api/getTasks")
Observable<List<Task>> getTasks();
@POST("api/addTask")
Observable<AddTaskResponse> addTask(@Body AddTaskRequest request);

The synergy between Android and the Backend that we developed in the previous example is that they communicate the same language. The request/response entities can be easily copied back and forth between both codebases. On Backend side we use Jackson for JSON de/serialization but on Android we use Gson. Jackson can also be used on Android without any problems or any other serializer.

I usually have 5 packages in my apps: “api”, “application”, “database”, “screens” and “utils”.

“api” — package usually contains the Retrofit REST API interfaces and separate packages for requests and responses.

“application” — package is where lives my custom Application class and a package inside named “builder”/”dagger” with all the application dependencies modules inside.

“database” — is the package where are located the domain entities, DAO classes generated by GreenDao and Repositories for accessing and manipulating entities.

“screens” — is the package where all the screens live, each screen has his own package with an Activity/Fragment or Dialog in it and two packages “core” (where the Model, View and Presenter live) and “dagger”/”builder” where are located all the Dagger needed classes. Dagger is a dependency injection framework which helps streamlining the dependency graph and makes unit testing easier.

“utils” — package is where multiple utils classes live. It can be virtually anything from String helper methods to Network availability methods.

So as I mentioned before each screen has a Model, View and Presenter. Sounds like regular MVP right?
An it actually is! However there are significant differences here.
The first one is that the View doesn’t know about the Presenter. It only has methods that set some values in the UI and also provides methods that expose Observable’s to our Presenter. The Presenter is the guy who knows about the View and Model and only is responsible for the business logic and forwarding data from the Model to the View.
The Model is the guy who is responsible for making network requests through Retrofit, fetching and inserting data from/in our Repositories, navigation between screens and any other external thing that is required.
So as you can see all the responsibilities are nicely separated between layers and offer a clear understanding what should be and where. Also by being mostly Context agnostic we can have regular JUnit tests that will cover all the business logic of the application. Cause that’s what we basically need, make sure that the logic that we write works as we want it to work.

One of the biggest differences of this approach is that the Activity/Fragment is an abstract entity here that only forwards lifecycle events to the Presenter. And the only guy to know about the Context (Activity/Presenter/Dialog) is the Model because he needs it for accessing various external resources and providing navigation.

Another interesting Square library that I use is Timber.
Using this library I can easily manage all the logs from all the application and define separate Loggers for Debug/Production (For production various logging solutions can be used however I prefer Fabric). This code is located in the AppController class which extends the Android Application.

if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}

What this basically means is that if the app is run in the release configuration, there will be no logs. If we add an “else” to our “if” and plant a custom Logging Tree then we’ll be able to view our logs in the web interface (Fabric has a nice dashboard for events logs).

Memory management has always been an issue on Android, and there is no developer that has never seen OutOfMemory Exception. What this exception means is that your app is leaking memory all other the place. By leaking I mean holding resources that are no longer needed which doesn’t allow GC (Garbage Collection). So after a while when such leaking resources become too many, at some point the Android OS can’t allocate more memory to the app and it throws the Exception. Tracing memory leaks has always been challenging, however not anymore. LeakCanary is another library from Square which analyzes the memory the application uses and notifies you if any leaks are detected and what reference is causing the issue allowing the developers to concentrate on fixing the issues and not spend time debugging and analyzing memory heap. It is being initialized in the AppController as well.

LeakCanary.install(this);

One of the best Rx features is easy threads handling. This is achieved by using various schedulers which are suitable for specific needs like: background processing, UI thread events or network requests. What I like to do is wrap this Schedulers to offer a single interface for accessing them. This allows easily finding what runs on what thread and changing threads for specific Schedulers for all the Observables at the same time by just modifying in one place.

public class AppRxSchedulers implements RxSchedulers { private static final Executor NETWORK_EXECUTOR = Executors.newCachedThreadPool();
private static final Scheduler NETWORK_SCHEDULER = Schedulers.from(NETWORK_EXECUTOR);
private static final Executor BACKGROUND_EXECUTOR = Executors.newCachedThreadPool();
private static final Scheduler BACKGROUND_SCHEDULER = Schedulers.from(BACKGROUND_EXECUTOR);
@Override
public Scheduler androidUI() {
return AndroidSchedulers.mainThread();
}
@Override
public Scheduler io() {
return Schedulers.io();
}
@Override
public Scheduler computation() {
return Schedulers.computation();
}
@Override
public Scheduler network() {
return NETWORK_SCHEDULER;
}
@Override
public Scheduler background() {
return BACKGROUND_SCHEDULER;
}
@Override
public Scheduler immediate() {
return Schedulers.immediate();
}
}

This is the implementation used in the application for handling various jobs that have to be executed on separate threads. For testing another implementation is used and all methods return “Schedulers.immediate()”. We’ll cover unit tests in the next article where I’ll go a bit more into detail on this matter.

The ORM of choice for this project is GreenDao. In my opinion it offers the optimal balance between performance and features and is pretty much the silver bullet for data storing. It supports relational schemes as well as building complicated queries. In this app I’m using the secure implementation of this data storage. I’m providing my “DaoSession” object in DataModule inside application dependencies package.

@Module
class DataModule {
private static final String DB_NAME = "cashex-db";
private static final String DB_PASSWORD = "db_secret_password";
@AppScope
@Provides
SharedPreferences sharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
@AppScope
@Provides
DaoSession daoSession(Context context) {
DaoMaster.OpenHelper helper = new MigrationUtils.MyOpenHelper(context, DB_NAME, null);
DaoMaster daoMaster = new DaoMaster(helper.getEncryptedWritableDb(DB_PASSWORD));
return daoMaster.newSession();
}
@AppScope
@Provides
public TaskRepository taskRepository(DaoSession daoSession) {
return new TaskRepository(daoSession);
}
}

The DaoSession is the class generated by GreenDao that allows data access, that’s why it’s being passed in the TaskRepository. Instead of this only the TaskDao could be passed in the repository (this is another GreenDao generated class), however DaoSession is fine as well. Also I’m using a custom OpenHelper implementation which allows me to painlessly migrate between schema versions withour losing all the user data. This is very handy when your app is in production and you have tons of potentially angry users that can ruin your Play Store rating. The password is being stored here (hint: not the most secure location for holding a password), but this was done intentionally just to demonstrate how easy it is to use an encrypted data storage and the best part is that it’s no different to using a regular database (not encrypted). You can find the OpenHelper in MigrationUtils class.

In the next article we’ll talk about code quality, CI and Unit Testing so stay tuned.

That’s it for this article, the full source code can be found here.

--

--