Android - OkHTTP requests - android

I am using HttpUrlConnection for doing requests to my mysql db using webservices. With HttpUrlConnection I can execute all my requests in background so the main thread don't get overloaded and start skipping frames.
With okHttp how does this is achieved? How do I make a request with it and print a response using JSON? Is it better than httpUrlConnection?
P.S I do not know anything about okHttp, I will be grateful if you are explicit with your examples.

With okHttp how does this is achieved?
Typically, you let it handle the background thread for you, using enqueue() for asynchronous operation:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
#Override public void onFailure(Call call, IOException e) {
// handle the error
}
#Override public void onResponse(Call call, Response response) throws IOException {
// use the result
}
});
}
(sightly simplified from the OkHttp docs)
Or, if you already have a background thread, you can use execute() instead of enqueue() for synchronous operation.
You might wish to review the other examples on the OkHttp recipes page, plus the OkHttp Web page, plus the OkHttp wiki, to get a better sense of how it compares with what you are used to.

Related

Retrofit & OkHttp - Is it possible to send only one request at a time?

I am using Retrofit 2.4.0 to send requests to a server. But sometimes server blocking my request if it has a similar timestamp in milliseconds with another request. I need to send request one at a time:
Request A is sent
Request B waits until the response for Request A received
Request A completes with success or error
Request B is sent
Is it possible to create such queue with Retrofit and OkHttp libraries?
I decided to use Dispatcher's setMaxRequests method to send request one at a time:
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(1);
OkHttpClient client = new OkHttpClient.Builder()
.dispatcher(dispatcher)
.build()
yes you just need to call the function or send request on success/failure result of the API
private void firstRequest() {
Call<LoginModel> call= apiInterface.getLogin("");
call.enqueue(new Callback<LoginModel>() {
#Override
public void onResponse(Call<LoginModel> call, Response<LoginModel> response) {
//function here
}
#Override
public void onFailure(Call<LoginModel> call, Throwable t) {
}
});
}

How to implement POST method in AsyncTask to write JSON data through API in android studio?

I want to POST JSON data having nested objects in it with the help of Asynctask in android studio, but I don't have good knowledge of API implementation in android studio. I am all new in android studio. I have successfully POST this data from POSTMAN, but I am not able to implement the code for it, also I don't have any tutorials for Asynctask. Please help me to implement code for this.
This is my Json data having nested Objects in it:
You don't need Async, Volley does it in the background for you. Put your JSONObject in the method instead of 'new JSONObject'. And YourURL - i.e '/api/route/'.
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest request_json = new JsonObjectRequest(YourURL, new JSONObject(params)),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
//Do what you want on response
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//If there's an error...
}
});
//Add process to queue to get JSON in background thread
queue.add(request_json);
Nowadays a better/simpler approach would be to use a libary like Retrofit to do all the magic for you.
You can simply send a Java instance model to an API endpoint. Retrofit takes care of converting it to json when using the GsonConverterFactory class and sends the json to the endpoint you provided with the given HTTP method.
Best and Simple Library for Implementation for API services by third party library made by Square, Retrofit a Easy HTTP Client.
Why Retrofit? because, Retrofit automatically creates the background thread ,Parse the Json using GSON converter and get a call success and Failure call back directly on main thread. Without writing too much boiler plate code of AsyncTask and Parsing JSON and getting the result on main thread.
Make Retrofit Client.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
RetrofitInterface service = retrofit.create(RetrofitInterface.class);
Make Method in RetrofitInterface.
#POST("users/new")
Call<User> yourMethod(#Body UserType user);
Now Call your method and It will make your success and Failure Callback method
Call<List<Repo>> repos = service.yourMethod("octocat");
And then Call enque method to automatic create background thread.
repos.enqueue(new Callback<List<Repo>>() {
#Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
#Override
public void onFailure(Call<MainResponse> call, Throwable t) {
}
});

How can I queue up and delay retrofit requests to avoid hitting an api rate limit?

I'm using an api that implements throttling. One of the limits is 1 request/second. ugh.
I have the following scenario which hits the limit right away.
Check the status of the api with api/status
if the api is up, get a users subscriptions
load a page from the list of subscriptions
Is there anything I can plug into retrofit that can queue each network request to only run at least 1000ms after the last? I am using/learning rxjava, can debounce be of any use here?
You can throttle your observable.
Observable<String> text = ...
text.throttleLast(1, SECONDS)
.flatMap(retrofitApiCall())
.subscribe(result -> System.out.println("result: " + result));
Another solution is to set a dispatcher in your okhttp builder, and add an interceptor that sleeps for one second. This may not be the most elegant solution and kills some of the benefits of using async because it limits you to one thread at a time.
OkHttpClient.Builder builder = new OkHttpClient.Builder();
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(1);
Interceptor interceptor = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
SystemClock.sleep(1000);
return chain.proceed(chain.request());
}
};
builder.addNetworkInterceptor(interceptor);
builder.dispatcher(dispatcher);
builder.build();
An interceptor (from OkHttpClient) combined with a RateLimiter (from Guava) is a good solution to avoid HTTP 429 error code.
Let's suppose we want a limit of 3 calls per second:
import java.io.IOException;
import com.google.common.util.concurrent.RateLimiter;
import okhttp3.Interceptor;
import okhttp3.Response;
public class RateLimitInterceptor implements Interceptor {
private RateLimiter limiter = RateLimiter.create(3);
#Override
public Response intercept(Chain chain) throws IOException {
limiter.acquire(1);
return chain.proceed(chain.request());
}
}
Actually, you can use already made OkHttp Delay Interceptor library. Just call .addInterceptor(DelayInterceptor(Long, TimeUnit)) method on your's OkHttp client builder object.

How to get the HTTP error code from a failed request in Retrofit 2.0.0?

I am making call using the following callback method:
Callback<PeopleList> callback = new Callback<PeopleList>() {
#Override
public void onResponse(Response<PeopleList> response) {
Toast.makeText(LoginActivity.this,getString(R.string.login_failed), Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Throwable t) {
Toast.makeText(LoginActivity.this,getString(R.string.login_failed), Toast.LENGTH_SHORT).show();
}
};
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit.create(MyService.class).getPeopleData().enqueue(callback);
To the following interface:
public interface MyService {
#Headers("Accept: application/json")
#GET("/data/people/")
Call<PeopleList> getPeopleData();
}
This callback works just fine on successful requests. On unsuccessful ones however it does not give me the opportunity to investigate further as the onFailure method does not allow me to retrieve the http error code that came with the response.
On investigating further I found that according to several stackoverflow threads, the onResponse method should be called even on unsuccessful requests. This however seems to be at odds not only with my personal experience but also with the documentation of the Callback interface, which states that:
Communicates responses from a server or offline requests. One and only one method will be
invoked in response to a given request.
So the question is, how do I get the HTTP error code from a failed response if the onResponse method isn't called?
I think that the onResponse method gets called even if there is a response with an Error so something like this might work(sorry if I did something wrong first attempt to answer anybody :)
#Override
public void onResponse(Response<PeopleList> response) {
if(response.isSuccess()){ //good http request, do something with response.body()....
Toast.makeText(LoginActivity.this,getString(R.string.login_failed), Toast.LENGTH_SHORT).show();
} else { //bad http response do something with error message
try {
Toast.makeText(LoginActivity.this,response.errorBody().string().toString(), Toast.LENGTH_SHORT).show();
} catch (IOException e){
//IOException caught from response.errorBody().string() method
}
}
}
onResponse() will be always called, for failed requests .body() is null. response.isSuccess() is used to quickly distinguish requests with http codes between 200 and 300.
If you want to access http codes you can do the following:
int htppResultCode = response.raw().code();
It accesses the raw Response object which holds information about general outcome of the request.

Blocking request interceptor with Retrofit?

Is there a nice way to implement "blocking" request interceptor?
The main idea is that all requests should be intercepted and added additional header - token.
If token does not exist yet it should be retrieved first, then added to that request and cached for future used. token is retrieved via API call.
I've tried to do synchronous request, but, that produces android.os.NetworkOnMainThreadException. And implementing with in_progress flags it doesn't look nice.
You can already do the 'intercept' part of this using RequestInterceptor. Just use RestAdapter.Builder.setRequestInterceptor().
It's a better idea to retrieve the token from the API outside the RequestInterceptor though, as it's not meant to do that. After that first call, you can just add the token anywhere you want in your requests inside RequestInterceptor.intercept().
Something like this:
Builder builder = new RestAdapter.Builder()
//Set Endpoint URL, Retrofit class... etc
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
String authToken = getAuthToken(); //Not included here, retrieve the token.
request.addHeader("Authorization", "Bearer " + authToken);
}
);
Well, you have already implemented your 'blocking' interceptor, your problem is android doesn't let you block the main thread with network calls.
You should probably wrap your retrofit calls in a service class that calls, asynchronously, to your getToken method, and makes the 'main' request only if and when that first one completes succesfully.
As of OkHTTP 2.2, you can now add interceptors that run on the network thread:
https://github.com/square/okhttp/wiki/Interceptors
An example interceptor for adding an auth token might be like this;
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// Get your auth token by going out over the network..
// add authorization header, defaulting to the original request.
Request authedRequest = request;
if (!TextUtils.isEmpty(authToken)) {
authedRequest = request.newBuilder().addHeader("Auth", authToken).build();
}
return chain.proceed(authedRequest);
}

Categories

Resources