I have AsyncTask and the doInBackground method inside which, I sending POST request using Retrofit. My code looks like:
//method of AsyncTask
protected Boolean doInBackground(Void... params) {
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(Constants.ROOT_API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
IConstructSecureAPI service = restAdapter.create(IConstructSecureAPI.class);
//request
Call<JsonElement> result = service.getToken("TestUser", "pass", "password");
result.enqueue(new Callback<JsonElement>() {
#Override
public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
}
#Override
public void onFailure(Call<JsonElement> call, Throwable t) {
}
});
return true;
}
The problem is: Retrofit sending request asynchronously and while it, the doInBackground method returning the value. So I need to send a request in the same thread with all executions in the sequence. One by one. And returning from doInBackground occurs after the request finished. How can I send a request in the same thread using Retrofit?
The Call class has an execute() method that will make your call synchronously.
enqueue() is explicitly for making an asychronous call.
"Retrofit sending request asynchronously" which as #Tanis.7x mentioned, enqueue() is doing the asynchronous, so what could be a reason to put in AsyncTask ? (async in async ?)
You can simply put all retrofit code out from AsyncTask and onResponse is the callback that is waiting for your request call to be back, so you can do any UI update inside of this callback.
Use retrofit execute method instead of the enqueue method.
Because in asynctask doInbackground method is already creating a thread to execute the code in background. No need to create it again using retrofit enqueue.
Related
I am trying to send the converted file (Base64 - String) as a parameter in POST, the file is about 8 MB, but sending takes about 4 minutes. Is there a way to speed up?
Interface:
#FormUrlEncoded
#POST("upload")
Call<Upload> upload(#Field("CONTENT") String content);
Retrofit instance:
public class RetrofitClientInstance {
private static Retrofit retrofit;
private static OkHttpClient client;
public static Retrofit getRetrofitInstance(String url) {
if (retrofit == null && !url.isEmpty()) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(url)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}}
Call:
private void upload(){
Api api = RetrofitClientInstance.getRetrofitInstance(SharedUtils.SERVER_URL).create(Api.class);
Call<Upload> request = api.upload(getBase64FromFile());
request.enqueue(new Callback<Upload>() {
#Override
public void onResponse(Call<Upload> call, Response<Upload> response) {
}
#Override
public void onFailure(Call<Upload> call, Throwable t) {
}
});
}
Try to compress your file or image before uploading, because it would take so much time to make it done
First of all, you are using enqueue() method of retrofit which is an asynchronous way of executing the code and you have registered callbacks to these methods on successful execution you will receive the call inside onResponse() method but on failure, you will get control inside the onFailure() method.
This will spawn a thread of execution from the daemon thread which creates another thread of execution you may never know when will this thread gets executed based on OS priority.
Use execute() method to execute this in a synchronous manner and then check the response time it would give a proper result.
Utils.java
/**
* Created by faiz on 15/08/17.
*/
package com.example.android.whereabouts;
import android.util.Log;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class Utils {
private String apiresponse;
private OkHttpClient okHttpClient;
public Utils(String url){
okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("exception",e.toString());
}
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
apiresponse = response.body().string();
Log.e("onResponse",apiresponse);
}
});
}
public String getData(){
if(apiresponse != null)
return apiresponse ;
else
return "error";
}
}
When i instantiate this class in my main activity and try to Log return value of getData method, it logs "error" instead of the value of variable apiresponse .
Its obvious that that it takes some time to get response from the server and getData call gets executed before the server returns a response.
So how to make sure getData gets called after onResponse has been executed.
Instead of getting a callback in Utility, You can implement that in your Activity so that call back will come to ur activity and you can update in UI without any issue.
public Utils(String url, Callback callback){
okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(callback);
}
in your actvity, you can call like,
public void getdata() {
new Utils("[url]", new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("exception",e.toString());
}
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
apiresponse = response.body().string();
Log.e("onResponse",apiresponse);
// here you can show in UI.
}
})
}
or you can create a separate custom interface and you can do same after getting the response from the server.
You can implement a callback mechanism and call the callback method from inside the onResponse(Call call, okhttp3.Response response) method.
Here is an example. You should define this in the Utils class -
public interface Callback {
void getData(String data);
}
private Callback callback;
In the constructor pass in the activity reference when you instantiate the Utils class.
// In the activity
utilsInstance = new Utils(url, this);
// In your Utils class
public Utils(String url, Callback activityCallback) {
callback = activityCallback
}
In your activity, you need to implement this interface -
public class RetrofitActivity implements Utils.Callback {
#Override
public void getData(String data) {
// do stuff
}
}
And in your OnResponse() method, you'll call this method like so -
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
apiresponse = response.body().string();
callback.getData(apiresponse);
Log.e("onResponse",apiresponse);
}
I found two workarounds which I'll share here and I request the people who answered this question to share their thoughts on this.(I appreciate the answers shared on this question..thanks to you all )
Note: Its more of a "clean code question" than "how to get this thing to work question"
Solution 1:
We can wait till the onResponse method gets called in getData() like this
while(true)
if(apiresponse!=null)
return(apiresponse);
to make sure this is not an indefinite while loop we set the variable apiresponse to something in both onResponse and OnFailure methods(either one will surely get executed) to break the loop.
this one seems to work but its pretty naive to me to use infinite loop and break it.
Solution 2:
Writing an AsyncTask and the Executing Utils class in the doInBackground method of that async task.
(I think the second approach makes sense as it falls under standard practices of android so it makes the thing work and also satisfies the best practices).
Another thing: an obvious question to some would be that when you're ready to write the whole async task inside the activity, then why is it an issue to write the Utils.java code directly inside the activity. My response to that is , despite of writing the asynctask in the activity, its better because it saves me from manually handling Handlers to create another thread inside onResponse to update the UI and it also falls under standard practices . So I think this approach makes more sense overall.
Step 1 : In Utils method pass calling activity as below
public Utils(CallingActivity activity , String url)
{
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(activity);
}
Step 2 : Implement Callback of OkHttpClient in your calling activity.
Step 3 : Override onFailure() and onResponse() of OkHttpClient and call Utils(this,url) in calling activity.
I am just now learning about Retrofit 2. In my app Intent "UploadToServer"
I have three async tasks that I need to call sequentially:
1. Post UserName and get back UserId.
2. Post Geolocation and some other string data and get back a "report ticket number".
3. Post a jpg image along with the ticket number.
I have a web service running on my server.
In standard hand-coded Java I would use a looper or something equivalent.
How could this be accomplished using Retrofit 2? And oh, I would like to have a progress bar moving, especially when uploading the jpg image file.
Thanks.
You can chain the calls using the callbacks:
OkHttpClient client = new OkHttpClient.Builder().build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL_WEBAPI)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
mService = retrofit.create(IWebApi.class);
...
mService.first_operation(...params...).enqueue(callback);
callback is an instance of a class that expects the results of first_operation. If first_operation success, then call the second_method.
public class Example implements Callback<void> {
#Override
public void onResponse(Response<LoginResponse> response) {
second_method();
}
#Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
}
Hope it helps.
Edit:
I use a ProgressDialog with indeterminated in true. You can show it right before the call to the service and hide when a response arrives, in the onResponse or in the onFailure methods.
mProgressDialog = ProgressDialog.show(this, getString(R.string.wait_plaease),
getString(R.string.executing_action), true);
I am an iOS Developer starting to learn Android. In Swift, creating a completion handler is very simple, but I still can't find a way to do it in Java.
I am sorry if this question is too noob for StackOverflow people.
Problem
I am creating a class to handle all my Http Request which is done using Retrofit.
I make this function is my RequestHelper.java
public static void checkEmailAvailability(String email) {
MyWebServiceAPI serviceAPI = retrofit.create(MyWebServiceAPI.class);
Call<APIResults> call = serviceAPI.checkEmailAvailability(getAuthenticationHeader(), RequestBody.create(MediaType.parse("text/plain"), email));
call.enqueue(new Callback<APIResults>() {
#Override
public void onResponse(retrofit.Response<APIResults> response, Retrofit retrofit) {
//Parse Response Json
//Get some value and place it inside an object
//ANDI WOULD LIKE RETURN SOME BOOLEAN VALUE AND SOME OTHER STRING
}
#Override
public void onFailure(Throwable t) {
//I WOULD LIKE A BOOLEAN VALUE HERE
}
});
}
I call it like this from my MainActivity
RequestHelper.checkEmailAvailability("user#user.com");
Now the function is still void but I would like for it to return something after the on the onResponse and onFailure method.
Any thoughts please?
You should pass the Callback object as a parameter to the checkEmailAvailability().
And implement the interface when you call the method from your MainActivity,and use the response parameter in the onXXX() method as the data returned to update UI.
I am working on an Android App, in which I need to make a lot of http queries. Since Android has a constrain to prevent program making http request on UI thread, I have to use a lot of Async methods to get response from the server. I am not a guru of using callbacks, there's a code design problem I am facing now:
Basically, I have a activity to display. I want the app to make a HttpRequest to server when the activity is created, so I can prepare the content of the activity based on the query response.
Since I am using the Google Volley library to make http requests, my code design is:
// in the Activity
OnCreate(Bundle b){
String response = RequestManager.makeRequest(args);
// other works based on the response in this activity.
}
// RequestManager Class
public static String makeRequest(args){
String url = getUrl();
// response callback
Response.Listener<String> responseListener = new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Don't know what to do here
}
};
// error callback
Response.ErrorListener errorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// deal with errors
}
};
BuildRequestAndPushToQueue(url, responseListener, errorListener);
// No way to return the response!
}
I know my design is totally incorrect, because String response = RequestManager.makeRequest(args); is intent to wait for a blocking call, but the call is actually async.
My ultimate goal is to let the response String returned to some code in the activity, so it can use the activity context to do the rest works (like access to a imageview, etc). But I am not sure how to design the code flow to make this happen.