Exploring different approaches to MVVM on Android
This is not another article explaining what is MVVM and how to implement it on Android. If you don’t know what is MVVM, this is a great way to find more about it. Implementing MVVM on Android is a very popular topic with lots of information.
Approaching MVVM on Android
There aren’t many ways to approach MVVM and it is not such a complicated pattern. You make a simple view model, you use it in the UI layer and you make a model layer with which the view model communicates. Simple as that. The initial approach to MVVM would include:
- DataBinding – well, using the DataBinding tool from android is not a must, but it will make your life way simpler. You use your view model directly inside your view layer (XML) instead of populating the fields through the Java code. You can almost do everything inside the XML using ObservableField or the other available DataBinding classes (ObservableBoolean/Integer etc.).
- RxJava – at its core, it is all about functional stuff and event driven programming so it plays awesome with MVVM. You subscribe to given events and then you update your UI layer automatically.
- Dagger – you should know what this is about. Inject your view models inside the activities inside which you plan using them.
The truth is you don’t need any of the above to use MVVM. The idea is that they will make your life easier in many ways, not writing code in the activity, replacing view models easier and some additional benefits if you decide to use Retrofit + RxJava + DataBinding.
Things to keep in mind
MVVM is just an MVP with some public fields. Nothing more, nothing less. But there are some things that I thought about when implementing MVVM. Let me share them with you.
Managing RxJava Subscriptions/Disposables
I hate the fact that I have to manage RxJava subscriptions by calling viewModel.start() and viewModel.stop() methods. It really makes me write additional boilerplate code which is one of the things I hate. I found several ways to fight this problem.
- Custom lifecycle for the view models/presenter – Here is the article I followed. You can use the RxLifecycle library from Trello to make your own custom lifecycle. Then you can have a BaseViewModel class that implements all of the needed things and adds a transformer function: bindUntil(Event event). Then you can just call that function in your compose() method of your RxJava subscription. No more CompositeSubscription and compositeSubscription.clear() methods.
- LruCache-ing the repository layer – you can always cache your observable using the LruCache and then take it from there. This is another good approach I found in this article. It really depends on what your needs are, I haven’t tested it still.
- Unsubscribing using DataBinding – You can use the approach Manas Chaudhari did in the Github example he made. You can unsubscribe in the add/remove onPropertyChanged callback of the observable DataBinding field. I am not fine with this approach because I would not rely on DataBinding to manage the subscriptions I create.
- RxJava.Observable DataBinding.ObservableField – The above repo has a nice example how to transform a RxJava Observable to DataBinding.Observable field. You can check his code.
- Custom implementation – you can always use a custom lifecycle callback to manage the subscriptions at a higher level. I will leave the”How?” question to your mind. If you have some better way of doing this – please feel free to share it.
How many layers of abstraction?
You can try to make a combination between MVVM and the Clean Architecture presented by Uncle Bob. It is all up to you. I would prefer to use a repository layer which calls the API, so I won’t depend so much on the network layer and I would use it inside the ViewModel. Using the Uncle Bob solution is the ultimate way of testing everything inside your app, but I would not implement it for small apps. It is like killing a mouse with a bazooka.
Almost everything should be controlled by your view model. If it is not controlling the thing, then there may be something wrong. For the navigation, you can use a custom class called Navigator which receives a FragmentActivity and has different methods to open different screens. You can always mock that class later to test the navigation. It is used in the VIPER architecture pattern. Other than that the communication between the view model and the view should be done through subscription to methods like RxJava methods or using observable fields.
Life of Android MVVM examples
- RxJava with Android
- DroidCon MVVM
Implementing MVVM on Android with or without RxJava is pretty straight forward. Either with the repository layer or not, it feels natural to the whole system and it fits with its dynamic UI. I am still on my way of figuring things out but it saves your writing a lot of boilerplate code like you do in MVP. Still, there are other interesting strategies to implement architecture patterns on Android so stay tuned and never stop learning.