Как приостановить / возобновить загрузку с помощью okhttp в Android
Я использую библиотеку okhttp для скачивания файлов в Android. Я успешно загружаю. Но что-то не так, когда я приостанавливаю и возобновляю загрузку.
Response request = new Request.Builder().url(url).build();
ResponseBody responseBody = response.body();
File file = new File(filePath);
BufferedInputStream input = new BufferedInputStream(responseBody.byteStream());
OutputStream output;
if (isResume) {
output = new FileOutputStream(file, true);
input.skip(downloadedSize);
} else {
output = new FileOutputStream(file, false);
}
long totalByteSize = responseBody.contentLength();
byte[] data = new byte[1024];
int count = 0;
while ((count = input.read(data)) != -1) {
downloadedSize += count;
output.write(data, 0, count);
}
Проблема в том, что, например, размер файла составляет 10 МБ. Я делаю паузу, когда он загружает 3 МБ, а затем возобновляет загрузку, и когда загрузка заканчивается, размер файла становится 13 МБ. Он не начинается с загруженного размера при возобновлении, он начинается с начала bytestream. поэтому файл стал 13MB. Что не так с кодом?
3 ответа
ПЕРВЫЙ ПУТЬ
Я перепробовал много кодов и, наконец, решил с помощью BufferedSource source = responseBody.source (); source.skip (downloadedSize);
Response request = new Request.Builder().url(url).build();
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
if(isResume)
source.skip(downloadedSize);
File file = new File(filePath);
BufferedInputStream input = new BufferedInputStream(responseBody.byteStream());
OutputStream output;
if (isResume) {
output = new FileOutputStream(file, true);
} else {
output = new FileOutputStream(file, false);
}
long currentDownloadedSize = 0;
long currentTotalByteSize = responseBody.contentLength();
byte[] data = new byte[1024];
int count = 0;
while ((count = input.read(data)) != -1) {
currentDownloadedSize += count;
output.write(data, 0, count);
}
Это сработало успешно. Я думаю, что мне повезло:)
ВТОРОЙ ПУТЬ
Я добавил заголовок для пропуска скачанных байтов, и это сработало.
Request.Builder requestBuilder = new Request.Builder();
if (isResume) {
requestBuilder.addHeader("Range", "bytes=" + String.valueOf(downloadedSize) + "-");
}
Response request = requestBuilder.url(url).build();
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
File file = new File(filePath);
BufferedInputStream input = new BufferedInputStream(responseBody.byteStream());
OutputStream output;
if (isResume) {
output = new FileOutputStream(file, true);
} else {
output = new FileOutputStream(file, false);
}
long currentDownloadedSize = 0;
long currentTotalByteSize = responseBody.contentLength();
byte[] data = new byte[1024];
int count = 0;
while ((count = input.read(data)) != -1) {
currentDownloadedSize += count;
output.write(data, 0, count);
}
val call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
listener.onFail(e)
}
override fun onResponse(call: Call, response: Response) {
// write the stream to a file (downloading happening)
val stream = response.body?.byteStream()
}
})
// this will stop the downloading
call.cancel()
для возобновления используйте заголовок "Диапазон" с вашим запросом и добавьте поток к уже загруженному файлу.
Основываясь на ответе Александра, я попробовал оба способа, которые он рекомендовал. Первый способ приводил к ошибкам, когда загрузка останавливалась, а затем продолжалась после перезапуска приложения. Я обнаружил, что второй способ более стабилен. Также в коде имеется синтаксическая ошибка. Пример кода здесь.
File file = new File(path);
long availableFileLength = file.exists() && file.isFile() ? file.length() :0;
Request.Builder requestBuilder = new Request.Builder();
requestBuilder.addHeader("Range", "bytes=" + String.valueOf(availableFileLength) + "-");
Request request = requestBuilder.url(url).build();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.build();
ResponseBody responseBody = okHttpClient.newCall(request).execute().body();
InputStream input = new BufferedInputStream(responseBody.byteStream());
OutputStream output = new FileOutputStream(downloadPath, true);
long currentDownloadedSize = 0;
long currentTotalByteSize = responseBody.contentLength();
byte[] data = new byte[1024];
int count = 0;
while ((count = input.read(data)) != -1) {
currentDownloadedSize += count;
output.write(data, 0, count);
}