Part 1: Reactive architectures. MVI + RxJava
TL;DR
MVI
is a great pattern to use with RxJava
. It allows you to get great event based reactive architecture which makes your code cleaner, more readable and easily scalable. Check out my repo to get an idea of reactive architecture I will describe in this article
Lucky hard workers
Fortunately, Google didn’t provide Android developers with patterns and general recommendations how to create good quality project till very recent moment. This situation forced us to find and create different tools for writing good quality code. Some of this tools are MVI
and RxJava
.
However, Google did something. Android applications are built in MVC
pattern which actually is very similar to iOS’s one. It has layouts as Views
, remote server or database as Model
and Controllers
which are Activities and Fragments. Why Google did not say us anything about it? Well, it was a very good decision. We had a chance to come up with solutions ourselves. Solutions for a problem which mostly all projects back in those days had: massive godlike Activities/Fragments with even 3–5k of lines (WOW?) easily. Some iOS developers even call it MMVC (Massive MVC).
To solve problem with huge Activities/Fragments an MVP
pattern came to the rescue. It became so popular with very interesting idea — why don’t we look at Activity/Fragment as Views
and business logic will be in different place (Presenter)? With this simple pattern code becomes more readable without those huge classes.
MVI
— Model View Intent (not Android Intents, but some events, lets call it Event Manager
and don’t mix with titles) — is a very similar pattern to MVP
, but instead of having lots of methods you have just one public method, which is used by View
and receives only one argument created in specific way to be able to identify every action.
Other great and very popular tool in Android community is RxJava
. Even when a topic of this article is not to tell why RxJava
is great (probably you already know it) but a few words about it to become clear with all approaches.
Reactive behaviours are built in mobile applications. You have a user who does some actions and you don’t know when exactly application will receive them, but it has to live all the time with this nescience and wait… and wait… and wait… and finally react. It is a good description why Reactive programming is a great tool to organise your reaction and combine them into chains of actions which have to be done to make user happy. Oh, did you think RxJava
is great for making background tasks and get rid of Async Tasks, Threads, requests from IntentService or some other strange solutions for background parts of your project? You’re partially right, but it is just an additional feature to well organised streams and reactions.
Let’s react to some events
Now, when you have an understanding how to use RxJava
in a better way we can combine it with MVI
and react to our events. First of all, how to combine key parts of MVI
with RxJava
?
View
As was told before, in MVI
pattern View
is Activity/Fragment and it only handles callbacks from UI (ClickListeners, Lifecycle etc.) to send event to Event Manager
and updates layout after receiving results from Event Manager
. To make events reactive View
implements Observer
and creates subscription which will provide it with a stream of results and/or errors. All results are received in onNext().
Model
Model
is the only common part in all patterns (MVC, MVP, MVI …… MVx) which is responsible for providing data from different sources like remote server or database. I will get to this part later with introduction of Clean Architecture by providing Interactors and Repositories as continuation of chains.
Event Manager (Intent)
Event Manager
is the most complex and important part of architecture. Look back again on description of View
: it receives events from Event Manager
and it’s easy to understand that Event Manager
is a place where we have Observable
and View
actually subscribes to exactly this Observable
.
And what about events sent from View
, Observable
doesn’t receive any signals to call some next specific action, right? Here comes Subject
which is an Observable
and Observer
at the same time. Now it’s clear how Event Manager
receives events from View
, handles them and sends back the result. View
, on its lifecycle start and end subscribes and unsubscribes to Event Manager
. When View
needs to do some job from Event Manager
it sends an event to a Subject
. After receiving an event by Subject
, it provides it to Event Handler
(or just onEvent() function) which identifies received event to call required function from Model
if it is required. After receiving result from Model
it packs data required by View
to send the result to its final Observer (View)
. If Model
wasn’t called, it just sends required pack of data back to View.
CODE! WE NEED SOME CODE!
Reading theory is always painfully boring and now it is done, let’s get to the best part where I will keep talking about MVI
parts with introducing those events I was talking all the time which are required for communication between main parts: View
and Event Manager
.
Event Model and UiModel
When we talk about events in MVI
with RxJava
we need two types of events:
Event Model
which will be a representation of events sent fromView
toEvent Manager
UiModel
which will be a representation of results fromEvent Manager
toView
With Kotlins sealed classes this Events
are scalable and easy to identify.
Let’s look at this classes:
- Both of them implement some
Base
classes which are just empty interfaces used for Generics inEvent Manager
andView
- Every defined class (or object) describe an event or result with required fields for it.
Now when you know how those famous events look, let’s use them.
View
First of all, to use events in View
requires an instance of Event Manager
. You can create or inject it with Dagger2 in onCreate(), you decide. When Event Manager
is ready to use, the first thing which has to be done is setting subscribing and unsubscribing to its Subject
.
Now View
is ready to send events and receive results to Event Manager
.
As you can see, every time you need to do something View
sends event to Event Manager
for triggering a chain of actions in Event Manager
which after doing its job sends result to its View
. View
, as it was already mentioned, is an Observer
and receives results in onNext.
Event Manager
Event Manager
, on the other hand, keeps Subject
which is Observer
and Observable
. It means it has to deal with all those events by itself, and View
is just its consumer. Let’s start by looking at Base
implementation of Event Manager
.
This class does not contain a lot of code, but still has some important parts:
- Every
Event Manager
containsPublishSubject
which receives only an instance ofBaseEvent
described with Generics - With attach() function
View
can subscribe toEvent Manager
. It also describes redirection to onEvent - Event(E) function is used for sending events from
View
to trigger a chain of actions inSubject
. It also receives only an instance ofBaseEvent
described with Generics - onEvent(E) function which identifies and handles events received from
View
. It is also a source from where results forView
are coming.
When BaseEventManager
is ready to rock, what else is left to do in actual presenter? Not much. It requires only a definition of Generics and implementation of onEvent(E). Easy, right?
Right in the same way as it was in View
, Event Manager
identifies events received from View
. But unlike View
, Event Manager
has to return an Observable
with UiModel
.
Interactor
Interactor, which was mentioned before, is a layer which has connection to Repositories (local database, remote server etc.) to get data from them. Also it is a class where you have to do all your data processing.
Conclusion
With this architecture you can use full power which RxJava
gives you. Finally, you can forget about using RxJava
for only wrapping your network requests. It may look like increase of code amount, but when you start using it you will understand what is the purpose of it and your code will become much more cleaner.
With ending of this part I want to thank Krystian Płoński for introducing to me into reactive architecture.