c0dehunter
c0dehunter

Reputation: 6150

Should I use Observable(RxJava2) or Call (retrofit2)?

TL;DR: I want to execute multiple Calls (Retrofit) like you can .zip() multiple Observables (RxJava2).


I have a retrofit2 function:

@GET("/data/price")
Call<JsonObject> getBookTitle(@Query("id") String id, @Query("lang") String lang);

I can execute it (async) in code with enquene():

ApiProvider.getBooksAPI().getBookTitle(bookId, "en").enqueue(new Callback<JsonObject>() {
    @Override
    public void onResponse(Call<JsonObject> call, Response<JsonObject> response) { }

    @Override
    public void onFailure(Call<JsonObject> call, Throwable t) { }
});

Now I want to execute multiple Calls at once (get multiple book titles) and be notified when all requests are done. Here is when I am missing knowledge.

I know I could start using Observable (RXJava2) instead of Call (Retrofit2):

@GET("/data/price")
Observable<JsonObject> getBookTitle(@Query("id") String id, @Query("lang") String lang);

and then merge calls like in below example. But this code seems much more complex and long (especially if I only need 1 book title). Isn't there any way I could merge Calls without using Observable?

List<Observable<JsonObject>> mergedCalls = new ArrayList<>();
mergedCalls.add(ApiProvider.getBooksAPI().getBookTitle(bookId1, "en"));
mergedCalls.add(ApiProvider.getBooksAPI().getBookTitle(bookId2, "en"));
mergedCalls.add(ApiProvider.getBooksAPI().getBookTitle(bookId3, "en"));

Observable<List<JsonObject>> observable = Observable.zip(calls, responses -> { 
        // merge responses, return List
        ...
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribeOn(Schedulers.io());

observer = new DisposableObserver<List<JsonObject>> () {
    @Override
    public void onNext(List<JsonObject> result) { // got all API results }

    @Override
    public void onError(Throwable e) { }

    @Override
    public void onComplete() { }
};

observable.subscribe(observer);

Upvotes: 6

Views: 1068

Answers (1)

Bartek Lipinski
Bartek Lipinski

Reputation: 31438

Using RxJava is the easy way of merging Retrofit Calls. Merging Calls manually by enqueuing all Calls and doing something when all of them invoke onResponse, will probably be more complex than simply using Observable.zip(...).

The other choice that you have is using Kotlin coroutines (now Retrofit has out of the box support for them). But that depends on the Kotlin presence in your code and your willingness of using coroutines.


EDIT: (Answering your question from the comment)

If you really think about Calls and RxJava Observables you don't really have to do anything more when using RxJava. When using raw Calls you still have to:

  1. Make sure you're on the right thread if you want to touch Views (observeOn(AndroidSchedulers.mainThread()))
  2. Make sure you're touching network on the right thread (subscribeOn(Schedulers.io()))
  3. Make sure you're not using the response when your Activity/Fragment/Something else is no longer present (disposing of the Disposable in RxJava handles that)

You can significantly simplify your example:

  1. Don't create Observable & Observer. Simply use the subscribe method which returns Disposable. And then maintain just this one Disposable.
  2. You probably don't need onComplete so you can use the simpler version of .subscribe(...)
  3. You can remove the need for .subscribeOn(Schedulers.io()) by properly creating your RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()) when building the Retrofit instance.
BooksApi booksApi = ApiProvider.getBooksAPI();
List<Observable<JsonObject>> mergedCalls = new ArrayList<>();
mergedCalls.add(booksApi.getBookTitle(bookId1, "en"));
mergedCalls.add(booksApi.getBookTitle(bookId2, "en"));
mergedCalls.add(booksApi.getBookTitle(bookId3, "en"));

final Disposable disposable = Observable
        .zip(mergedCalls, responses -> {
            // merge responses, return List
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(list -> {
            // got all API results
        }, throwable -> {

        });

Doing that for one call would be as simple as:

final Disposable disposable = booksApi
        .getBookTitle(bookId1, "en")
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(title -> {
            // got the result
        }, throwable -> {

        });

Upvotes: 2

Related Questions