当前位置: 移动技术网 > IT编程>开发语言>Java > 基于Ok+Rxjava+retrofit实现断点续传下载

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

2019年07月19日  | 移动技术网IT编程  | 我要评论

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

1、基于ok+rxjava实现断点续传下载

2、基于ok+rxjava+retrofit实现断点续传下载

上一篇博客中介绍了基于ok+rxjava实现断点续传下载,这一篇给大家介绍下基于ok+rxjava+retrofit实现断点续传下载,,效果图跟上一篇图片一样,哈哈

 说下我的大致思路吧(跟上一篇略有不同):根据文件下载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<responsebody> 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<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, observable<responsebody>>() {
 @override
 public observable<responsebody> apply(downloadinfo downinfo) throws exception {
 return httpservice.download("bytes=" + downinfo.getprogress() + "-", downinfo.geturl());
 }
 })//下载
 .map(new function<responsebody, downloadinfo>() {
 @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<downloadinfo>() {
 @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 = 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);
 }
 });
 }
 });

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

github地址:downmanager  欢迎star

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网