How to Make Multiple Request and Wait Until Data Is Come from All the Requests in Retrofit 2.0 - Android

How to make multiple request and wait until data is come from all the requests in retrofit 2.0 - android

The clean and neat approach to wait until all your requests will be done is to use Retrofit2 in conjunction with RxJava2 and its zip function.

What zip does is basically constructs new observable that waits until all your retrofit Observable requests will be done and then it will emit its own result.

Here is an example Retrofit2 interface with Observables:

public interface MyBackendAPI {
@GET("users/{user}")
Observable<User> getUser(@Path("user") String user);

@GET("users/{user}/photos")
Observable<List<Photo>> listPhotos(@Path("user") String user);

@GET("users/{user}/friends")
Observable<List<User>> listFriends(@Path("user") String user);
}

In the code where you going to make multiple requests and only after all of them will complete do something else you can then write the following:

    Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build();

MyBackendAPI backendApi = retrofit.create(MyBackendAPI.class);

List<Observable<?>> requests = new ArrayList<>();

// Make a collection of all requests you need to call at once, there can be any number of requests, not only 3. You can have 2 or 5, or 100.
requests.add(backendApi.getUser("someUserId"));
requests.add(backendApi.listPhotos("someUserId"));
requests.add(backendApi.listFriends("someUserId"));

// Zip all requests with the Function, which will receive the results.
Observable.zip(
requests,
new Function<Object[], Object>() {
@Override
public Object apply(Object[] objects) throws Exception {
// Objects[] is an array of combined results of completed requests

// do something with those results and emit new event
return new Object();
}
})
// After all requests had been performed the next observer will receive the Object, returned from Function
.subscribe(
// Will be triggered if all requests will end successfully (4xx and 5xx also are successful requests too)
new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
//Do something on successful completion of all requests
}
},

// Will be triggered if any error during requests will happen
new Consumer<Throwable>() {
@Override
public void accept(Throwable e) throws Exception {
//Do something on error completion of requests
}
}
);

That's all :)


Just in case wanna show how the same code looks like in Kotlin.

    val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build()

val backendApi = retrofit.create(MyBackendAPI::class.java)

val requests = ArrayList<Observable<*>>()

requests.add(backendApi.getUser())
requests.add(backendApi.listPhotos())
requests.add(backendApi.listFriends())

Observable
.zip(requests) {
// do something with those results and emit new event
Any() // <-- Here we emit just new empty Object(), but you can emit anything
}
// Will be triggered if all requests will end successfully (4xx and 5xx also are successful requests too)
.subscribe({
//Do something on successful completion of all requests
}) {
//Do something on error completion of requests
}

How to make multiple calls with Retrofit?

First of all you need to understand the differences between Retrofit's Call#enqueue() and Call#execute() methods.

  1. enqueue() method is Asynchronous which means you can move on to another task before it finishes

  2. execute() method is Synchronous which means, you wait for it to finish before moving on to another task.

And in your case, you're using for loop to execute multiple requests in a single stretch.

Now, if you use for loops to execute network operation, the network operation will not stop for loops from going to the next iteration. Do not expect that the API will always respond in a fast enough way before going to for loops next iteration. That's a bad idea.

If you use Retrofit's execute() method, it will not allow you to continue to next line (or iteration) as its Synchronous behavior, plus it throws NetworkOnMainThreadException and IOException. Hence, you need to wrap the request in an AsyncTask and handle IOException.

I'd recommend you to use RxAndroid with RxJava instead of using for loops. There are plenty of tutorials out there on this topic.

Refer to the following StackOverflow questions to solve your problem.

  1. How to make multiple request and wait until data is come from all the requests in Retrofit 2.0 - Android?
  2. Asynchronous vs synchronous execution, what does it really mean?

Adjust the code as per your requirements.

Good luck!

How to make multiple requests using retrofit2 and rxjava2 on android?

try to use Observable.from(Iterable<? extends T> iterable) (Observable.fromArray() in rx-java2) instead of zip
So you'll have something like:

Observable.from(mySourceList)
.flatMap(new Func1<String, Observable<List<NewsItem>>>() {
@Override
public Observable<List<NewsItem>> call(String source) {
return api.getNews(source);
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.toList() // This will give you List<List<NewsItem>>
.map(new Func1<List<List<NewsItem>>, List<NewsItem>>() {
@Override
public List<NewsItem> call(List<List<NewsItem>> listOfList) {
//Merged list of lists to single list using Guava Library
List<NewsItem> list = Lists.newArrayList(Iterables.concat(listOfList));
return list;
}
})
.subscribe(new Subscriber<List<NewsItem>>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {
e.printStackTrace();
}

@Override
public void onNext(List<NewsItem> newsList) {
//Attached the final newslist to livedata
newsLiveData.setValue(newsList);
}
});

EDITED Updated the method

Java Retrofit multiple request one single response

I assume you have something like the following code in your retrofit api interface

@GET("v1/test/{name}/")
Observable<UserModel> getUserBy(@Path("name") name)

Then in your business logic you can call.

Observable.zip(retrofitApi.getUser("ALEX"), retrofitApi.getUser("ELISA"), retrofitApi.getUser("JOE"), (u1, u2, u3) -> {
// prepare your returned users in a way suitable for further consumption
// in this case I put them in a list
return Arrays.asList(u1, u2, u3);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( listOfUsers -> // TODO: do something with your users)

Hope this helps.

Is it possible , multiple rest API hit within single network request by retrofit network library

No, you can not hit more than one API in a single request. You have to create multiple request.You can follow this link for more information about retrofit :- https://square.github.io/retrofit/



Related Topics



Leave a reply



Submit