AndroidアプリケーションでネットワーキングにOKHTTPクライアントを使用しています。
これ の例は、バイナリファイルをアップロードする方法を示しています。 OKHTTPクライアントでダウンロードするバイナリファイルの入力ストリームを取得する方法を知りたいです。
例のリストは次のとおりです。
public class InputStreamRequestBody extends RequestBody {
private InputStream inputStream;
private MediaType mediaType;
public static RequestBody create(final MediaType mediaType,
final InputStream inputStream) {
return new InputStreamRequestBody(inputStream, mediaType);
}
private InputStreamRequestBody(InputStream inputStream, MediaType mediaType) {
this.inputStream = inputStream;
this.mediaType = mediaType;
}
@Override
public MediaType contentType() {
return mediaType;
}
@Override
public long contentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return 0;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(inputStream);
sink.writeAll(source);
} finally {
Util.closeQuietly(source);
}
}
}
単純なget要求の現在のコードは次のとおりです。
OkHttpClient client = new OkHttpClient();
request = new Request.Builder().url("URL string here")
.addHeader("X-CSRFToken", csrftoken)
.addHeader("Content-Type", "application/json")
.build();
response = getClient().newCall(request).execute();
では、応答をInputStream
に変換するにはどうすればよいですか。 OkHttp
応答に対するApache HTTP Client
からの応答に似たもの:
InputStream is = response.getEntity().getContent();
以下から回答を受け入れました。私の変更されたコード:
request = new Request.Builder().url(urlString).build();
response = getClient().newCall(request).execute();
InputStream is = response.body().byteStream();
BufferedInputStream input = new BufferedInputStream(is);
OutputStream output = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
OKHTTPからByteStreamを取得
私はOkHttpのドキュメントで掘り下げてきました
このメソッドを使用します:
response.body()。byteStream()wichはInputStreamを返します
したがって、単にBufferedReaderまたは他の代替手段を使用できます
OkHttpClient client = new OkHttpClient();
request = new Request.Builder().url("URL string here")
.addHeader("X-CSRFToken", csrftoken)
.addHeader("Content-Type", "application/json")
.build();
response = getClient().newCall(request).execute();
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
response.body().close();
ダウンロードするときに大量のデータを簡単に操作できるようにするために、 okio からresponse.body().source()
をお勧めします(OkHttpは既にネイティブにサポートしているため)。ファイル。
@Override
public void onResponse(Call call, Response response) throws IOException {
File downloadedFile = new File(context.getCacheDir(), filename);
BufferedSink sink = Okio.buffer(Okio.sink(downloadedFile));
sink.writeAll(response.body().source());
sink.close();
}
InputStreamと比較してドキュメントから得られるいくつかの利点:
このインターフェイスは、機能的にInputStreamと同等です。消費されるデータが異種の場合、InputStreamは複数のレイヤーを必要とします。プリミティブ値のDataInputStream、バッファリングのBufferedInputStream、および文字列のInputStreamReaderです。このクラスは、上記のすべてにBufferedSourceを使用します。ソースは、実装不可能なavailable()メソッドを回避します。代わりに、呼び出し元は必要なバイト数を指定します。
Sourceは、InputStreamによって追跡される、安全でない構成マークとリセット状態を省略します。代わりに、呼び出し元は必要なものだけをバッファします。
ソースを実装するとき、効率的に実装するのが面倒で、257の可能な値の1つを返すシングルバイト読み取りメソッドを心配する必要はありません。
また、ソースには、より強力なスキップメソッドがあります。BufferedSource.skip(long)は、途中で戻りません。
これは私がOkhttp + Okioライブラリを使用して、チャンクをダウンロードするたびにダウンロードの進行状況を公開する方法です。
public static final int DOWNLOAD_CHUNK_SIZE = 2048; //Same as Okio Segment.SIZE
try {
Request request = new Request.Builder().url(uri.toString()).build();
Response response = client.newCall(request).execute();
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
File file = new File(getDownloadPathFrom(uri));
BufferedSink sink = Okio.buffer(Okio.sink(file));
long totalRead = 0;
long read = 0;
while (read = (source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
totalRead += read;
int progress = (int) ((totalRead * 100) / contentLength);
publishProgress(progress);
}
sink.writeAll(source);
sink.flush();
sink.close();
publishProgress(FileInfo.FULL);
} catch (IOException e) {
publishProgress(FileInfo.CODE_DOWNLOAD_ERROR);
Logger.reportException(e);
}
ダウンロードに最適なオプション(ソースコード「okio」に基づく)
private void download(@NonNull String url, @NonNull File destFile) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = okHttpClient.newCall(request).execute();
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
BufferedSink sink = Okio.buffer(Okio.sink(destFile));
Buffer sinkBuffer = sink.buffer();
long totalBytesRead = 0;
int bufferSize = 8 * 1024;
for (long bytesRead; (bytesRead = source.read(sinkBuffer, bufferSize)) != -1; ) {
sink.emit();
totalBytesRead += bytesRead;
int progress = (int) ((totalBytesRead * 100) / contentLength);
publishProgress(progress);
}
sink.flush();
sink.close();
source.close();
}
より良い解決策は、OkHttpClientを次のように使用することです。
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// Headers responseHeaders = response.headers();
// for (int i = 0; i < responseHeaders.size(); i++) {
// System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
// }
// System.out.println(response.body().string());
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
}
});