改造 1.9 原始响应无法在成功回调中处理

Posted

技术标签:

【中文标题】改造 1.9 原始响应无法在成功回调中处理【英文标题】:Retrofit 1.9 raw response cannot be processed in success callback 【发布时间】:2016-03-22 09:18:59 【问题描述】:

我的第一个理解是ProGuard导致Retrofit成功回调中无法检索到响应对象。但是问题是 Retrofit 根据日志级别在成功回调中返回原始响应对象(第二个参数)。

在下面查看我自己的答案。

Google 报告的 IOException:

com.google.a.ae:java.io.IOException:关闭于 com.google.a.k.a(未知来源)在 com.google.a.k.a(未知来源) 在 com.myapp.rest.model.ApiResponse.parseResponse(Unknown Source) 在 com.myapp.service.e.a(未知来源)在 com.myapp.service.e.success(未知来源)在 retrofit.CallbackRunnable$1.run(Unknown Source) at android.os.Handler.handleCallback(Handler.java:739) 在 android.os.Handler.dispatchMessage(Handler.java:95) 在 android.os.Looper.loop(Looper.java:155) 在 android.app.ActivityThread.main(ActivityThread.java:5696) 在 java.lang.reflect.Method.invoke(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) 原因:java.io.IOException:在 c.x.read 关闭(未知来源) 在 java.io.InputStreamReader.read(InputStreamReader.java:231) 在 java.io.BufferedReader.fillBuf(BufferedReader.java:145) 在 java.io.BufferedReader.read(BufferedReader.java:333) 在 com.google.a.d.a.b(未知来源)在 com.google.a.d.a.b(未知 来源)在 com.google.a.d.a.A(未知来源)在 com.google.a.d.a.o(未知来源)在 com.google.a.d.a.f(未知 来源)... 14 更多

异步改造请求:

@POST("/api/myobjects")
void newMyObject(@Body MyObject myObject, Callback<MyObject> cb);

改造成功回调:

public void success(MyObject myObject, Response raw) 
    try  
        ApiResponse res = ApiResponse.parseResponse(raw);
     catch (IOException | NullPointerException e) 
        super.failure(RetrofitError.unexpectedError(raw.getUrl(), e));
    

并解析 API 响应:

public static ApiResponse parseResponse(Response response) throws IOException 
    final Gson gson = new Gson();
    final BufferedReader reader = new BufferedReader(new InputStreamReader(response.getBody().in()));
    return gson.fromJson(reader, ApiResponse.class);

按照 Retrofit 和 Gson 指南实施 ProGuard:

-dontwarn rx.**
-dontwarn okio.**
-dontwarn jce.**
-dontwarn javax.naming.**

# keep okhttp & retrofit following retrofit guidelines
-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.**  *; 
-keep interface com.squareup.okhttp.**  *; 

-dontwarn retrofit.**
-keep class retrofit.**  *; 
-keepclasseswithmembers class * 
    @retrofit.http.* <methods>; 

# keep gson following google guidelines
-keep class sun.misc.Unsafe  *; 
-keep class com.google.gson.stream.**  *; 

# keep application classes that are serialized/deserialized over Gson
-keep class com.myapp.rest.model.**  *; 

# keep the data for stacktraces
-keepattributes *Annotation*
-keepattributes Signature
-keepattributes LineNumberTable
-keepattributes Exceptions

一些进一步的分析表明响应是可用的, 但是在解析响应对象时连接已经关闭。 下面的日志显示可以检索到响应 URL 和状态 在改造成功回调中。

12-17 10:39:46.639 4192-4192/?我/com.myapp.service.e: https://urlto/api/myobjects?locale=en&app=xxx12-17 10:39:46.639 4192-4192/?我/com.myapp.service.e:好的 12-17 10:39:46.649 4192-4192/?W​​/dalvikvm:threadid=1:线程以未捕获的方式退出 异常(组=0x4208f8e0)12-17 10:39:46.669 4192-4192/? E/AndroidRuntime: 致命例外: main com.google.gson.ae: java.io.IOException:在 com.google.gson.k.a 关闭(未知来源)

【问题讨论】:

【参考方案1】:

经过进一步研究,它表明当日志级别未满时,Retrofit 不返回原始响应正文(输入流已读取并关闭)是一个已知功能。

请参阅:https://github.com/square/retrofit/issues/953(已关闭)。我不清楚它为什么要关闭,因为第二个参数的行为会因日志级别而异。

其他人建议的解决方法是在第一个参数中返回 Response 对象。替代方法是将日志级别保持为 FULL。

【讨论】:

以上是关于改造 1.9 原始响应无法在成功回调中处理的主要内容,如果未能解决你的问题,请参考以下文章

如何将改造回调响应中的回调从 java 转换为 Kotlin

jQuery $get 处理error回调

通过在改造中透明地发送另一个请求来处理特定错误

在 Kotlin 中为成功和错误处理两种不同的改造响应

改造解析JSON响应空值Android

改造回调获取响应体