Android &引用;返回response.body().string();是空的,带有okhttp3
我创建了以下类:Android &引用;返回response.body().string();是空的,带有okhttp3,android,okhttp3,Android,Okhttp3,我创建了以下类: 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 stati
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
它曾经在一个活动中工作,我在服务器上向MySQL写入一些数据。
当我从下面的代码调用它时,我得到一个空的响应
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;
这是我在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.
最后,在我的PostJSON类中,我将正确的结果写入System.out。然后把它还给我。但结果却是空的。
我不明白为什么。我找到了一个听起来很奇怪的解决方案,至少对我来说是这样 我改变了课程的结尾如下:
String MyResult = response.body().string();
System.out.println("postJSONRequest response.body : "+MyResult);
return MyResult ;
因此,我没有调用两次response.body().string()
,而是将其放入变量中。
而且它有效 调用
response.body().string()
会消耗主体-因此,您不能第二次调用它。
如果需要进一步处理,解决方案是将其存储在变量中
在
okhttp3
中还有一个新方法可用,即peekBody(byte count)
,根据文档,它从响应体中最多窥视字节计数字节,并将其作为新的响应体返回。当调用string()
并清空备份源代码时,您会读取该体。OkHttp尝试尽快释放备份资源。将正文读入变量是在多次使用中传递或存储正文的正确方法
通常你不需要关闭主体,但在Android上,我们没有资源试用,我建议最后用手写的方式关闭
以下是关于该主题的文档:
响应主体只能使用一次。
此类可用于流式传输非常大的响应。例如,可以使用该类读取大于分配给当前进程的整个内存的响应。它甚至可以传输比当前设备上的总存储容量更大的响应,这是视频流应用程序的常见要求
由于此类不会在内存中缓冲完整响应,因此应用程序可能不会重新读取响应的字节。使用这一次,使用bytes()或string()将整个响应读取到内存中。或者使用source()、byteStream()或charStream()流式传输响应
我们必须将响应内容保存到字符串类型的变量中
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();
}
适用于Kotlin用户
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()
}
}
在我的例子中,我想更进一步,一方面将响应主体存储为字符串,但不消耗缓冲区,以便能够像往常一样使用它 我在这里找到了一个有效的解决方案: 基本上,您可以获得缓冲区的只读视图,从中可以读取而不使用它,因此以后仍然可以使用它 一段代码:
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())
使用
source.string()
而不是source.buffer().snapshot().utf8()
,流将是空的。你说得对,这很奇怪。但这也是OkHttp的工作原理(根据设计)。调用response.body().string()后,信息将被清除,这意味着第二次调用时将不会收到任何信息。在源代码后面有一个缓冲区,string()会使用它,因此任何后续调用都不会找到任何可使用的信息。如果您想阅读多次,可以使用“中继”类。