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

网友投稿 316 2023-01-03


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

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

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

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

上一篇博客中介绍了基于Ok+Rxjava实现断点续传下载,这一篇给大家介绍下基于Ok+Rxjava+Retrofit实现断点续传下载,demo下载地址,效果图跟上一篇图片一样,哈哈

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

还有的不同是,这里需要重新ResponseBody的source()方法,在这里监听文件下载的进度,然后通过我么自定义的Downloadinterceptor把我们重新的DownloadResponseBody给设置进去,从而完成我们的进度监听工作。

下面还是上主要代码:

首先重写ResponseBody

public class DownloadResponseBody extends ResponseBody {

private ResponseBody responseBody;

//进度回调接口

private DownFileCallback downFileCallback;

private BufferedSource bufferedSource;

private String downUrl;

public DownloadResponseBody(ResponseBody responseBody, DownFileCallback downFileCallback, String downUrl) {

this.responseBody = responseBody;

this.downFileCallback = downFileCallback;

this.downUrl = downUrl;

}

@Override

public MediaType contentType() {

return responseBody.contentType();

}

@Override

public long contentLength() {

return responseBody.contentLength();

}

@Override

public BufferedSource source() {

if (bufferedSource == null) {

bufferedSource = Okio.buffer(source(responseBody.source()));

}

return bufferedSource;

}

private Source source(Source source) {

return new ForwardingSource(source) {

long totalBytesRead = 0L;

File file = new File(DownloadManager.getInstance().getTemporaryName(downUrl));

@Override

public long read(Buffer sink, long byteCount) throws IOException {

long bytesRead = super.read(sink, byteCount);

totalBytesRead += bytesRead != -1 ? bytesRead : 0;

if (null != downFileCallback) {

if (bytesRead != -1) {

long loacalSize = file.length();//本地已下载的长度

long trueTotal = loacalSize + responseBody.contentLength() - totalBytesRead;//文件真实长度

downFileCallback.onProgress(trueTotal,loacalSize);

} else {

}

}

return bytesRead;

}

};

}

}

重写Interceptor

public class Downloadinterceptor implements Interceptor {

private DownFileCallback downFileCallback;

private String downUrl;

public Downloadinterceptor(DownFileCallback listener,String downUrl) {

this.downFileCallback = listener;

this.downUrl = downUrl;

}

@Override

public Response intercept(Chain chain) throws IOException {

Response response = chain.proceed(chain.request());

return response.newBuilder()

.body(new DownloadResponseBody(response.body(), downFileCallback,downUrl))

.build();

}

}

然后我们的service

public interface HttpService {

/*大文件需要加入Streaming这个判断,防止下载过程中写入到内存中,造成oom*/

@Streaming

@GET

Observable download(@Header("range") String start, @Url String url);

}

接下来我们的DownloadManager中download方法

/**

* 开始下载

* @param url 下载地址

* @param downFileCallback 进度回调接口

*/

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

/*正在下载不处理*/

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

return;

}

Downloadinterceptor interceptor = new Downloadinterceptor(downFileCallback, url);

okHttpClient = new OkHttpClient.Builder()

.addInterceptor(interceptor)

.build();

Retrofit retrofit = new Retrofit.Builder()

.client(okHttpClient)

.baseUrl("http://imtt.dd.qq.com")

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

.build();

final HttpService httpservice = retrofit.create(HttpService.class);

ProgressDownSubscriber subscriber =

Observable.just(url)

.flatMap(new Function>() {

@Override

public ObservableSource apply(String s) throws Exception {

return Observable.just(createDownInfo(s));

}

})

.map(new Function() {

@Override

public DownloadInfo apply(DownloadInfo s) throws Exception {

return getRealFileName(s);

}

})

.flatMap(new Function>() {

@Override

public Observable apply(DownloadInfo downInfo) throws Exception {

return httpservice.download("bytes=" + downInfo.getProgress() + "-", downInfo.getUrl());

}

})//下载

.map(new Function() {

@Override

public DownloadInfo apply(ResponseBody responsebody) {

try {

return writecache(responsebody, url);

} catch (IOException e) {

//*失败抛出异常*//

e.printStackTrace();

}

return null;

}

})

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

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

.subscribeWith(new ProgressDownSubscriber() {

@Override

public void onNext(DownloadInfo downInfo) {

downFileCallback.onSuccess(downInfo);

submap.remove(downInfo.getUrl());

}

@Override

public void onError(Throwable t) {

downFileCallback.onFail(t.getMessage());

submap.remove(url);

}

});

submap.put(url, subscriber);

}

然后暂停操作:

/**

* 暂停下载

*/

public void stop(String url) {

if (url == null) return;

if (submap.containsKey(url)) {

ProgressDownSubscriber subscriber = submap.get(url);

subscriber.dispose();

submap.remove(url);

}

}

从服务器获取文件长度

/**

* 从服务器获取文件长度

*

* @param downloadUrl

* @return

*/

private long getContentLength(String downloadUrl) {

Request request = new Request.Builder()

.url(downloadUrl)

.build();

try {

Response response JIBqh= 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 onSuccess(DownloadInfo info) {

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

}

@Override

public void onFail(String msg) {

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

}

@Override

public void onProgress(final long totalSize, final long downSize) {

// 需要注意的是,如果文件总大小为50M,已下载的大小为10M,

// 再次下载时onProgress返回的totalSize是文件总长度

// 减去 已下载大小 10M, 即40M,downSize为本次下载的已下载量

// 好消息是,我已经在内部做过处理,放心使用吧,但是这个问题大家还是要知道的

runOnUiThread(new Runnable() {

@Override

public void run() {

int progress = (int) (downSize * 100 / totalSize);

progress1.setProgress(progress);

}

});

}

});

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

demo下载地址

github地址:DownManager  欢迎star


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:深入了解java Lombok的使用方法
下一篇:关于财付通接口测试工具下载的信息
相关文章

 发表评论

暂时没有评论,来抢沙发吧~