OkHttp 優雅封裝 HttpUtils 之 上傳下載解密

曾經在代碼裏放蕩不羈,現在在博文中日夜兼行,只爲今天與你分享成果。若是以爲本文有用,記得關注我,我將帶給你更多。

還沒看過第一篇文章的歡迎移步: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均是在構建時設置了BaseUrlHTTP實例(詳細請看前文):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();

  這裏要說明一下:syncasync的區別在於鏈接服務器並獲得響應這個過程的同步與異步(這個過程的耗時在大文件下載中佔比極小),而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 之 回調線程魔變(敬請期待)


曾經在代碼裏放蕩不羈,現在在博文中日夜兼行,只爲今天與你分享成果。若是以爲本文有用,記得關注我,我將帶給你更多。

相關文章
相關標籤/搜索