Reputation: 604
I created the following class:
package com.inverseo.marc.t372lematin;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class PostJSON {
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
public String postJSONRequest(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
System.out.println("postJSONRequest response.body : "+response.body().string());
return response.body().string() ;
} //postJSONRequete
} //class PostJSON
It used to work from an activity where I write some data to MySQL on a server. And when I call it from the following piece of code, I get an empty response !
System.out.println("début appel "+getString(R.string.CF_URL)+"authentication2.php" );
PostJSON client2 = new PostJSON();
JSONObject obj = new JSONObject();
try {
obj.put("username", mUserName);
obj.put("password", mPassword);
obj.put("email", mEmail);
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("obj.toString()="+obj.toString());
String response = null;
try {
response = client2.postJSONRequest(getString(R.string.CF_URL)+ "authentication2.php", obj.toString());
} catch (IOException e) {
e.printStackTrace();
System.out.println("appel d'authentication2.php échoué : " + e);
}
System.out.println("fin authentication2, response = "+response);
return response;
Here is what I get in logcat
02-25 05:52:24.938 26130-26226/com.inverseo.marc.t372lematin I/System.out: Accès à Internet : OK
02-25 05:52:24.938 26130-26226/com.inverseo.marc.t372lematin I/System.out: début appel http://mywebsite.fr/Inverseo/authentication2.php
02-25 05:52:24.938 26130-26226/com.inverseo.marc.t372lematin I/System.out: obj.toString()={"email":"xxx-ts@laposte.net","password":"xxx","username":"MarcUser"}
02-25 05:52:25.068 26130-26130/com.inverseo.marc.t372lematin I/Choreographer: Skipped 30 frames! The application may be doing too much work on its main thread.
02-25 05:52:25.448 26130-26130/com.inverseo.marc.t372lematin I/Choreographer: Skipped 34 frames! The application may be doing too much work on its main thread.
02-25 05:52:27.898 26130-26226/com.inverseo.marc.t372lematin I/System.out: postJSONRequest response.body : {"result":1,"message":"AUTHENTICATION OK","Id_profile":"1394","DebutDerCycle":"2016-01-31"}
02-25 05:52:27.898 26130-26226/com.inverseo.marc.t372lematin I/System.out: fin authentication2, response =
02-25 05:52:28.588 26130-26130/com.inverseo.marc.t372lematin I/Choreographer: Skipped 140 frames! The application may be doing too much work on its main thread.
So to wrap it up, in my PostJSON class, I write the correct result to System.out. Then return it. But the response is then empty. I can't figure out why.
Upvotes: 18
Views: 30706
Reputation: 1043
In my case I wanted to go a bit further, on one hand storing the response body as a string, but without consuming the buffer, to be able to use it as usual.
I have found an efficient solution here: https://github.com/square/okhttp/issues/2869
Basically, you can get a read-only view of the buffer, from which you can read without consuming it, so it still can be used later on.
A snippet of code:
final BufferedSource source = responseBody.source();
if (!source.request(Integer.MAX_VALUE)) {
LOGGER.debug("Error reading response body");
}
final String bodyAsStr = source.buffer().snapshot().utf8();
// you can still use your response body as usual
responseParser.apply(responseBody.byteStream())
With source.string()
instead of source.buffer().snapshot().utf8()
, the stream would be empty.
Upvotes: 2
Reputation: 172
For Kotlin users
val topNewsList = gson.fromJson(body, NewsList::class.java)
getActivity()?.runOnUiThread {
try {
if(topNewsList.post_data != null) {
//set adapter
recyclerView_news.adapter = TopNewsAdapter(topNewsList, layout.row_news)
}
else{
// handle the empty list
}
}
catch (e: Exception) {
Toast.makeText(context, "Please refresh again", Toast.LENGTH_SHORT).show()
}
}
Upvotes: -1
Reputation: 1785
We have to save the response content into a variable of string type.
OkHttpClient client = new OkHttpClient();
try{
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "'{\"id\":\"10001\"}'");
Request request = new Request.Builder()
.url("mydomain")
.post(body)
.addHeader("content-type", "application/json")
.addHeader("cache-control", "no-cache")
.build();
Response response= client.newCall(request).execute();
String MyResult = response.body().string();
return MyResult;
}catch (Exception ex){
return ex.toString();
}
Upvotes: 2
Reputation: 550
You read the body when you called string()
and emptied the backing source. OkHttp attempts to free the backing resource as soon as possible. Reading the body into a variable is the correct way to pass it or store it more in more than one use.
Usually you won't need to close the body, but on Android, where we don't have try-with-resources, I'd recommend closing in a hand-written finally.
Here are the docs on the subject: http://square.github.io/okhttp/3.x/okhttp/
The response body can be consumed only once.
This class may be used to stream very large responses. For example, it is possible to use this class to read a response that is larger than the entire memory allocated to the current process. It can even stream a response larger than the total storage on the current device, which is a common requirement for video streaming applications.
Because this class does not buffer the full response in memory, the application may not re-read the bytes of the response. Use this one shot to read the entire response into memory with bytes() or string(). Or stream the response with either source(), byteStream(), or charStream().
Upvotes: 8
Reputation: 307
Calling response.body().string()
consumes the body - therefore, you can't call it the second time.
The solution is to store it in a variable if you need it for further processing.
There is also a new method available in okhttp3
and that is peekBody(byte count)
which, per documentation, peeks up to byteCount bytes from the response body and returns them as a new response body.
Upvotes: 17
Reputation: 604
I found a solution which sounds weird, at least to me.
I changed the end of the class as following:
String MyResult = response.body().string();
System.out.println("postJSONRequest response.body : "+MyResult);
return MyResult ;
So instead of calling twice response.body().string()
, I put it in a variable.
And it works !
Upvotes: 22