曾经在代码里放荡不羁,现在在博文中日夜兼行,只为今天与你分享成果。若是以为本文有用,记得关注我,我将带给你更多。
还没看过第一篇文章的欢迎移步:OkHttp 优雅封装 HttpUtils 之气海雪山初探java
介绍
HttpUtils 是近期开源的对 OkHttp 轻量封装的框架,它首创的异步预处理器,特点的标签,灵活的上传下载进度监听与过程控制功能,在轻松解决不少本来使人头疼问题的同时,设计上也力求纯粹与优雅。git
- 链式调用,一点到底
- BaseURL、URL占位符、JSON自动封装与解析
- 同步拦截器、异步预处理器、回调执行器
- 文件上传下载(过程控制、进度监听)
- TCP链接池、Http2
项目地址 Gitee:https://gitee.com/ejlchina-zhxu/httputils GitHub:https://github.com/ejlchina/httputilsgithub
安装教程
Maven
<dependency> <groupId>com.ejlchina</groupId> <artifactId>httputils</artifactId> <version>2.2.0</version> </dependency>
Gradle
compile 'com.ejlchina:httputils:2.2.0'
在正式开始以前,咱们依然假设,下文中出现http
均是在构建时设置了BaseUrl
的HTTP
实例(详细请看前文):api
HTTP http = HTTP.builder() .baseUrl("http://api.demo.com") .build();
OK,一切就绪,咱们接着上篇文章继续讲。服务器
8 文件下载
HttpUtils 并无把文件的下载排除在常规的请求以外,而是使用同一套API,它优雅的设计使得下载与常规请求融合的毫无违和感,一个简单的示例:网络
http.sync("/download/test.zip") .get() // 使用 GET 方法(其它方法也能够,看服务器支持) .getBody() // 获得报文体 .toFolder("D:/download") // 下载到指定目录,文件名将根据下载信息自动生成 .start(); // 启动下载
或使用异步请求方式:app
http.async("/download/test.zip") .setOnResponse((HttpResult result) -> { // 下载到指定路径 result.getBody().toFile("D:/download/test.zip").start(); }) .get();
这里要说明一下:sync
与async
的区别在于链接服务器并获得响应这个过程的同步与异步(这个过程的耗时在大文件下载中占比极小),而start
方法启动的下载过程则都是异步的。框架
8.1 下载进度监听
就直接上代码啦,相信诸君一看便懂:异步
http.sync("/download/test.zip") .get() .getBody() .setStepBytes(1024) // 设置每接收 1024 个字节执行一次进度回调(不设置默认为 8192) // .setStepRate(0.01) // 设置每接收 1% 执行一次进度回调(不设置以 StepBytes 为准) .setOnProcess((Process process) -> { // 下载进度回调 long doneBytes = process.getDoneBytes(); // 已下载字节数 long totalBytes = process.getTotalBytes(); // 总共的字节数 double rate = process.getRate(); // 已下载的比例 boolean isDone = process.isDone(); // 是否下载完成 }) .toFolder("D:/download/") // 指定下载的目录,文件名将根据下载信息自动生成 // .toFile("D:/download/test.zip") // 指定下载的路径,若文件已存在则覆盖 .setOnSuccess((File file) -> { // 下载成功回调 }) .start();
值得一提的是:因为 HttpUtils 并无把下载作的很特别,这里设置的进度回调不仅对下载文件起用做,即便对响应JSON的常规请求,只要设置了进度回调,它也会告诉你报文接收的进度(提早是服务器响应的报文有Content-Length
头),例如:async
List<User> users = http.sync("/users") .get() .getBody() .setStepBytes(2) .setOnProcess((Process process) -> { System.out.println(process.getRate()); }) .toList(User.class);
8.2 下载过程控制
过于简单:仍是直接上代码:
Ctrl ctrl = http.sync("/download/test.zip") .get() .getBody() .setOnProcess((Process process) -> { System.out.println(process.getRate()); }) .toFolder("D:/download/") .start(); // 该方法返回一个下载过程控制器 ctrl.status(); // 下载状态 ctrl.pause(); // 暂停下载 ctrl.resume(); // 恢复下载 ctrl.cancel(); // 取消下载(同时会删除文件,不可恢复)
不管是同步仍是异步发起的下载请求,均可以作以上的控制:
http.async("/download/test.zip") .setOnResponse((HttpResult result) -> { // 拿到下载控制器 Ctrl ctrl = result.getBody().toFolder("D:/download/").start(); }) .get();
8.3 实现断点续传
HttpUtils 对断点续传并无再作更高层次的封装,由于这是app该去作的事情,它在设计上使各类网络问题的处理变简单的同时力求纯粹。下面的例子能够看到,HttpUtils 经过一个失败回调拿到断点,便将复杂的问题变得简单:
http.sync("/download/test.zip") .get() .getBody() .toFolder("D:/download/") .setOnFailure((Failure failure) -> { // 下载失败回调,以便接收诸如网络错误等失败信息 IOException e = failure.getException(); // 具体的异常信息 long doneBytes = failure.getDoneBytes(); // 已下载的字节数(断点),须要保存,用于断点续传 File file = failure.getFile(); // 下载生成的文件,须要保存 ,用于断点续传(只保存路径也能够) }) .start();
而后实现断点续传:
long doneBytes = ... // 拿到保存的断点 File file = ... // 待续传的文件 http.sync("/download/test.zip") .setRange(doneBytes) // 设置断点(已下载的字节数) .get() .getBody() .toFile(file) // 下载到同一个文件里 .setAppended() // 开启文件追加模式 .setOnSuccess((File file) -> { }) .setOnFailure((Failure failure) -> { }) .start();
8.4 实现分块下载
当文件很大时,有时候咱们会考虑分块下载,与断点续传的思路是同样的,示例代码:
static String url = "http://api.demo.com/download/test.zip" public static void main(String[] args) { long totalSize = HttpUtils.sync(url).get().getBody() .close() // 由于此次请求只是为了得到文件大小,不消费报文体,因此直接关闭 .getContentLength(); // 得到待下载文件的大小(因为未消费报文体,因此该请求不会消耗下载报文体的时间和网络流量) download(totalSize, 0); // 从第 0 块开始下载 sleep(50000); // 等待下载完成(否则本例的主线程就结束啦) } static void download(long totalSize, int index) { long size = 3 * 1024 * 1024; // 每块下载 3M long start = index * size; long end = Math.min(start + size, totalSize); HttpUtils.sync(url) .setRange(start, end) // 设置本次下载的范围 .get().getBody() .toFile("D:/download/test.zip") // 下载到同一个文件里 .setAppended() // 开启文件追加模式 .setOnSuccess((File file) -> { if (end < totalSize) { // 若未下载完,则继续下载下一块 download(totalSize, index + 1); } else { System.out.println("下载完成"); } }) .start(); }
本例中使用了HttpUtils
类,关于它的详细介绍,请看前文:OkHttp 优雅封装 HttpUtils 之 气海雪山初探。
9 文件上传
一个简单文件上传的示例:
http.sync("/upload") .addFileParam("test", "D:/download/test.zip") .post() // 上传发法通常使用 POST 或 PUT,看服务器支持
异步上传也是彻底同样:
http.async("/upload") .addFileParam("test", "D:/download/test.zip") .post()
9.1 上传进度监听
HttpUtils 的上传进度监听,监听的是全部请求报文体的发送进度,示例代码:
http.sync("/upload") .addBodyParam("name", "Jack") .addBodyParam("age", 20) .addFileParam("avatar", "D:/image/avatar.jpg") .setStepBytes(1024) // 设置每发送 1024 个字节执行一次进度回调(不设置默认为 8192) // .setStepRate(0.01) // 设置每发送 1% 执行一次进度回调(不设置以 StepBytes 为准) .setOnProcess((Process process) -> { // 上传进度回调 long doneBytes = process.getDoneBytes(); // 已发送字节数 long totalBytes = process.getTotalBytes(); // 总共的字节数 double rate = process.getRate(); // 已发送的比例 boolean isDone = process.isDone(); // 是否发送完成 }) .post()
咦!怎么感受和下载的进度回调的同样?没错!HttpUtils 仍是使用同一套API处理上传和下载的进度回调,区别只在于上传是在get/post
方法以前使用这些API,下载是在getBody
方法以后使用。很好理解:get/post
以前是准备发送请求时段,有上传的含义,而getBody
以后,已经是报文响应的时段,固然是下载。
9.2 上传过程控制
上传文件的过程控制就很简单,和常规请求同样,只有异步发起的上传能够取消:
HttpCall call = http.async("/upload") .addFileParam("test", "D:/download/test.zip") .setOnProcess((Process process) -> { System.out.println(process.getRate()); }) .post() call.cancel(); // 取消上传
上传就没有暂停和继续这个功能啦,应该没人有这个需求吧?
前篇文章:OkHttp 优雅封装 HttpUtils 之 气海雪山初探 下篇文章:OkHttp 优雅封装 HttpUtils 之 回调线程魔变(敬请期待)
曾经在代码里放荡不羁,现在在博文中日夜兼行,只为今天与你分享成果。若是以为本文有用,记得关注我,我将带给你更多。