How to make multiple calls with Retrofit? - android

I need to make multiple calls to API REST with Retrofit and show the response in a ListView, but I don't know how to do this and this code doesn't work.
Model
#GET("apks/{sha256}")
Call<DatoAPI> getTask2(#Path("sha256") String hash, #Query("Authorization") String key);
Implementation
for (String s: hash) {
Call<DatoAPI> call = services.getTask2(s, API.API_KEY);
call.enqueue(new Callback<DatoAPI>() {
#Override
public void onResponse(Call<DatoAPI> call, Response<DatoAPI> response) {
if (response.isSuccessful()) {
datoAPI = response.body();
items.add(datoAPI.getApp());
}
}
#Override
public void onFailure(Call<DatoAPI> call, Throwable t) {
Toast.makeText(getApplicationContext(),t.getMessage(),Toast.LENGTH_LONG).show();
}
});
}
Also I tried with call.execute() and same problem
I want to show this response in a ListView but it doesn't work.

First of all you need to understand the differences between Retrofit's Call#enqueue() and Call#execute() methods.
enqueue() method is Asynchronous which means you can move on to another task before it finishes
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.
How to make multiple request and wait until data is come from all the requests in Retrofit 2.0 - Android?
Asynchronous vs synchronous execution, what does it really mean?
Adjust the code as per your requirements.
Good luck!

Related

RxJava Only want to call cache when api call is success

I am very new to RxJava and can't seem to find figure out the solution to this use case. I have been researching on this for 2 days now and no luck.
I have 2 Singles, remote and cache, to register a user in my app
I first call remote which saves the user data on a server, and returns a custom code to indicate successfully saved. I only want to call cache after I have checked the custom code from remote and gotten a success. If custom code comes as failure, I want to return that, and not go to the cache at all
The operator, which you're looking for, is flatMap. Example:
remoteApi.login().flatMap(new Function<String, SingleSource<String>>() {
#Override public SingleSource<String> apply(String response) throws Exception {
if (response.equals("success")) {
// do what you want to do with cache
return cache.save(response);
}
return Single.just(response);
}
}).subscribe(yourObserver);
Don't forget to use subscribeOn and observeOn...

Retrofit rxJava does not invoke onError for 500 internal server errors

On android, I make server calls through retrofit and the server can sometimes return a 500 response.
Is there a reason why onError does not get invoked in the subscriber?
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response<Void>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
if (isViewAttached()) {
getView().onError(e);
}
}
#Override
public void onNext(Response<Void> response) {
response.code() <-- why would 500 here not get routed to the onError instead?
}
});
This depends part on your configuration and part on how you defined your call, but it will all boil down to one of 2 Observables.
If you look at the source code you can see that if your call returns a type of Response<Foo> Retrofit will internally create either a CallEnqueueObservable<Foo> or CallExecuteObservable for your call. Check it out in the adapt method. For RxJava 1 this is similar, but the observables are called differently. Anyway, internally the way things work are quite the same. The call is executed and onNext is called with a response instance.
If you take a look at how this works inside Retrofit's proxy mechanism, there will always be a response instance even if the response is an Http error. This means that calling onNext will still happen even if the response is an http error itself. You can have a look at the parseReponse method and as you see there's no exception thrown if the status code is 500.
Back to the observables, only when there's an exception will the subscriber's onError be called. Remember, if it's status code 500 there's no exception thrown.
To get your onError to fire for non 2XX http error codes there are different ways, but one possible way is to (if you can afford it) make your call return Observable<Foo> instead of Observable<Response<Foo>>.
This will make retrofit use internally different observables that will make sure to call your subscriber's onError when there's an http error as well as exceptions.
Only network errorsare thrown into onError (e.g. no internet connection).
Think of a 500er as a valid response from the server instead of an error case. Furthermore you want to use the error information the server provided (Body, status code, Headers, etc.). onError can't provide this (unless as an Exception).

retrofit for android - how to do sequential network calls

in my android app i have 3 network calls and they are dependent on the call before it. So 1 must finish, then 2 can go and finally 3 gets run with the data from the previous ones. So i need the network calls to run sequentially is the goal. after one call is finished it will have data passed to the next call, etc. I dont want to use rxJava. Is there a way with retrofit to make this happen ? My project is already using retrofit thus i want to continue using it ? I've tried playing around with asynchTask but its not clean and since im using retrofit i thought i would ask.
If you're using Retrofit with the asynchronous Callbacks then for the first network call you can pass in the generated interface which represents the web service that you're interacting with. In the success method you can then use the instance of the generated interface to make a second network call, using the data which came back in success under the parametrised type T, and so on for the third call inside a second callback. For example:
class FirstCallback implements Callback<First> {
private Api api;
public FirstCallback(Api api) {
this.api = api;
}
void success(First data, Response response) {
api.secondCall(data, new SecondCallback(api))
}
}
// somewhere else in your code
api.firstCall(new FirstCallback(api));
This is a quick solution using chaining with the asynchronous calls. This would most likely look more sequential and easier to read inside of an AsyncTask using the synchronous calls, which would return the type T directly. For example:
class MyTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
First first = api.firstCall();
Second second = api.secondCall(first);
// ...and so on until you return the final result
}
}

Executing Multiple Queries In IntentService

i have an IntentService which performs a webservice call using retrofit, then on success the response (Set of queries) will be executed.
the webservice call is being made successfuly and all is well, but when executing the queries, the UI freezes then continues when the execution finishes.
shouldnt an intent service do tasks in background without affecting the UI?
code simplified:
#Override
public void success(Response iu, Response response) {
//get respose (set of queires then loop over them and execute them.
for (int i = 0; i < contentArray.length; i++) {
String query = contentArray[i];
MainActivity.myDataBase.execSQL(query);
} //the amount of queries can reach 100
if you would like to post more code i will
You appear to be making the Web service call using Retrofit, and in particular, using a Retrofit Callback. The Callback is designed for cases were you are initiating the query from the main application thread and you want the results to be delivered to the main application thread (e.g., to update a UI).
In your case, none of that is true.
Instead, drop the Callback and use Retrofit's synchronous API. So, instead of something like:
#GET("/group/{id}/users")
void groupList(#Path("id") int groupId, Callback<List<User>> callback);
use something like:
#GET("/group/{id}/users")
List<User> groupList(#Path("id") int groupId);
This way, the results will be delivered to you on the same thread that you are on, synchronously, and it will ensure that you are on the background thread for your database I/O.
BTW, if you are not doing so already, consider wrapping those database calls in a transaction -- doing ~100 individual transactions may get a little slow.

How to maintain progress bar state when using volley?

It is easy to maintain progress bar state when i use AysncTask with fragments Callback but how should i achieve it with volley? I can;t use AsyncTask because it is outdated and volley is better and faster.
Any Help or Hint will be grateful.
I am using google's volley to Post and Get Requests
I think there are misconceptions here.
First off, Volley faster than AsyncTask.
This is comparing apples and oranges. They both use threads. Volley threads are not any faster than the threads in async task. The queues are separate but that is about it. In API 11 & higher you are allowed to use your own threadpool for AsyncTask instances.
Second, define better.
Volley is designed for sending a lot of light payloads (GET/POST) to a server and getting back pretty quick responses. These responses can then be used by the caller.
AsyncTask is designed to complete a given task off the UI thread and provide various callbacks as to the state of that task.
For your ProgressBar I am assuming you are trying to determine the progress of a request that is being executed. In the Volley world, since these are expected to be tiny, you have pretty much 3 states.
Not Started
Executing(also contains start parsing)
Done (comprised of success, error and cancelled and such)
As you know with AsyncTask there is a callback for onProgress when using publishProgress. So your instance can define anything it wants to send through as an indication of progress.
If your payload is big and will take time to transfer to the server, Volley may not be appropriate. Volley doesn't do a great job or even try to do a great job of sending large payloads to and from a server. The reason is that this just isn't what it is meant for. Like it requires that all payloads, upload and receive can fit in memory entirely. So If you have a few volley requests going all over, and each one with like a 1MB payload and a 1MB response, you could see this adding up pretty quickly. You would need a streaming option to better handle that.
Volley is great library but consider what it is recommended to be used for. Read the documentation and implementation of the code for more info.
If you are doing something that is going to take a rather long time, I would write a specific request type in volley that sends and streams content to and from. That way you can tell how much work is left with the request. I am assuming you are using bytes sent and receive as the measure for progress.
you can add a listener to the queue which is executed when the request end
mRequestQueue.add(yourRequest);
mRequestQueue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<String>() {
#Override
public void onRequestFinished(Request<String> request) {
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
}
});
It's a pretty simple fix. Before you make your volley request, call the method progress.show(), and then on your response, call progress.dismiss() Just did this and it works great!
It's very easy to do that.. see the below code snippet
sendJsonRequest(){
///ENABLE PROGRESS BAR HERE
enableProgressBar();
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, URL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
hideProgressDialog();
System.out.println(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
hideProgressDialog();
}
});
queue.add(jsObjRequest);
}

Categories

Resources