Как приостановить / возобновить загрузку с помощью 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);   
        }
Другие вопросы по тегам