热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要为大家详细介绍了基于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() {
  @Override
  public boolean test(String s) throws Exception {
  //过滤条件 若map中存在,则这次不下载
  return !downCalls.containsKey(s);
  }
 })
 .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 ObservableSource 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 {
 private DownloadInfo downloadInfo;
 
 public DownloadSubscribe(DownloadInfo downloadInfo) {
 this.downloadInfo = downloadInfo;
 }
 
 @Override
 public void subscribe(ObservableEmitter 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

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


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
author-avatar
jasonmysh
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有