Android OkHttp + Retrofit 断点续传

Android 2020

本文链接

前面我们已经知道如何使用OkHttp+Retrofit下载文件
下载文件时,可能会遇到一些意外情况,比如网络错误或是用户暂停了下载。
再次启动下载,如果又要从头开始,会白白浪费前面下载好的内容。
断点续传功能可以从上次停止的地方继续下载文件。

http范围请求

Range 是一个请求首部,告知服务器返回文件的哪一部分。
在一个 Range 首部中,可以一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。
如果服务器返回的是范围响应,需要使用 206 Partial Content 状态码。
假如所请求的范围不合法,那么服务器会返回 416 Range Not Satisfiable 状态码,表示客户端错误。
服务器允许忽略Range首部,从而返回整个文件,状态码用200。

示例

Range: <unit>=<range-start>-
Range: <unit>=<range-start>-<range-end>
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>

发起请求时,一般Range的内容写成 bytes=0-100 这样的形式。
或者请求多个部分时,指定多个范围。

Range: bytes=200-1000, 2000-6576, 19000- 

Content-Range 表示主体长度或者尺寸。

参考:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range

使用示例

参考
https://github.com/RustFisher/android-Basic4/tree/master/appdowloadsample

使用OkHttp添加Range头部,告知服务器我们需要的文件数据范围。

定义的方法中要求传入 @Header("Range")

    private interface ApiService {
        @Streaming
        @GET
        Observable<ResponseBody> downloadPartial(@Url String url, @Header("Range") String range);
    }

需要传入的Range字符串形如 bytes=200-1000

retrofit.create(ApiService.class)
    .downloadPartial(callBack.getUrl(), "bytes=" + startByte + "-")
    .subscribeOn(Schedulers.newThread())
    .observeOn(Schedulers.io())
    .doOnNext(new Consumer<ResponseBody>() {
        @Override
        public void accept(ResponseBody responseBody) throws Exception {
            callBack.saveFile(responseBody);
        }
    })
    .doOnError(new Consumer<Throwable>() {
        @Override
        public void accept(Throwable throwable) throws Exception {
            tellDownloadError(callBack.getUrl(), throwable);
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<ResponseBody>() {
        @Override
        public void onSubscribe(Disposable d) {

        }

        @Override
        public void onNext(ResponseBody responseBody) {

        }

        @Override
        public void onError(Throwable e) {
            callBack.setState(DownloadTaskState.ERROR);
            tellDownloadError(callBack.getUrl(), e);
        }

        @Override
        public void onComplete() {

        }
    });

我们也可以在下载前,先去检查文件已下载的部分的大小,再决定Range范围。
续传时,写入本地文件注意选择流的append模式。

fos = new FileOutputStream(file, true);
posted @   AnRFDev  阅读(1700)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示