okhttp-OkGo的文件下载模块
OkDownload主要功能
- 结合OkGo的request进行网络请求,支持与OkGo保持相同的配置方法和传参方式
- 支持断点下载,支持突然断网,强杀进程后,继续断点下载
- 每个下载任务具有无状态、下载、暂停、等待、出错、完成共六种状态
- 所有下载任务按照tag区分,切记不同的任务必须使用不一样的tag,否者断点会发生错乱
- 相同的下载url地址,如果使用不一样的tag,也会认为是两个下载任务
- 不同的下载url地址,如果使用相同的tag,会认为是同一个任务,导致断点错乱
- 默认同时下载数量为3个,默认下载路径
/storage/emulated/0/download
,下载路径和下载数量都可以在代码中配置 - 下载文件名可以自己定义,也可以不传,让框架自动获取文件名
注意!!!
OkGo与OkDownload的区别就是,OkGo只是简单的做一个下载功能,不具备断点下载,暂停等操作,但是这在很多时候已经能满足需要了。
而有些app需要有一个下载列表的功能,就像迅雷下载一样,每个下载任务可以暂停,可以继续,可以重新下载,可以有下载优先级,这时候OkDownload就有用了。
OkDownload只是对OkGo功能的一个扩展升级,如果你不需要使用下载管理的功能,那么就不需要导入该包。
废话不多说,看看怎么用。
全局配置
直接上代码,如图:
- 支持设置全局下载文件夹,以后每个任务如果不设置文件夹,将默认用这个路径,如果不设置,默认就是图中的目录。
- 可以设置同时下载的任务数量,如果不设置,默认就是3个,改方法只在第一次调用时生效,以后无效
- 可以设置所有任务的监听,比如全部任务开始的时候做点事情,全部完成后做点事情。
- 记得监听可以取消,否则可能会发生内存泄露。
此外,OkDownload不仅有全局相关的设置,还有对全部任务的同时操作能力。 例如如下方法:
- startAll():开始所有任务,或者继续下载所有暂停的任务都是这个方法
- pauseAll():将全部下载中的任务暂停
- removeAll():移除所有任务,无论这个任务是在下载中、暂停、完成还是其他任何状态,都可以直接移除这个任务,他有一个重载方法,接受一个boolen参数,true表示删除任务的时候同时删除文件,false表示只删除任务,但是文件保留在手机上。不传的话,默认为false,即不删除文件。
- removeTask():根据tag移除任务
- getTaskMap():获取当前所有下载任务的map
- getTask():根据tag获取任务
- hasTask():标识为tag的任务是否存在
Progress对象
在使用之前,先介绍一个对象,这个对象是我们在做进度回调时,无论是上传进度回调,还是下载进度回调,无论是使用OkGo
,OkDownload
,或则OkUpload
时候,都会碰到一个对象,叫Progress
对象,他保存了当前进度的很多信息,源码中的定义如下,字段很多,但是我觉得看字段名和后面的注释就能知道是什么作用了,所以如果你需要什么进度信息,直接就能取出来。
唯一需要说明的一点是,最顶部对应的6个静态常量,表示下载的状态,其实就是对应下面的status
字段的,该字段永远是这六个状态中的一个。
基本断点下载方法
我们首先看看一个最基本的下载任务是怎么写的,先给代码如下: 以上的几行代码就完成了下载文件的断点下载,可以开始,暂停,继续,重新下载等,是不是很简单,关于以上代码,详细说明如下:
- 构建一个下载请求Request,这个构建方法和OkGo是一样的,params参数和headers参数是只是演示使用,一切OkGo的使用方法,这里都是一样的。
- 构建下载任务,使用OkDownload中的request方法,传入一个tag和我们上一步创建的request对象,创建出下载任务,其他的方法我们下文在细讲。
- 启动任务,我们已经得到了DownloadTask任务对象,那么简单调用start启动他就好了,同时他还支持这么几个方法:
- start():开始一个新任务,或者继续下载暂停的任务都是这个方法
- pause():将一个下载中的任务暂停
- remove():移除一个任务,无论这个任务是在下载中、暂停、完成还是其他任何状态,都可以直接移除这个任务,他有一个重载方法,接受一个boolen参数,true表示删除任务的时候同时删除文件,false表示只删除任务,但是文件保留在手机上。不传的话,默认为false,即不删除文件。
- restart():重新下载一个任务。重新下载会先删除以前的任务,同时也会删除文件,然后从头开始重新下载该文件。
下载任务需要一个回调,我们上面随意注册一个打日志的回调,代码如下: 控制台的输出如下:
这个log要做以下几点说明:
- onStart()方法是在下载请求之前执行的,所以可以做一些请求之前相关的事,比如修改请求参数,加密,显示对话框等等。
- 服务端返回的响应码是206,注意是206,这个很重要,只有206才能实现断点下载,表示本次返回的是部分响应体,并不是全部的数据。
- 服务端一定要返回Content-Length,注意,是一定要返回Content-Length这个响应头,如果没有,该值默认是-1,这个值表示当前要下载的文件有多大,如果服务端不给的话,客户端在下载过程中是不可能知道我要下载的文件有多大的,所以常见的问题就是进度是负数。
- 下载文件的时候,响应体会打印一句话:
maybe [binary boby], emitted!
,这句话表示当前的数据是二进制文件,控制台没法打印也没必要打印出来,所以不用打印了。很多人经常拿着这个log告诉我出问题了,搞的我真是欲哭无泪,所以不要认为是bug,这是正常的。 - 下载完后,最后会调用onFinish(),不过我设计成在调用onFinish()之前,还会额外调用一次onProgress()方法,这样的好处可以在onProgress方法中捕获到所有的状态变化,方便管理。
下载API介绍
以上的介绍只是简单的说了一下使用方法,那么OkDownload究竟提供的api一共有哪些呢,我们来看看,保证满足你的任何需求。
Request的构建详细参考OkGo的用法,这里重点介绍DownloadTask的构建,这里面的方法一个个介绍:
- request():静态方法创建DownloadTask对象,接受两个参数,第一个参数是tag,表示当前任务的唯一标识,就像介绍中说的,所有下载任务按照tag区分,不同的任务必须使用不一样的tag,否者断点会发生错乱,如果相同的下载url地址,如果使用不一样的tag,也会认为是两个下载任务,不同的下载url地址,如果使用相同的tag,也会认为是同一个任务,导致断点错乱。切记,切记!!
- priority():表示当前任务的下载优先级,他是一个int类型的值,只要在int的大小范围内,数值越大,优先级越高,也就会优先下载。当然也可以不设置,默认优先级为0,当所有任务优先级都一样的时候,就会按添加顺序下载。
- floder():单独指定当前下载任务的文件夹目录,如果你是6.0以上的系统,记得下载的时候先自己获取sd卡的运行时权限,否则文件夹创建不成功,无法下载。当然也可以不指定,默认下载路径
/storage/emulated/0/download
。 - fileName():手动指定下载的文件名,一般来说是不需要手动指定的,也建议不要自己指定,除非你明确知道你要下载的是什么,或者你想改成你自己的文件名。如果不指定,文件名将按照以下规则自动获取,获取规则与OkGo文件下载获取规则一致,点击这里查看。
- extra():这个方法相当于数据库的扩展字段,我们知道我们断点下载是需要保存下载进度信息的,而我们这个框架是保存在数据库中,数据库的字段都是写死的,如果用户想在我们的下载数据库中保存自己的数据就做不到了,所以我们这里提供了三个扩展字段,允许用户保存自己想要的数据,如果不需要的话,也不用调用该方法。
- register():这是个注册监听的方法,我们既然要下载文件,那么我们肯定要知道下载的进度和状态是吧,就在这里注册我们需要的监听,监听可以注册多个,同时生效,当状态发生改变的时候,每个监听都会收到通知。当然如果你只是想下载一个文件,不关心他的回调,那么你不用注册任何回调。
细心你一定会发现我有个方法没有讲,那就是save()
方法,这个方法很重要,重要到我要单独拿出来说他。我们先看看这个方法的源码: 简直简单到不行,就一行代码,就是把当前的progress进度对象,保存到数据库。
想想,如果数据库中没有你这条记录,然后你还开始下载,我如何去更新这个记录,一旦你这么做,OkDownload就会抛出一个异常如下,告诉你必须在start()前,先调用save()方法。 所以我们知道了,save()用在什么地方呢?
- 如果你是第一次下载这个标识为这个tag的任务,那么你一定要调用save()方法,先将该数据写入数据库。
- 如果你对标识为tag的任务进行了一些参数的修改,比如修改了extra数据,修改了下载目录,下载文件夹等等,也必须调用save()方法,更新数据库。
到这里就基本把请求的相关api介绍完了。
ProgressListener对象
我们上面介绍了一些请求的API,这里我们看看回调的API,下载回调用的DownloadListener,源码如下: 实现了一个接口,定义如下: 需要说明的是以下几点:
- DownloadListener的构造方法需要传一个tag,这个tag唯一标识当前listener,主要目的是方便取消监听,同时可以防止数据错乱。
- 你看到的这5个回调方法,全部在主线程回调,不需要你自己开任何线程。
- onProgress方法不仅在任何进度变化的时候会被回调,任何下载状态变化的时候也会回调,所以很多时候,想监听状态变化,也在这个方法中就够了。
监听取消
我们都知道,网络请求是个长时间的事情,如果你在下载过程中,关闭了Activity,而你的回调又还在这个页面中更新UI,那么久会发生内存泄露,为了避免这种情况的发生,推荐以下做法:
- 如果你要实现页面进度的实时刷新,那么该监听就只需要在当前页面有效就行了,关闭页面之前,记得把监听移除,这样就不会泄露了,代码如下,我们看到了取消监听的时候需要传递一个tag,那么这个tag是你创建监听的时候传递的那个tag,不是创建下载任务的那个task,不要搞混了。监听是监听的,任务是任务的。
- 有人问了,我要是取消了,我想在其他页面,其他地方监听到这个下载任务怎么办?你当然可以继续注册一个监听,这个监听里面不要干与UI相关的事,不要持有Activity的引用,那么你这个监听是不会造成泄露的。
- 如果你还不放心,你可以自己额外起一个service,在service中下载任务,注册监听,这样就不怕泄露了。
DownloadManager
我们知道了下载任务是保存在数据库中的,那么数据库中的数据我们能不能直接查看呢,答案是可以的,就是这DownloadManager类,这个类是对下载任务的数据库进行增删改查的管理类,切记不要自己修改这里面的数据,不要直接使用DownloadManager的api,而应该使用OkDownload的api,这样才能确保数据的完整性和准确性。
介绍3个常用的方法: 分别表示从数据库中获取所有的下载记录,已完成的下载记录和未完成的下载记录。
这里可以看出来,我们获取是Progress对象的列表,我们拿到这个列表一般是没什么用的,我们也不能去修改这里面的数据。
所以,这个类的方法一般还需要和OkDownload的方法配合一下使用,一般用法就是获取数据后,将数据库的集合数据恢复成下载任务数据,代码如下:
这里我们看到了这个OkDownload.restore()这个方法,他的作用就是把数据库中的记录,恢复成下载任务。我们拿到了这个任务列表,这个DownloadTask对象,操作方法不就是文档上面讲的那堆了不。
结束
到这里OkDownload的用法就和全部API基本就讲完了。
什么?你说你用的时候列表进度错乱?这个怪我喽?
关于在列表中进度错乱的问题,这个其实和库一点关系没有,完全是因为ListView或者RecyclerView复用问题导致的,你要是不会解决,好好看看Demo怎么解决的吧。
okhttp-OkGo的文件下载模块的更多相关文章
- Android网络文件下载模块整理
一.知识基础 tomcat服务器配置 理解http协议 理解javaIO操作相关知识 SDcard操作知识 Android 权限配置 二.实现步骤 1.从网上获取资源 public String do ...
- Android 6.0 7.0 8.0 一个简单的app内更新版本-okgo app版本更新
登陆时splash初始页调用接口检查app版本.如有更新,使用okGo的文件下载,保存到指定位置,调用Android安装apk. <!-- Android 8.0 (Android O)为了针对 ...
- Okhttp 请求流程梳理
最近在看 Okhttp 的源码.不得不说源码设计的很巧妙,从中能学到很多.其实网上关于 Okhttp 的文章已经很多了,自己也看了很多.但是俗话说得好,好记性不如烂笔头,当你动手的时候,你会发现你在看 ...
- Ansible Ad-Hoc与常用模块
ansible 执行结果信息–各颜色说明:ansible Ad-Hoc 说明:ansible 如何查看帮助文档与常用模块详解 主机规划 添加用户账号 说明: 1. 运维人员使用的登录账号: 2. 所有 ...
- Android常用优秀开源框架
Android常用优秀开源框架 https://github.com/Ericsongyl/AOSF AOSF:全称为Android Open Source Framework,即Android优秀开 ...
- 十一、Android学习第十天——项目开始(转)
(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 十一.Android学习第十天——项目开始 Android知识点的学习告一 ...
- django项目前期准备
本文转载自 https://blog.csdn.net/xiaogeldx/article/details/89037748 Django现状 Django开发前景 Django的厉害之处 在Pyth ...
- 浅析android系统设计中的回调思想
一.为何写作本文 在慢慢深入接触android开发的过程中,我越来越发现android中(至少应用曾的开发)用到了很多回调的思想.比如activity的生命周期,fragment的生命周期,皆是回调 ...
- 潭州课堂25班:Ph201805201 django 项目 第一课 (课堂笔记)
一.Django 现状 1.Django开发前景 1.1 老师做过的项目 项目图展示: 1.2 Django的厉害之处 在python中,与web开发环境相关的包有13045个 ...
随机推荐
- STL容器 -- Stack
核心:后进后出, LIFO. 头文件: #include <stack> 常用的构造方法: stack<int> st1; //构造一个空的存放 int 型的栈 stack&l ...
- 洛谷P2127 序列排序 [贪心]
题目传送门 题目描述 小C有一个N个数的整数序列,这个序列的中的数两两不同.小C每次可以交换序列中的任意两个数,代价为这两个数之和.小C希望将整个序列升序排序,问小C需要的最小代价是多少? 输入输出格 ...
- 编译 Windows 版本的 Unity Mono(2017-03-12 20:59)
上一篇说了如何编译 Android 下的 mono,这里简要说下编译 windows 版本的 mono,就是 mono.dll,Unity 版本只有一个 mono.dll,官方的 mono,好几个可执 ...
- 【BZOJ 1216】 1216: [HNOI2003]操作系统 (模拟+优先队列)
1216: [HNOI2003]操作系统 Description 写一个程序来模拟操作系统的进程调度.假设该系统只有一个CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的.其中运行优先级用自 ...
- [UOJ217]奇怪的线段树
如果一个节点是$0$但它子树内有$1$那么无解,否则我们只需把那些是$1$但子树内没有其他$1$的节点(这些区间是被定位的区间)都访问一遍即可 根据ZKW线段树定位区间的过程,可以发现一段(从左到右) ...
- [转]OpenSessionInView模式
OpenSessionInView模式解决的问题: * hibernate事物边界问题 * 因session关闭导致hibernate延迟加载例外的问题 事物边界: 一个事物的完成应该 ...
- jquer总结
前端jq总结 选择器********************************************************************** 1,基本选择 器 #id .clss ...
- HDU 3473 Minimum Sum(划分树)
Minimum Sum Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- Clover 的功能就是给资源管理器加上 Chrome 一样的标签页
官网下载地址:http://cn.ejie.me/
- IIS配置Asp.net时,出现“未能加载文件或程序集“System.Web.Extensions.Design, Version=1.0.61025.0”
如果出现未能加载文件或程序集“System.Web.Extensions.Design, Version=1.0.61025.0, 主要是没有安装.net framwork 3.5,安装一下就行了. ...