Android 史上最優(yōu)雅的實(shí)現(xiàn)文件上傳、下載及進(jìn)度的監(jiān)聽

本文已授權(quán)「劉望舒」微信公眾號獨(dú)家原創(chuàng)發(fā)布

前言

本文將直接使用RxHttp庫實(shí)現(xiàn)文件上傳、下載、斷點(diǎn)下載、進(jìn)度的監(jiān)聽,不對RxHttp做過多講解,如果對RxHttp不了解,請移步

RxHttp 一條鏈發(fā)送請求,新一代Http請求神器(一)

RxHttp 一條鏈發(fā)送請求之強(qiáng)大的數(shù)據(jù)解析功能(二)

RxHttp 一條鏈發(fā)送請求之強(qiáng)大的Param類(三)

RxHttp 一條鏈發(fā)送請求之注解處理器 Generated API(四)

本文目的在于讓更多的讀者知道RxHttp庫,如果您已閱讀上面4篇文章,本文可直接跳過,感謝你的支持。????。

上傳

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

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

帶進(jìn)度上傳

帶進(jìn)度上傳使用asUpload(Progress,Scheduler)操作符

  RxHttp.postForm("http://www.......") //發(fā)送Form表單形式的Post請求
        .add("key1", "value1")//添加參數(shù),非必須
        .add("file1", new File("xxx/1.png"))
        .asUpload(progress -> {
            //上傳進(jìn)度回調(diào),0-100,僅在進(jìn)度有更新時才會回調(diào),最多回調(diào)101次,最后一次回調(diào)Http執(zhí)行結(jié)果
            int currentProgress = progress.getProgress(); //當(dāng)前進(jìn)度 0-100
            long currentSize = progress.getCurrentSize(); //當(dāng)前已上傳的字節(jié)大小
            long totalSize = progress.getTotalSize();     //要上傳的總字節(jié)大小
        }, AndroidSchedulers.mainThread())//指定主線程回調(diào)
        .as(RxLife.as(this))  //感知生命周期
        .subscribe(s -> { //s為String類型,由SimpleParser類里面的泛型決定的
            //上傳成功,處理相關(guān)邏輯
        }, throwable -> {
            //上傳失敗,處理相關(guān)邏輯
        });

注:如果需要對Http的返回值做解析,可使用asUpload(Parser,Progress,Scheduler)方法,傳入一個解析器Parser

下載

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

帶進(jìn)度下載

帶進(jìn)度下載使用asDownload(String,Consumer,Scheduler)方法

  //文件存儲路徑
  String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .asDownload(destPath, progress -> {
            //下載進(jìn)度回調(diào),0-100,僅在進(jìn)度有更新時才會回調(diào),最多回調(diào)101次,最后一次回調(diào)文件存儲路徑
            int currentProgress = progress.getProgress(); //當(dāng)前進(jìn)度 0-100
            long currentSize = progress.getCurrentSize(); //當(dāng)前已下載的字節(jié)大小
            long totalSize = progress.getTotalSize();     //要下載的總字節(jié)大小
        }, AndroidSchedulers.mainThread()) //指定主線程回調(diào)
        .as(RxLife.as(this)) //感知生命周期
        .subscribe(s -> {//s為String類型,這里為文件存儲路徑
            //下載完成,處理相關(guān)邏輯
        }, throwable -> {
            //下載失敗,處理相關(guān)邏輯
        });

斷點(diǎn)下載

斷點(diǎn)下載相較于下載,僅需要調(diào)用setRangeHeader方法傳入開始及結(jié)束位置即可(結(jié)束位置不傳默認(rèn)為文件末尾),其它沒有任何差別

  String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
  long length = new File(destPath).length(); //已下載的文件長度
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .setRangeHeader(length)  //設(shè)置開始下載位置,結(jié)束位置默認(rèn)為文件末尾
        .asDownload(destPath)
        .as(RxLife.asOnMain(this)) //加入感知生命周期的觀察者
        .subscribe(s -> { //s為String類型
            Log.e("LJX", "breakpointDownloadAndProgress=" + s);
            //下載成功,處理相關(guān)邏輯
        }, throwable -> {
            //下載失敗,處理相關(guān)邏輯
        });

帶進(jìn)度斷點(diǎn)下載

帶進(jìn)度斷點(diǎn)下載相較于帶進(jìn)度下載僅需要調(diào)用setRangeHeader方法傳入開始及結(jié)束位置即可(結(jié)束位置不傳默認(rèn)為文件末尾),其它沒有任何差別

  String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
  long length = new File(destPath).length(); //已下載的文件長度
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .setRangeHeader(length)  //設(shè)置開始下載位置,結(jié)束位置默認(rèn)為文件末尾
        .asDownload(destPath, progress -> {
            //下載進(jìn)度回調(diào),0-100,僅在進(jìn)度有更新時才會回調(diào)
            int currentProgress = progress.getProgress(); //當(dāng)前進(jìn)度 0-100
            long currentSize = progress.getCurrentSize(); //當(dāng)前已下載的字節(jié)大小
            long totalSize = progress.getTotalSize();     //要下載的總字節(jié)大小
        }, AndroidSchedulers.mainThread()) //指定主線程回調(diào)
        .as(RxLife.as(this)) //加入感知生命周期的觀察者
        .subscribe(s -> { //s為String類型
            //下載成功,處理相關(guān)邏輯
        }, throwable -> {
            //下載失敗,處理相關(guān)邏輯
        });

注:上面帶進(jìn)度斷點(diǎn)下載中,返回的進(jìn)度會從0開始,如果需要銜接上次下載的進(jìn)度,則調(diào)用asDownload(String,long,Consumer,Scheduler)方法傳入上次已經(jīng)下載好的長度(第二個參數(shù)),如下:

  String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
  long length = new File(destPath).length(); //已下載的文件長度
  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .setRangeHeader(length)  //設(shè)置開始下載位置,結(jié)束位置默認(rèn)為文件末尾
        .asDownload(destPath, length, progress -> {
            //下載進(jìn)度回調(diào),0-100,僅在進(jìn)度有更新時才會回調(diào)
            int currentProgress = progress.getProgress(); //當(dāng)前進(jìn)度 0-100
            long currentSize = progress.getCurrentSize(); //當(dāng)前已下載的字節(jié)大小
            long totalSize = progress.getTotalSize();     //要下載的總字節(jié)大小
        }, AndroidSchedulers.mainThread()) //指定主線程回調(diào)
        .as(RxLife.as(this)) //加入感知生命周期的觀察者
        .subscribe(s -> { //s為String類型
            //下載成功,處理相關(guān)邏輯
        }, throwable -> {
            //下載失敗,處理相關(guān)邏輯
        });

多任務(wù)下載

多任務(wù)下載我們可以使用RxJava的merge操作符,如下:

List<Observable<String>> downList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
    String destPath = getExternalCacheDir() + "/" + i + ".apk";
    String url = "http://update.9158.com/miaolive/Miaolive.apk"
    Observable<String> down = RxHttp.get(url)
            .asDownload(destPath);
    downList.add(down);
}

//通過RxJava內(nèi)部線程池,多任務(wù)并行下載
Observable.merge(downList)
        .as(RxLife.as(this))
        .subscribe(s -> {
            //單個任務(wù)下載完成
        }, throwable -> {
            //下載出錯
        }, () -> {
            //所有任務(wù)下載完成
        });

如果想監(jiān)聽每個任務(wù)的下載進(jìn)度,也簡單,用老方法即可,如下:

List<Observable<String>> downList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
    String destPath = getExternalCacheDir() + "/" + i + ".apk";
    String url = "http://update.9158.com/miaolive/Miaolive.apk"
    Observable<String> down = RxHttp.get(url)
            .asDownload(destPath, progress -> {
                //單個下載任務(wù)進(jìn)度回調(diào)
            }, AndroidSchedulers.mainThread())
    downList.add(down);
}

//通過RxJava內(nèi)部線程池,多任務(wù)并行下載
Observable.merge(downList)
        .as(RxLife.as(this))
        .subscribe(s -> {
            //單個任務(wù)下載完成
        }, throwable -> {
            //下載出錯
        }, () -> {
            //所有任務(wù)下載完成
        });

多任務(wù)上傳

與多任務(wù)下載同理,不再講述。

小結(jié)

好了,文件上傳、下載相關(guān)就介紹到這里了,到這你會發(fā)現(xiàn),不管是上傳還是下載,進(jìn)度的監(jiān)聽都極其的相似,極大的降低了學(xué)習(xí)成本。怎么樣?是不是很優(yōu)雅,歡迎打臉??!

最后,很大一部分功勞都要?dú)w功于RxJava的強(qiáng)大,感謝RxJava,向它致敬?。。?!

下一文將繼續(xù)使用RxJava強(qiáng)大的操作符,看看它與RxHttp又能擦出怎樣的火花。
轉(zhuǎn)載請注明出處,謝謝??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,621評論 1 32
  • 相信不少同學(xué)到語培班學(xué)習(xí),老師要求的第一件事就是背單詞,擴(kuò)大詞庫。相比于學(xué)霸自帶“過目不忘”的背詞技能,一般的學(xué)生...
    考雅君閱讀 1,464評論 0 0
  • 生活環(huán)境真的能影響一個人的生活方式,思維方式。最近重溫了這部電影,每看一次都會有新的感觸。 先介紹一下人物, 伊萊...
    南湘竹閱讀 1,852評論 1 2
  • 昨晚一直做夢,夢到你,夢到我,夢到年輕的我們,笑吟吟的互相看著對方 這兩年,總會突然想起你,有時候一個人在家里,做...
    蘇德的小松鼠閱讀 405評論 0 4
  • 青春,這個詞,對于即將27歲的我來說,似乎已經(jīng)很遙遠(yuǎn)很陌生了,但是看到我的學(xué)生們,又覺得近在眼前。 也不知道我們的...
    曾經(jīng)的故事閱讀 185評論 0 0

友情鏈接更多精彩內(nèi)容