Home » Android » android – "return response.body().string() " is empty with okhttp3

android – "return response.body().string() " is empty with okhttp3

Posted by: admin May 14, 2020 Leave a comment

Questions:

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":"[email protected]","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.

How to&Answers:

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 !

Answer:

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.

Answer:

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().

Answer:

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();
    }

Answer:

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()
  }
}