Earlier we already know how to use OkHttp + Retrofit download files .
When you download a file, you may encounter some unexpected situations, such as a network error or a user pauses a download.
Start download again, if you have to start from scratch, it will be wasted in front of downloaded content.
HTTP functionality can continue to download files from where it left off.
http range request
Range is a request header, which tells the server to return a portion of the file.
In a Range header, the plurality of parts may be disposable request, the server in the form of a multipart document will be returned.
If the server returns a range response requires 206 Partial Content status code.
If the requested range is not legitimate, then the server will return 416 Range Not Satisfiable status code indicating that the client error.
Server allows you to override the header Range, to return the entire file, with a 200 status code.
Examples
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>
When initiating request, the content is generally written in bytes = 0-100 Range of such forms.
When a request or a plurality of portions, a plurality of the specified range.
Range: bytes=200-1000, 2000-6576, 19000-
Content-Range represents the body length or size.
reference:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range
Examples of Use
Reference
https://github.com/RustFisher/android-Basic4/tree/master/appdowloadsample
Use OkHttp add a Range header file tells the server we need the data range.
The method defined in claim incoming @Header ( "Range")
private interface ApiService {
@Streaming
@GET
Observable<ResponseBody> downloadPartial(@Url String url, @Header("Range") String range);
}
Range-passed as string-shaped 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() {
}
});
We also can before downloading, go check the file downloaded portion size, and then decided Range range.
When the resume, write local files attention to the selection append mode stream.
fos = new FileOutputStream(file, true);