Download binary file from OKHTTP
The best option to download (based on source code "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();
}
This is how I use Okhttp + Okio libraries while publishing download progress after every chunk download:
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);
}
Getting ByteStream from OKHTTP
I've been digging around in the Documentation of OkHttp you need to go this way
use this method :
response.body().byteStream() wich will return an InputStream
so you can simply use a BufferedReader or any other alternative
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();
For what it's worth, I would recommend response.body().source()
from okio (since OkHttp is already supporting it natively) in order to enjoy an easier way to manipulate a large quantity of data that can come when downloading a file.
@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();
}
A couple of advantages taken from the documentation in comparison with InputStream:
This interface is functionally equivalent to InputStream. InputStream requires multiple layers when consumed data is heterogeneous: a DataInputStream for primitive values, a BufferedInputStream for buffering, and InputStreamReader for strings. This class uses BufferedSource for all of the above. Source avoids the impossible-to-implement available() method. Instead callers specify how many bytes they require.
Source omits the unsafe-to-compose mark and reset state that's tracked by InputStream; callers instead just buffer what they need.
When implementing a source, you need not worry about the single-byte read method that is awkward to implement efficiently and that returns one of 257 possible values.
And source has a stronger skip method: BufferedSource.skip(long) won't return prematurely.