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个 ...
随机推荐
- Sqli-labs less 13
Less-13 本关我们输入username:admin' Password: (随便输) 进行测试 可以看到报错了,错误为: You have an error in your SQL syntax ...
- ALL运算符
ALL在英文中的意思是“所有”,ALL运算符要求比较的值需要匹配子查询中的所有值.ALL运算符同样不能单独使用,必须和比较运算符共同使用. 下面的SQL语句用来检索在所有会员入会之前出版的图书: SE ...
- angularjs学习笔记3-directive中scope的绑定修饰符
在angularjs中,一个directive返回一个对象,对象存在很多属性,并且可以在directive中自定义自己的scope,而使用自己的scope是为了防止一个directive被使用在多个地 ...
- 【UOJ #171】【WC 2016】挑战NPC
http://uoj.ac/problem/171 带花树开花时的u和v一定要记清楚顺序,想好了再写,数据范围也要算好! 对每个筐子拆成3个点,连成一个三元环,对每个(u,v),让u和v的3个点都连边 ...
- wannafly挑战赛14
第一次打wannafly..觉得自己好菜啊... 题目描述 在三维空间中,平面 x = 0, y = 0, z = 0,以及平面 x + y + z = K 围成了一个三棱锥. 整天与整数打交道的小明 ...
- 【贪心】【后缀自动机】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem E. Enter the Word
题意:给你一个串,让你从左到右构造这个串,一次操作可以直接在当前串后面添加一个任意字符,或者拷贝当前串的任意一个子串到当前串的后面.问你最少要多少次操作才能构造出这个串. 从前向后贪心,从当前已构造的 ...
- 设计BBS
功能分析: 1 登陆功能(基于ajax,图片验证码) 2 注册功能(基于ajax,基于forms验证) 3 博客首页 4 个人站点 5 文章详情 6 点赞,点踩 7 评论 --根评论 --子评论 8 ...
- Python学习札记
Python是很多公司都在使用的一种脚本语言,其语法与Perl.C++.JAVA等都大同小异.本文仅对一些比较常用的语法结构进行总结,比如字典.列表.正则匹配.读写文件等.供广大喜爱Python的同学 ...
- BigInt的实现——C++编程风格读书笔记
C++编程风格这本书前面一些章节都觉得很简明易懂,但是读到效率这一章是才充分认识到读别人的代码还是很痛苦的一件事.书中给出的需要改进的初始类如下: class BigInt { private: ch ...
- Problem C: 零起点学算法82——数组中查找数
#include<stdio.h> int main(void) { ],m; while(scanf("%d",&n)!=EOF) { ;i<n;i++ ...