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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM