The RxJava's approach to choose a thread during the subscription, not in time of the sending is much more appropriate. Actually the only advantage of LiveData over RxJava we have noticed is they automatically subscribe and unsubscribe on Activity life cycle events (or over android components implementing life cycle).
RxJava is a Java library that enables Functional Reactive Programming in Android development. It raises the level of abstraction around threading in order to simplify the implementation of complex concurrent behavior.
LiveData notifies Observer objects when underlying data changes. You can consolidate your code to update the UI in these Observer objects. That way, you don't need to update the UI every time the app data changes because the observer does it for you. No memory leaks.
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.
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
.
There are many differences between LiveData and RxJava:
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();
}
}
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
As you may know in the reactive ecosystem we have an Observable that emits data and an Observer that subscribes( get notified) of this Observable emission, nothing strange is how works the so called Observer Pattern. An Observable "shouts"something, the Observer get notified that Observable shout something in a given moment.
Think to LiveData
as an Observable that allows you to manage the Observers that are in an active
state. In other terms LiveData
is a simple Observable but also takes care of the life cycle.
But let's see the two code cases you request:
A) Live Data
B) RXJava
A)This is a basic implementation of LiveData
1) you usually instantiate LiveData in the ViewModel to maintain orientation change (you can have LiveData that is read only, or MutableLiveData that is writable, so you usually expose outside from the class LiveData)
2) in the OnCreate
method of the Main Activity(not the ViewModel)
you "subscribe" an Observer object (usually an a onChanged method)
3) you launch the method observe to establish the link
First the ViewModel
(owns the business logic)
class ViewModel : ViewModel() { //Point 1
var liveData: MutableLiveData<Int> = MutableLiveData()
}
And this is the MainActivity
( as dumb as possible)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val ViewModelProvider= ViewModelProviders.of(this).get(ViewModel::class.java)
ViewModelProvider.observe(this, Observer {//Points 2 and 3
//what you want to observe
})
}
}
}
B)This is the basic implementation of RXJava
1) you declare an Observable
2) you declare an Observer
3) you subscribe the Observable with the Observer
Observable.just(1, 2, 3, 4, 5, 6) // Point 1
.subscribe(new Subscriber() { //Points 2 & 3
@Override
public void onCompleted() {
System.out.println("Complete!");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Double value) {
System.out.println("onNext: " + value);
}
});
In particular LiveData
is used with Lifecycle
and often with ViewModel
(as we have seen) architecture components. In fact when LiveData
is combined with a ViewModel allows you to keep updated in real time every change in the Observer, so that the events are managed in real time where is needed. To use LiveData
is strongly recommended to know the concept of lifecycle and the relative objects LifeCycleOwner/LifeCycle, also I would suggest you to have a look at Transformations, if you want to implement LiveData
in real life scenarios. Here you can find some use cases from the great commonsware.
To wrap up basically LiveData
is a simplified RXJava
, an elegant way to observe changes across multiple components without creating explicit so called dependency rules between the components, so that you can test much easier the code and make it much more readable.
RXJava, allows you to do the things of LiveData and much more. Because of the extended functionalities of RXJava, you can both use LiveData for simple cases or exploit all the power of RXJava keep using Android Architecture components as the ViewModel, of course this means that RXJava
can be far more complex, just think has hundreds of operators instead of SwitchMap and Map of LiveData(at the moment).
RXJava version 2 is a library that revolutionized the Object Oriented paradigm, adding a so called functional way to manage the flow of the program.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With