在用自定义GsonConverterFactory 中解析数据出现异常
retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall@5c86aee==java.lang.IllegalStateException: closed===closed```
完整如下:
java.lang.IllegalStateException: closed
at okio.RealBufferedSource.read(RealBufferedSource.java:44)
at okio.ForwardingSource.read(ForwardingSource.java:35)
at retrofit2.OkHttpCall$ExceptionCatchingRequestBody$1.read(OkHttpCall.java:290)
at okio.RealBufferedSource.request(RealBufferedSource.java:68)
at okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:418)
at okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:402)
at okhttp3.internal.Util.bomAwareCharset(Util.java:432)
at okhttp3.ResponseBody$BomAwareReader.read(ResponseBody.java:249)
at com.google.gson.stream.JsonReader.fillBuffer(JsonReader.java:1295)
at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1333)
at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:549)
at com.google.gson.stream.JsonReader.peek(JsonReader.java:425)
开始怀疑是数据实体类没有写对,经过确认,实体类并没毛病,查询其它博客发现,在
@Override
public T convert(ResponseBody value) throws IOException {
try {.. }
}
对value (ResponseBody)只能读取一次 , 如果你调用了response.body().string()两次或者response.body().charStream()两次就会出现这个异常, 先调用string()再调用charStream()也不可以.
查看ResponseBody源码描述,
* <p>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
* {@link #bytes()} or {@link #string()}. Or stream the response with either {@link #source()},
* {@link #byteStream()}, or {@link #charStream()}.
*/
public abstract class ResponseBody implements Closeable {
/** Multiple calls to {@link #charStream()} must return the same instance. */
private Reader reader;
public abstract @Nullable MediaType contentType();
因为ResponseBody类不会在内存中缓冲完整响应,所以应用程序可能不会 重新读取响应的字节
value值是一次性的,而在自定义GsonConverterFactory 中,我用了2次,第二次读取不到,造成异常的发生
解决办法:保存一个ResponseBody
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
HttpStatus httpStatus = gson.fromJson(response, HttpStatus.class);
if (httpStatus.isCodeInvalid()) {
value.close();
throw new ApiException(httpStatus.getCode(), httpStatus.getMessage());
}
MediaType contentType = value.contentType();
Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
InputStream inputStream = new ByteArrayInputStream(response.getBytes());
Reader reader = new InputStreamReader(inputStream, charset);
JsonReader jsonReader = gson.newJsonReader(reader);
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}