曾經在代碼裏放蕩不羈,現在在博文中日夜兼行,只爲今天與你分享成果。若是以爲本文有用,記得關注我,我將帶給你更多。
還沒看過第一篇文章的歡迎移步: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 之 回調線程魔變(敬請期待)
曾經在代碼裏放蕩不羈,現在在博文中日夜兼行,只爲今天與你分享成果。若是以爲本文有用,記得關注我,我將帶給你更多。