基于Ok+Rxjava实现断点续传下载

本文为大家分享了实现断点续传下载的具体代码,供大家参考,具体内容如下

1、基于Ok+Rxjava实现断点续传下载

2、基于Ok+Rxjava+Retrofit实现断点续传下载

最近总结一下了一下之前学过以及用到过得功能,整理了一个基于Ok+Rxjava实现断点续传下载的demo。下面先给大家展示一下使用效果吧。

 

说下我的大致思路吧:根据文件下载url按照自己定义的规则生成文件名,判断本地同路径下是否存在此文件,如果存在,文件大小与服务器上获取的文件大小一致的情况下,则生成新的文件名重新下载;如果文件比服务器获取的文件大小小,则执行断点下载,从本地文件长度处开始下载。如果文件不存在,则从0字节开始下载。

DownloadSubscribe(被观察者)中执行下载存入本地操作

核心还是:addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)

DownLoadObserver(观察者)通过onnext(DownloadInfo downloadInfo)方法回调下载进度

下面上主要代码:

/**

* 开始下载

* @param url 下载请求的网址

* @param downFileCallback 用来回调的接口

*/

public void download(final String url, final DownFileCallback downFileCallback) {

if (url == null || downCalls.get(url) != null) {

return;

}

Observable.just(url)

.filter(new Predicate<String>() {

@Override

public boolean test(String s) throws Exception {

//过滤条件 若map中存在,则这次不下载

return !downCalls.containsKey(s);

}

})

.flatMap(new Function<String, ObservableSource<DownloadInfo>>() {

@Override

public ObservableSource<DownloadInfo> apply(String s) throws Exception {

//创建下载实体类

return Observable.just(createDownInfo(s));

}

})

.map(new Function<DownloadInfo, DownloadInfo>() {

@Override

public DownloadInfo apply(DownloadInfo s) throws Exception {

//根据本地是否存在此文件,来设置文件名及文件初始下载大小

return getRealFileName(s);

}

})

.flatMap(new Function<DownloadInfo, ObservableSource<DownloadInfo>>() {

@Override

public ObservableSource<DownloadInfo> apply(DownloadInfo downloadInfo) throws Exception {

//创建被观察者

return Observable.create(new DownloadSubscribe(downloadInfo));

}

})//下载

.observeOn(AndroidSchedulers.mainThread())//在主线程回调

.subscribeOn(Schedulers.io())//在子线程执行

.subscribe(new DownLoadObserver() {//添加观察者

@Override

public void onNext(DownloadInfo downloadInfo) {

super.onNext(downloadInfo);

downFileCallback.onProgress(downloadInfo.getTotal(), downloadInfo.getProgress());

}

@Override

public void onError(Throwable e) {

super.onError(e);

if (!(e instanceof SocketException)) {

downFileCallback.onFail(e.getMessage());

}

}

@Override

public void onComplete() {

downFileCallback.onSuccess(url);

}

});

}

/**

* 根据url暂停下载操作

* @param url

*/

public void cancel(String url) {

Call call = downCalls.get(url);

if (call != null) {

call.cancel();//取消

}

downCalls.remove(url);

}

/**

* 创建被观察者DownloadSubscribe

*/

private class DownloadSubscribe implements ObservableOnSubscribe<DownloadInfo> {

private DownloadInfo downloadInfo;

public DownloadSubscribe(DownloadInfo downloadInfo) {

this.downloadInfo = downloadInfo;

}

@Override

public void subscribe(ObservableEmitter<DownloadInfo> e) throws Exception {

String url = downloadInfo.getUrl();

long downloadLength = downloadInfo.getProgress();//已经下载好的长度

long contentLength = downloadInfo.getTotal();//文件的总长度

//初始进度信息

e.onNext(downloadInfo);

Request request = new Request.Builder()

//断点续传的核心

.addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)

.url(url)

.build();

Call call = mClient.newCall(request);

//根据下载url,把call存放在map中,取消的时候就可以通过call.cancle()来实现

downCalls.put(url, call);

Response response = call.execute();

File file = new File(getTemporaryPath(), downloadInfo.getFileName());

InputStream is = null;

FileOutputStream fileOutputStream = null;

try {

is = response.body().byteStream();

fileOutputStream = new FileOutputStream(file, true);

byte[] buffer = new byte[2048];//缓冲数组2kB

int len;

while ((len = is.read(buffer)) != -1) {

fileOutputStream.write(buffer, 0, len);

downloadLength += len;

downloadInfo.setProgress(downloadLength);

e.onNext(downloadInfo);

}

fileOutputStream.flush();

downCalls.remove(url);

} finally {

//关闭IO流

IOUtil.closeAll(is, fileOutputStream);

}

e.onComplete();//完成

}

}

/**

* 从服务器获取文件长度

*

* @param downloadUrl

* @return

*/

private long getContentLength(String downloadUrl) {

Request request = new Request.Builder()

.url(downloadUrl)

.build();

try {

Response response = mClient.newCall(request).execute();

if (response != null && response.isSuccessful()) {

long contentLength = response.body().contentLength();

response.close();

return contentLength == 0 ? DownloadInfo.TOTAL_ERROR : contentLength;

}

} catch (IOException e) {

e.printStackTrace();

}

return DownloadInfo.TOTAL_ERROR;

}

从服务器获取文件长度的时候注意一下,Android P之后,也就是api 28以上禁止明文网络传输。需要在你的AndroidManifest中的application标签中声明"android:usesCleartextTraffic="true",允许应用进行明文传输。

使用方法:首先要获取sd卡权限

DownloadManager.getInstance().downloadPath(本地存在地址).download(url1, new DownFileCallback() {

@Override

public void onProgress(long totalSize, long downSize) {

progress1.setMax((int) totalSize);

progress1.setProgress((int) downSize);

}

@Override

public void onSuccess(String url) {

Toast.makeText(MainActivity.this, url1 + "下载完成", Toast.LENGTH_SHORT).show();

}

@Override

public void onFail(String msg) {

Toast.makeText(MainActivity.this, url1 + "下载失败", Toast.LENGTH_SHORT).show();

}

});

好了今天就到这里,希望能帮到大家,这对我来说也是一种加深印象的笔记,

下载地址demo

git地址:DownloadManager 欢迎star

以上是 基于Ok+Rxjava实现断点续传下载 的全部内容, 来源链接: utcz.com/z/352953.html

回到顶部