All streams come and go to the ViewModel on the top!

Reactive MVVM architectural pattern

Hadi Lashkari Ghouchani
ProAndroidDev
5 min readNov 6, 2018

--

People keep asking me what do you mean in your clean architecture project here by RMVVM. So I decided to write this post to introduce it.

As an Android developer you must be familiar with the MVVM architectural pattern, and you may know it’s already reactive, so what is the point here by this title? Let me explain. Based on Wikipedia, by “Reactive Programming” we mean:

In computing, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change.

In MVVM architectural pattern, we use LiveData objects to propagate view states, as data, from ViewModel to the View. You can see in the below diagram that for any state in the View we have a LiveData in ViewModel to propagate and cache that state.

MVVM architectural pattern

Also it is proper to use the concept of channel here. You can think of LiveData as a channel, which the ViewModel puts view states into it and on the other side the View receives that view states. So in MVVM for any view states we have a channel. Having channel in your code have at least two important advantages, which MVVM architecture borrows them.

  • First, when you put the data in the channel, you don’t need to think where, how or who wants to listen to this data. .For instance, multiple Fragments can observe one channel.
  • Second, when you want to listen to the channel for the streamed data, you don’t need to think where, how or who puts them there. The data may streams from database or network or etc

These advantages make the use of channels much easier than passing data by direct call of methods, because as the above advantages are shown, it’s dividing the problem at least into two sub-problems. This method named divide and conquer, which is a problem-solving strategy. However there are more advantages for reactive programming such as

  • Whenever you want you can close the channel.
  • Having declarative code, which makes the code more readable.
  • Be prepared for multi-core CPU supports in the future! :D
  • You feel like a piping manager!
  • etc.

Additionally the disadvantage of MVVM architecture, in my view, is that if an action is happening in the View, we directly call a method in the ViewModel to notify it, which means in the case of actions the MVVM isn’t reactive, but we want to fully support reactive idea by RMVVM.

As the following diagram shows, the idea of RMVVM architectural pattern is to propagate the actions via a channel from View to ViewModel.

RMVVM architectural pattern

One of the best game players around for reactive programming in Android is the RxJava2 library, so we’ll use it to implement our idea, but you can implement the same concept with the Arrow library.

I have to mention, that the idea of having actions as data is not new and you can find it in other patterns such as Redux.

Implementation

For starting, you have to implement MVVM architectural pattern. Then you must have a base action interface:

After that, you need a RxJava subject in your ViewModel, where you can put it in your BaseViewModel class as follows:

To treat different actions differently just need to filter them out with the filterTo extension function like this:

Then you can subscribe to this subject and wait for the actions to come:

Or more exciting, you can use a monad like flatMap operation to send the event of click to deeper layers of your app.

To fire the actions for example from the fragment, you can do this:

Until now, it seems that we made things harder to do! But please wait for me to explain problems that this architectural pattern can make easier.

Advantages

I can provide three examples that this pattern can make your life easier. First, you can handle the timing of actions super easily. Second, you can add multiple middleware functions for actions. Third, you may have difficulty to pass the actions from ViewHolder of a RecyclerView to your ViewModel by using interfaces. This pattern can make your life easier, so let’s look at these examples one by one.

Timing

In RMVVM, it’s easy to avoid double click or click on different buttons simultaneously, which would cause to bad behavior of your app, such as opening an activity twice and so on. This can be handled easily by using throttleFirst operation of RxJava like the following:

In this example, we just ignore the following click actions until one second is passed from the first click, then after that, user can click again to start the timing.

Middleware functions

Middleware functions are functions that have access to the action and in principle can manipulate and control events. A simple example of such functions is logger middleware. For example, you want to log the actions of user into Google Analytics or some other analytics service, then you can write middleware functions for each of those loggers independently and attach them to the stream like this:

Passing Actions

Imagine you have multiple types of ViewHolders in a RecyclerView which reside in a Fragment and for each of these types you have different kinds of buttons that user can click and have a different experience. The first method that people use to handle this scenario is to define different kinds of ClickListener interfaces for each of those clicks, then pass these listeners to the Adapter of that RecyclerView and in the Adapter pass those listeners for each of ViewHolders that needs them. Then assume the product owner assigns a new task to you to add a new ViewHolder with new kinds of listeners to the RecyclerView. To do that, you have to change the constructor of the Adapter and also change your Fragment to call methods of ViewModel. Well, you have to change unnecessary parts of your code, which is bad. Let’s try to implement this scenario with RMVVM.

The first approach is to pass the actionStream of the ViewModel to all ViewHolders, then in case of any event the ViewHolder propagates the action to the ViewModel. It would be OK because the life cycle of ViewHolders is shorter than the life cycle of ViewModel. But to avoid forgetting this rule and mistakenly using them for longer life cycle components, it’s better to have another approach. Let’s give each ViewHolder their own actionStream to propagate their events, which easily can be defined in the BaseViewHolder of your app as follows:

In the Fragment we subscribe those actionStreams with the actionStream of the ViewModel as follows, then we have a chance in Fragment to dispose the Disposable of those subscriptions to avoid possible memory leak:

With RMVVM, if the product owner assigns any task to add a new ViewHolder then you don’t need to change the constructor of your Adapter or the Fragment. Wonderful.

Finally, I have to say it would be good to have your feedback for making better patterns in the future.

--

--