欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-18 17:33:38
本文为大家分享了实现断点续传下载的具体代码,供大家参考,具体内容如下 1、基于ok+rxjava实现断点续传下载 2、基于ok+rxjava+retrofit实现断点续...

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

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

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

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

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

说下我的大致思路吧:根据文件下载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

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