OkHttpライブラリを介してhttp呼び出しを実装します。すべて正常に動作しますが、応答の文字列として2回本文にアクセスすると、IllegalStateException
がスローされることに気付きました。つまり、(たとえば)Log.d("TAG", response.body().string())
を実行し、その後、実際にprocessResponse(response.body().string())
のような文字列を使用したいのです。しかし、その2番目の呼び出しは、メッセージclosed
で例外をスローします。
文字列に2回アクセスすると失敗する可能性はありますか?いくつかの値(ヘッダー、ボディ、ステータスコードなど)を保存するためだけに、ラッパー/ダミーオブジェクトを追加する必要なく、その応答を処理したいと思います。
応答のstring
メソッドは、入力(ネットワーク)ストリームを読み取り、それを文字列に変換します。そのため、文字列を動的に構築し、それを返します。 2回目に呼び出すと、ネットワークストリームはすでに消費されており、使用できなくなります。
string
の結果をString変数に保存し、必要な回数だけアクセスする必要があります。
更新:
mugwortが指摘 よりシンプルで軽量なAPIが利用可能になりました( GitHubの問題を参照 ):
String responseBodyString = response.peekBody(Long.MAX_VALUE).string();
Log.d("TAG", responseBodyString);
元の答え:
問題の説明については、 Greg Ennis 'answer を参照してください。
ただし、結果を変数に簡単に渡すことができず、応答本文に2回アクセスする必要がある場合は、別のオプションがあります。
読み込む前にバッファを複製します。それにより、元のバッファは空にも閉じられません。このスニペットをご覧ください:
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // request the entire body.
Buffer buffer = source.buffer();
// clone buffer before reading from it
String responseBodyString = buffer.clone().readString(Charset.forName("UTF-8"))
Log.d("TAG", responseBodyString);
このアプローチは、プロジェクト内の HttpLoggingInterceptor で使用されます okhttp 正方形自体。
ところで、グレッグエニスの答えに加えて、ウォッチウィンドウでresponse.body()。string()を忘れたときに、これがいつ起こったかを知ることができます。そのため、デバッガーの下では、本体がウォッチを読み取り、その後ネットワークストリームが閉じられました。
ser2011622 および Greg Ennis の答えを少し拡大して、本文の完全なクローンを作成するのに役立つメソッドを作成しました。本体は個別に。 Retrofit2でこのメソッドを自分で使用します
/**
* Clones a raw buffer so as not to consume the original
* @param rawResponse the original {@link okhttp3.Response} as returned
* by {@link Response#raw()}
* @return a cloned {@link ResponseBody}
*/
private ResponseBody cloneResponseBody(okhttp3.Response rawResponse) {
final ResponseBody responseBody = rawResponse.body();
final Buffer bufferClone = responseBody.source().buffer().clone();
return ResponseBody.create(responseBody.contentType(), responseBody.contentLength(), bufferClone);
}
response.peekBody(Long.MAX_VALUE);
を呼び出して、メモリ内の応答全体をバッファし、その軽量コピーを取得できます。無駄がずっと少なくなります。 GitHubでこの問題を参照 。
ResponseBody body = response.peekBody(Long.MAX_VALUE);
String content = body.string();
//do something
このコードは応答本文を取得し、バッファーを消費しません。 この問題 に追加された新しいAPIです