Android 史上最優雅的實現文件上傳、下載及進度的監聽

前言

本文將直接使用RxHttp庫實現文件上傳、下載、斷點下載、進度的監聽,不對RxHttp做過多講解,如果對RxHttp不瞭解,可以先去查閱相關資料先行了解,本文目的在於讓更多的讀者知道RxHttp庫。

上傳

  RxHttp.postForm("http://...") //發送Form表單形式的Post請求
        .add("key", "value")
        .add("file1", new File("xxx/1.png")) //添加file對象
        .add("file2", new File("xxx/2.png"))
        .from() //from操作符,是異步操作
        .as(RxLife.asOnMain(this))  //感知生命週期,並在主線程回調
        .subscribe(s -> { 
            //上傳成功,拿到Http返回值,這裏返回值爲String類型
        }, throwable -> {
            //上傳失敗
        });

注:如果需要對Http的返回值做解析,可在使用from操作符時,傳入一個解析器Parser

帶進度上傳

帶進度上傳使用uploadProgress操作符,並結合doOnNextfiltermap即可

  RxHttp.postForm("http://www.......") //發送Form表單形式的Post請求
        .add("file1", new File("xxx/1.png"))
        .add("file2", new File("xxx/2.png"))
        .add("key1", "value1")//添加參數,非必須
        .add("key2", "value2")//添加參數,非必須
        .addHeader("versionCode", "100") //添加請求頭,非必須
        .uploadProgress() //注:如果需要監聽上傳進度,使用uploadProgress操作符
        .observeOn(AndroidSchedulers.mainThread()) //主線程回調
        .doOnNext(progress -> {
            //上傳進度回調,0-100,僅在進度有更新時纔會回調,最多回調101次,最後一次回調Http執行結果
            int currentProgress = progress.getProgress(); //當前進度 0-100
            long currentSize = progress.getCurrentSize(); //當前已上傳的字節大小
            long totalSize = progress.getTotalSize();     //要上傳的總字節大小
            String result = progress.getResult(); //Http執行結果,最後一次回調纔有內容
        })
        .filter(Progress::isCompleted)//過濾事件,上傳完成,才繼續往下走
        .map(Progress::getResult) //到這,說明上傳完成,拿到Http返回結果並繼續往下走
        .as(RxLife.as(this))  //感知生命週期
        .subscribe(s -> { //s爲String類型,由SimpleParser類裏面的泛型決定的
            //上傳成功,處理相關邏輯
        }, throwable -> {
            //上傳失敗,處理相關邏輯
        });

注:如果需要對Http的返回值做解析,可在使用uploadProgress操作符時,傳入一個解析器Parser

下載

  //文件存儲路徑
  String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .download(destPath) //注意這裏使用download操作符,並傳入本地路徑
        .as(RxLife.asOnMain(this))  //感知生命週期,並在主線程回調
        .subscribe(s -> {
            //下載成功,回調文件下載路徑
        }, throwable -> {
            //下載失敗
        });

帶進度下載

帶進度下載使用downloadProgress操作符,並結合doOnNextfiltermap即可

  //文件存儲路徑
  String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .downloadProgress(destPath) //注:如果需要監聽下載進度,使用downloadProgress操作符
        .observeOn(AndroidSchedulers.mainThread())
        .doOnNext(progress -> {
            //下載進度回調,0-100,僅在進度有更新時纔會回調,最多回調101次,最後一次回調文件存儲路徑
            int currentProgress = progress.getProgress(); //當前進度 0-100
            long currentSize = progress.getCurrentSize(); //當前已下載的字節大小
            long totalSize = progress.getTotalSize();     //要下載的總字節大小
            String filePath = progress.getResult(); //文件存儲路徑,最後一次回調纔有內容
        })
        .filter(Progress::isCompleted)//下載完成,才繼續往下走
        .map(Progress::getResult) //到這,說明下載完成,返回下載目標路徑
        .as(RxLife.as(this)) //感知生命週期
        .subscribe(s -> {//s爲String類型,這裏爲文件存儲路徑
            //下載完成,處理相關邏輯
        }, throwable -> {
            //下載失敗,處理相關邏輯
        });

斷點下載

斷點下載相較於下載,僅僅是添加了RANGE頭信息而已,其它沒有任何差別

  String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
  long length = new File(destPath).length(); //已下載的文件長度
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        //如果文件存在,則添加 RANGE 頭信息 ,從上次斷開的點,開始下載
        .addHeader("RANGE", "bytes=" + length + "-", length > 0)
        .download(destPath)
        .as(RxLife.as(this)) //加入感知生命週期的觀察者
        .subscribe(s -> { //s爲String類型
            Log.e("LJX", "breakpointDownloadAndProgress=" + s);
            //下載成功,處理相關邏輯
        }, throwable -> {
            //下載失敗,處理相關邏輯
        });

帶進度斷點下載

帶進度斷點下載相較於帶進度下載,僅僅是添加了RANGE頭信息而已,其它沒有任何差別

  String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
  long length = new File(destPath).length(); //已下載的文件長度
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        //如果文件存在,則添加 RANGE 頭信息 ,從上次斷開的點,開始下載
        .addHeader("RANGE", "bytes=" + length + "-", length > 0)
        .downloadProgress(destPath)
        .observeOn(AndroidSchedulers.mainThread()) //主線程回調
        .doOnNext(progress -> {
            //下載進度回調,0-100,僅在進度有更新時纔會回調
            int currentProgress = progress.getProgress(); //當前進度 0-100
            long currentSize = progress.getCurrentSize(); //當前已下載的字節大小
            long totalSize = progress.getTotalSize();     //要下載的總字節大小
        })
        .filter(Progress::isCompleted)//過濾事件,下載完成,才繼續往下走
        .map(Progress::getResult) //到這,說明下載完成,拿到Http返回結果並繼續往下走
        .as(RxLife.as(this)) //加入感知生命週期的觀察者
        .subscribe(s -> { //s爲String類型
            //下載成功,處理相關邏輯
        }, throwable -> {
            //下載失敗,處理相關邏輯
        });

注:上面帶進度斷點下載中,返回的進度會從0開始,如果需要接着上次下載的進度,則可以在downloadProgress下再添加一個map操作符,添加上次已經下載好的長度,如下:

  String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
  long length = new File(destPath).length(); //已下載的文件長度
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        //如果文件存在,則添加 RANGE 頭信息 ,從上次斷開的點,開始下載
        .addHeader("RANGE", "bytes=" + length + "-", length > 0)
        .downloadProgress(destPath)
        .map(progress -> {
            if (length > 0) {//增加上次已經下載好的字節數,並更新進度
                progress.addCurrentSize(length);
                progress.addTotalSize(length);
                progress.updateProgress();
            }
            return progress;
         })
        .observeOn(AndroidSchedulers.mainThread()) //主線程回調
        .doOnNext(progress -> {
            //下載進度回調,0-100,僅在進度有更新時纔會回調
            int currentProgress = progress.getProgress(); //當前進度 0-100
            long currentSize = progress.getCurrentSize(); //當前已下載的字節大小
            long totalSize = progress.getTotalSize();     //要下載的總字節大小
        })
        .filter(Progress::isCompleted)//過濾事件,下載完成,才繼續往下走
        .map(Progress::getResult) //到這,說明下載完成,拿到Http返回結果並繼續往下走
        .as(RxLife.as(this)) //加入感知生命週期的觀察者
        .subscribe(s -> { //s爲String類型
            //下載成功,處理相關邏輯
        }, throwable -> {
            //下載失敗,處理相關邏輯
        });

小結

好了,文件上傳、下載相關就介紹到這裏了,到這你會發現,涉及到進度的監聽,都使用了RxJava的doOnNextfiltermap這3個操作符,一切都那麼的相似,極大的降低了學習成本。怎麼樣?是不是很優雅,歡迎打臉!!

最後,很大一部分功勞都要歸功於RxJava的強大,感謝RxJava,向它致敬!!!!

下一文將繼續使用RxJava強大的操作符,看看它與RxHttp又能擦出怎樣的火花。

最後文末放上一個技術交流羣:Android IOC架構設計

羣內有許多技術大牛,有任何問題,歡迎廣大網友一起來交流,羣內還不定期免費分享高階Android學習視頻資料和麪試資料包~

再推薦一篇文章:“寒冬未過”,阿里P9架構分享Android必備技術點,讓你offer拿到手軟!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章