由于okhttp异步HTTP POST请求中的onResponse代码导致java.lang.IllegalStateException

时间:2018-10-25 11:41:45

标签: android retrofit2 okhttp leanback

我在这里写了一个代码:

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 LINE,则不会发生例外情况!

发生了什么事?为什么在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)

2 个答案:

答案 0 :(得分:3)

Retrofit响应中的正文仅可以访问一次,读取后将被清除,您的情况是第二次登录控制台。

摘自文档:

  

从原始服务器到客户端应用程序的一站式流,其中包含响应主体的原始字节。

有关official documentation的更多详细信息。

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

答案 1 :(得分:3)

您两次使用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

P.s。您无需将字符串记录到Logcat。调试OkHttp客户端的有效方法很少,例如