When to use RxJava in Android and when to use LiveData from Android Architectural Components?

Solution 1:

Regarding the original question, both RxJava and LiveData complement each other really well.

LiveData shines on ViewModel layer, with its tight integration with Android lifecycles and ViewModel. RxJava provides more capabilities in transformations (as mentioned by @Bob Dalgleish).

Currently, we're using RxJava in data source and repository layers, and it's transformed into LiveData (using LiveDataReactiveStreams) in ViewModels (before exposing data to activities/fragments) - quite happy with this approach.

Solution 2:

Android LiveData is a variant of the original observer pattern, with the addition of active/inactive transitions. As such, it is very restrictive in its scope.

Using the example described in Android LiveData, a class is created to monitor location data, and register and unregister based on application state.

RxJava provides operators that are much more generalized. Let's assume that this observable will provide location data:

Observable<LocationData> locationObservable;

The implementation of the observable can be built up using Observable.create() to map the call back operations. When the observable is subscribed, the call back is registered, and when it is unsubscribed, the call back is unregistered. The implementation looks very similar to the code provided in the example.

Let's also assume that you have an observable that emits true when the application is active:

Observable<Boolean> isActive;

Then you can provide all the functionality of LiveData by the following

Observable<LocationData> liveLocation =
  isActive
    .switchMap( active -> active ? locationObservable : Observable.never() );

The switchMap() operator will either provide the current location as a stream, or nothing if the application is not active. Once you have the liveLocation observable, there a lot of things you can do with it using RxJava operators. My favorite example is:

liveLocation.distinctUntilChanged()
  .filter( location -> isLocationInAreaOfInterest( location ) )
  .subscribe( location -> doSomethingWithNewLocation( location ) );

That will only perform the action when the location changed, and the location is interesting. You can create similar operations that combine time operators to determine speed. More importantly, you can provide detailed control of whether operations happen in the main thread, or a background thread, or a multiple threads, using RxJava operators.

The point of RxJava is that it combines control and timing into a single universe, using operations provided from the library, or even custom operations that you provide.

LiveData addresses only one small part of that universe, the equivalent of building the liveLocation.

Solution 3:

There are many differences between LiveData and RxJava:

  1. LiveData is not a STREAM while in RxJava everything (literally everything) is a STREAM.
  2. LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.
  3. LiveData is synchronous, So you can't execute a chunk of code (network call, database manipulation etc.) asynchronously using just LiveData as you do with RxJava.
  4. What best you can do to exploit the most of this duo is to use RxJava for your business logic (network call, data manipulation etc, anything that happens in and beyond Repository) and use LiveData for your presentation layer. By this, you get transformation and stream capabilities for your business logic and lifecycle-aware operation for your UI.
  5. LiveData and RxJava compliment each other if used together. What I mean is, do everything with RxJava and at the end when you want to update UI, do something like the code given below to change your Observable into LiveData. So, your View (UI) observes to the LiveData in ViewModel where your LiveData is nothing but non-mutable MutableLiveData (or MutableLiveData is mutable LiveData).
  6. So the question here is, why should you even use LiveData at the first place? As you can see below in the code, you store your response from RxJava to MutableLiveData (or LiveData) and your LiveData is lifecycle-aware, so in a way, your data is lifecycle-aware. Now, just imagine the possibility when your data itself know when and when-not-to update the UI.
  7. LiveData doesn't have a history (just the current state). Hence, you shouldn't use LiveData for a chat application.
  8. When you use LiveData with RxJava you don't need stuff like MediatorLiveData, SwitchMap etc. They are stream control tools and RxJava is better at that by many times.
  9. See LiveData as a data holder thing and nothing else. We can also say LiveData is lifecycle-aware consumer.

    public class RegistrationViewModel extends ViewModel {
        Disposable disposable;

        private RegistrationRepo registrationRepo;
        private MutableLiveData<RegistrationResponse> modelMutableLiveData =
                new MutableLiveData<>();

        public RegistrationViewModel() {
        }

        public RegistrationViewModel(RegistrationRepo registrationRepo) {
            this.registrationRepo = registrationRepo;
        }

        public void init(RegistrationModel registrationModel) {
            disposable = registrationRepo.loginForUser(registrationModel)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<Response<RegistrationResponse>>() {
                        @Override
                        public void accept(Response<RegistrationResponse>
                                                   registrationModelResponse) throws Exception {

                            modelMutableLiveData.setValue(registrationModelResponse.body());
                        }
                    });
        }

        public LiveData<RegistrationResponse> getModelLiveData() {
            return modelMutableLiveData;
        }

       @Override
       protected void onCleared() {
                super.onCleared();
            disposable.dispose();
         }
    }

Solution 4:

In fact, LiveData is not an essentially different tool to RxJava , so why was it introduced as an architecture component when RxJava could have easily managed the lifecycle by storing all the subscriptions to observables in a CompositeDispoable object and then disposing them in onDestroy() of the Activity or onDestroyView() of the Fragment using only one line of code?

I have answered to this question fully by building a movie search app once using RxJava and then using LiveData here.

But in short, yes, it could, but that would need first overriding the relevant lifecycle methods besides having the basic lifecycle knowledge. This still might not make sense for some, but the fact is that according to one of the Jetpack sessions in Google I/O 2018 many developers find lifecycle management complex. The crash errors arising from not handling lifecycle dependence might be another sign that some developers, even if knowledgable of lifecycle, forget to take care of that in every Activity / Fragment they use in their app. In large apps this could become an issue, notwithstanding the negative effect it could have on productivity.

The bottom line is that by introducing LiveData , larger number of developers are expected to adopt MVVM without even having to understand the lifecycle management, memory leak and crash. Even though I have no doubt that LiveData is not comparable with RxJava in terms of capabilities and the power it gives to developers, reactive programming and RxJava is a hard-to-understand concept and tool for many. On the other side, I do not think LiveData is meant to be a replacement for RxJava–it simply cannot–but a very simple tool for handling a controversial widespread issue experienced by many developers.

** UPDATE ** I have added a new article here where I have explained how misusing LiveData can lead to unexpected results. RxJava can come to rescue in these situations