Chaining requests in Retrofit + RxJava
Solution 1
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)
Solution 2
Yes, you can use flatmap for this exact purpose. See the below example (Assuming your service A returns Observable<FooA>
and service B returns Observable<FooB>
)
api.serviceA()
.flatMap(new Func1<FooA, Observable<FooB>>() {
@Override
public Observable<FooB> call(FooA fooA) {
// code to save data from service A to db
// call service B
return api.serviceB();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<FooB>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(FooB fooB) {
// code to save data from service B to db
}
});
Related videos on Youtube
Sourabh
Updated on April 22, 2020Comments
-
Sourabh about 4 years
I have 2 APIs that I want to make request to in sequence and store their data in SQLite.
First I want to make request to API
A
and store its data in SQL tablea
. Then make request to APIB
and store its data in tableb
and some data in tablea_b
. The data stored ina_b
is from requestB
alone.How can I do this using RxJava. I read somewhere about using flatMap for this, something like this
apiService.A() // store in DB here? How? maybe use map()? .flatMap(modelA -> { // or maybe store modelA in DB here? return apiService.B().map(modelB -> { storeInDB()l // store B here ? return modelB; }); });
If I wasn't using lambda functions, this would look as ugly as normal nested calls. Is this a better way to do it?
-
Sourabh about 8 yearsI didn't know about
do
operators of Rx. After reading its docs, isn'tdoOnComplete
a better function for this? -
Bartek Lipinski about 8 years@Sourabh it depends on your
Observable
. IfonComplete
is called after a successful call from api, then yes. If yourObservable
can emit multiple events, then you should go fordoOnNext
. In your case (Retrofit
) usingdoOnNext
anddoOnComplete
will have the same result, but indeeddoOnComplete
might be a bit more intuitive (I useddoOnNext
out of pure habit). -
Sourabh about 8 yearsI meant, use
doOnComplete
instead offlatMap
-
Sourabh about 8 years... as
B()
doesn't depend on result ofA()
(SO's 5 min comment edit time) -
Bartek Lipinski about 8 yearsusing
doOnComplete
instead offlatMap
would be wrong, becausedoOnComplete
wouldn't change theObservable
in stream, andflatMap
would. In other words, if you useflatMap
you can use just onesubscribe
, and trying to usedoOnComplete
instead of this would force you to callapiService.B().subscribe(...)
inside thisdoOnComplete
(which would look ugly as hell) -
Sudheesh Mohan over 7 yearsIf I write code to save data to DB in onNext it will run on main thread right? How to save data to db on background thread instead?
-
Much Overflow over 7 yearsthrow in another
flatMap
operator.api.serviceA().flatMap((FooA) -> {// call service B}).flatMap((FooB) -> {// save data from service B and return a observable stating success / failure}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).doOnNext((isSuccess) -> {// Only this will execute on main thread})
-
Ryhan over 7 yearsHow would you do this in RxJava2?
-
Andrii Kovalchuk over 6 yearsUse this for a Single:
.doOnEvent { t1, t2 -> }