基于Ok+Rxjava+retrofit实现断点续传下载
本文为大家分享了实现断点续传下载的具体代码,供大家参考,具体内容如下
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<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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
基于HTML5代码实现折叠菜单附源码下载
-
Android实现简单断点续传和下载到本地功能
-
基于Java文件输入输出流实现文件上传下载功能
-
Android基于自带的DownloadManager实现下载功能示例
-
基于jquery实现的tab选项卡功能示例【附源码下载】
-
Android多线程断点续传下载功能实现代码
-
Android实现网络多线程断点续传下载功能
-
Android基于OkHttp实现下载和上传图片
-
RxJava+Retrofit+OkHttp实现多文件下载之断点续传
-
基于DevExpress的SpreadsheetControl实现对Excel的打开、预览、保存、另存为、打印(附源码下载)