Manage Lifecycle of Rx Observables in DataBinding ViewModels (MVVM)

Muthu Raj
Adventurous Android
3 min readFeb 18, 2018

--

If you don’t know what databinding is , head over to the documentation and read about it.

Simply, data binding is a glue between your ViewModel and your view. It generates all the boilerplate to get the text from you view model and set in on textView, get the url from viewmodel and call the static method specified to load image and observe on changes on the fields in the view models.

With data binding, we can import java classes, use java class instances inside xml. Though we can use as many different class instances as we want, it would be better if we only use one instance of class per xml. That class would be the ViewModel of that particular xml.

My thumb rule is, each xml should contain only one instance . It would be handy in several places and I wrote about one in here.

Now we created one ViewModel per view (or layout file to be exact) and all the logic to show data is in that ViewModel. The data processing and manipulation would not be synchronous in nature. We may want to initiate a network call and wait for it to show some data, get data from local storage which all are asynchronous in nature.

These kind of operations should be properly cleared when the view is not being used (not shown to the user) for performance reasons and to avoid memory leak. We can use RxJava for this asynchronous operations (or reactive operations). RxJava needs to be subscribed to start the operations and can be disposed to clear the operations.

Basically, our ViewModels need to be lifecycle aware.

We create a base class for the ViewModel named BaseViewModel which contains onAttach and onDetach methods from which we can subscribe and dispose the observables correspondingly.

Now we need to call these methods at the correct time. Another important note is, all the variable names on xml should be same. Quoting from my previous article:

Usually, we set the variable for the layout using DataBinding.set{{variableName}}(object). There is another less known method in the ViewDataBinding class(which is the base class for all generated data binding class) called setVariable which takes a BR field and the actual variable as parameters. For every data binding variable, a field in BR class is generated(just like for every drawable, layout, strings etc. a field is created in R.java).

Here we have a generic method to bind viewmodels for any binding with any ViewModel class.

We leverage the View.OnAttachStateChangeListener to get attach/detach events of that particular view and call the ViewModel’s onAttach/onDetach methods correspondingly.

Why am I throwing exception if the binding is not success? It was explained in my previous article which I’m quoting here

The setVariable method returns a boolean which indicates whether the binding is successful or not. Why would it no be successful, you may ask. Usually because the BR field you specified is not the name you set in you xml. If it fails, our ViewModel would not be bind to the view and nothing will show on the UI. It is hard to debug what went wrong at this point, trust me. That’s why we throw an exception if the binding variable is mismatched (Fail Fast).

Here we manage the lifecycle of views as local as possible(local to that particular view). Now all we have to do is extend the BaseViewModel, override onAttach method and start your subscription and add that to the compositeDisposable.

For binding ViewModels, instead of calling set{{vairableName}} method, call

bindViewModel(viewModelInstance)

Since it is an extension function, we can call this method directly from the binding object.

Note: We clear the CompositeDisposable instead of dispose because after dispose, we can’t use the compositeDisposable after disposing(See Common RxJava Mistakes by Daniel Lew).

TL;DR

  1. Paste the BaseViewModel.kt and DataBindingUtil.kt in your project
  2. All the xml variable names should be same (ex: viewModel)
  3. Extend the view model from BaseViewModel
  4. Subscribe to the observables in onAttach method and add the disposables to compositeDisposable.
  5. To set the viewmodel, call bindViewModel method from the binding with the view model instance as parameter.

Now your subscriptions are managed automatically. Happy coding :)

--

--