【问题标题】:java.lang.IllegalStateException because of onResponse code in okhttp async HTTP POST requestjava.lang.IllegalStateException 因为 okhttp 异步 HTTP POST 请求中的 onResponse 代码
【发布时间】:2019-03-30 00:24:42
【问题描述】:

我在这里写了一段代码:

public class Wizard1 extends GuidedStepFragment implements Callback {

    private boolean sendPhoneNumber(String userPhoneNumber) {

        OkHttpClient client = new OkHttpClient();

        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("request_magic_code", Urls.REQUEST_MAGIC_CODE)
                .build();

        Request request = new Request.Builder()
                .url(Urls.HOST + Urls.SEND_PHONE_NUMBER)
                .post(requestBody)
                .build();

        client.newCall(request).enqueue(this);
        return success;
    }

    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        e.printStackTrace();
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        ResponseBody myResponse = response.body();
        Log.d("SS", response.body().string());

    Log.d("SS", response.body().string());

        if (myResponse != null) {
            success = true;
            }

}

当我运行它时,令人惊讶的是我得到了 java.lang.IllegalStateException。更令人惊讶的是,如果我删除第二条 Log.d 行,异常将不会发生!

发生了什么?为什么在 onResponse 中添加虚拟行会导致此错误?

这是完整的错误日志:

10-24 05:16:38.307 6639-6659/com.example.android.persistence W/System.err:java.lang.IllegalStateException:关闭 在 okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:398) 在 okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:392) 在 okhttp3.internal.Util.bomAwareCharset(Util.java:431) 在 okhttp3.ResponseBody.string(ResponseBody.java:174) 10-24 05:16:38.308 6639-6659/com.example.android.persistence W/System.err:
在 android.support.v17.leanback.supportleanbackshowcase.app.wizard.WizardGetPhoneNumber.onResponse(WizardGetPhoneNumber.java:244) 在 okhttp3.RealCall$AsyncCall.execute(RealCall.java:141) 在 okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 在 java.lang.Thread.run(Thread.java:761)

【问题讨论】:

    标签: android retrofit2 okhttp leanback


    【解决方案1】:

    你使用了两次response.body().string()

    来自 OkHttp 3 documentation响应正文只能使用一次。

    你可以创建局部变量并使用它

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        ResponseBody body = response.body();
        if(body != null) {
            try {
                //Use it anytime you want
                String responseString = body.string();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    或者你可以复制 ResponseBody

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        ResponseBody body = response.body();
        //Warning: this method loads the requested bytes into memory. Most
        // applications should set a modest limit on {@code byteCount}, such as 1 MiB.
        int bufferSize = 1024 * 1024;
        ResponseBody copy = response.peekBody(bufferSize);
    }
    

    但要注意正确使用bufferSize,防止OutOfMemoryError

    附:您不需要将字符串记录到 Logcat。调试 OkHttp 客户端的方法很少,例如

    【讨论】:

    • 是的,谢谢,我得到这个是因为 2 个 API 调用具有相同的响应处理回调
    【解决方案2】:

    来自Retrofit 响应的正文只能访问一次,在读取后被清除,在您的情况下第二次登录到控制台。

    来自文档:

    从源服务器到客户端应用程序的一次性流,带有响应正文的原始字节。

    更多详情请关注official documentation

    您应该继续使用已保存的变量myResponse

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多