Chaining Requests in Retrofit + Rxjava

Chaining requests in Retrofit + RxJava

I don't think using map operator is the best way to go with things like storing the result of the api call.

What I like to do is to separate those things inside doOnNext operators. So your example would be something like this:

apiService.A()
.doOnNext(modelA -> db.store(modelA))
.flatMap(modelA -> apiService.B())
.doOnNext(modelB -> db.store(modelB));

(add necessary observeOn and subscribeOn yourself, exactly like you need them)

Chaining API Requests with Retrofit + Rx

Single as a return type in your case will not be the best option because it is designed to only maintain single stream. concatMap or flatMap on Single will not either because it will try to map list of items to another list of items which is not the case
here.

Instead you could use Observable or map your Single to Observable by using toObservable() with concatMapIterable operator which maps your single item to sequence of items.

I used concatMap operator instead of flatMap because it maintains order of the list items so your data won't be mixed up.

getTopStoryIDs()
.map { it.take(20) }
.toObservable()
.concatMapIterable { it }
.concatMapSingle { singleId ->
api.getItem(singleId)
}
.toList()
.subscribe { items ->
//do something with your items
}

This code will work but it's not the best solution because you will make 20 or more api calls which will hurt your network data and device battery so I wouldn't use it if it is not completely necessary.

If you have any questions fill free to ask :)

RXJava2: correct pattern to chain retrofit requests

I would suggest using flat map (And retrolambda if that is an option).
Also you do not need to keep the return value (e.g Single<FirstResponse> first) if you are not doing anything with it.

retrofitService.getSomething()
.flatMap(firstResponse -> retrofitService.getSecondResponse(firstResponse.id)
.subscribeWith(new DisposableSingleObserver<SecondResponse>() {
@Override
public void onSuccess(final SecondResponse secondResponse) {
// we're done with both!
}

@Override
public void onError(final Throwable error) {
// a request request Failed,
}
});

This article helped me think through styles in how I structure RxJava in general. You want your chain to be a list of high level actions if possible so it can be read as a sequence of actions/transformations.

EDIT
Without lambdas you can just use a Func1 for your flatMap. Does the same thing just a lot more boiler-plate code.

retrofitService.getSomething()
.flatMap(new Func1<FirstResponse, Observable<SecondResponse> {
public void Observable<SecondResponse> call(FirstResponse firstResponse) {
return retrofitService.getSecondResponse(firstResponse.id)
}
})
.subscribeWith(new DisposableSingleObserver<SecondResponse>() {
@Override
public void onSuccess(final SecondResponse secondResponse) {
// we're done with both!
}

@Override
public void onError(final Throwable error) {
// a request request Failed,
}
});

chaining requests with retrofit and rxjava

You can use flatmap function for this exact purpose

textsCall
.flatMap(new Func1 < ResponseBody, Observable < AirportCombo >> () {
@Override
public Observable < AirportCombo > call(ResponseBody valueA) {
// code to save data from service valueA to db
// call service B
return routesCall;
}
})
.flatMap(new Func1 < AirportCombo, Observable < ValueC >> () {
@Override
public Observable < ValueC > call(AirportCombo valueB) {
// code to save data from service valueB to db
// call service C
return observableC;
}
})
.flatMap(new Func1 < ValueC, Observable < ValueD >> () {
@Override
public Observable < ValueD > call(ValueC valueC) {
// code to save data from service valueC to db
// call service D
return observableD;
}
})
.flatMap(new Func1 < ValueD, Observable < ValueFinal >> () {
@Override
public Observable < ValueFinal > call(ValueD valueC) {
// code to save data from service valueD to db
// call Final Service
return observableFinal;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber < ValueFinal > () {
@Override
public void onCompleted() {}

@Override
public void onError(Throwable e) {

}

@Override
public void onNext(ValueFinal fooB) {
// code to save data from service ValueFinal to db

}
});

Chaining multiple calls RxJava, Room and Retrofit

First of all try not rely on Side effects, that make things unpredictable .. for example this function

fun insertKafaniInDb(kafani: List<Kafana>) {
Observable.fromCallable { kafanaDao.insertAll(kafani) }
.subscribeOn(Schedulers.io())
.subscribe {
Timber.d("Inserted ${kafani.size} kafani from API in DB...")
}
}

its return type is Unit, it's better to include it in the stream, this is done by converting to Completable so it will be something like this

  fun insertKafaniInDb(kafani: List<Kafana>) {
return Observable.fromAction { kafanaDao.insertAll(kafani) }
.subscribeOn(Schedulers.io())
.doOnComplete { Timber.d("Inserted ${kafani.size} kafani from API in DB...") }
}

other functions that return Unit (void in java) should be converted the same way to completabel. so now I'll try to rewrite your logic without using side effects. and explaining each step.

fun getUpdatedData(): Single<MutableList<String>>? {
return kafanaRepository.getFavoriteKafani()
.toObservable()
.flatMap { Observable.fromIterable(it) } //to iterate on favorite items
.flatMap { localItem ->
kafanaRepository.getKafaniFromApi()
.flatMap { Observable.fromIterable(it) } //to iterate api items
.filter { localItem == it } //search for the favorite item in Api response
.flatMap {
//we update this item then we pass it after update
kafanaRepository.updateFavoriteKafana(it)
.andThen(Observable.just(it))
}
.defaultIfEmpty(localItem) //if it's not found, then no update needed we take this it.

}.toList() // we collect the updated and non updated local items to list
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}

Hope this could help you.
Final words .. Rx is about ordering your thoughts and plug your logic in functional way .. try to avoid using onNext() to update global variables, use it just for logging and non Business logic.

Chaining Retrofit calls with RxJava and returning the main object

    Observable<List<Library>> observable = myRestInterface
.getLibraryList()
.flatMapIterable(response -> response.getItems())
.doOnNext(library -> myRestInterface
.getAuthorList(library.getUrl().substring(library.getUrl().lastIndexOf("/") + 1))
.flatMapIterable(response -> response.getItems())
.doOnNext(author -> library.getAuthors().add(author))
.doOnNext(
author -> myRestInterface
.getBooksList(author.getUrl().substring(author.getUrl().lastIndexOf("/") + 1))
.flatMapIterable(response -> response.getItems())
.doOnNext(book -> author.getBooks().add(book))
.subscribe()
)
.subscribe()
)

.doOnNext(mainObjectList -> new ViewupdateMethod(mainObjectList))
.subscribe();

Note .subscribe() calls. They are used to start execution of the whole chain. RxObservable does nothing until subscriber arrives.



Related Topics



Leave a reply



Submit