欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Retrofit+RxJava實(shí)現(xiàn)帶進(jìn)度下載文件

 更新時(shí)間:2018年05月10日 08:34:50   作者:jiashuai94  
這篇文章主要為大家詳細(xì)介紹了Retrofit+RxJava實(shí)現(xiàn)帶進(jìn)度下載文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

Retrofit+RxJava已經(jīng)是目前市場上最主流的網(wǎng)絡(luò)框架,使用它進(jìn)行平常的網(wǎng)絡(luò)請求異常輕松,之前也用Retrofit做過上傳文件和下載文件,但發(fā)現(xiàn):使用Retrofit做下載默認(rèn)是不支持進(jìn)度回調(diào)的,但產(chǎn)品大大要求下載文件時(shí)顯示下載進(jìn)度,那就不得不深究下了。

接下來我們一起封裝,使用Retrofit+RxJava實(shí)現(xiàn)帶進(jìn)度下載文件。

github:JsDownload

先來看看UML圖:

大家可能還不太清楚具體是怎么處理的,別急,我們一步步來:

1、添依賴是必須的啦

compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

使用時(shí)注意版本號

2、寫回調(diào)

/**
 * Description: 下載進(jìn)度回調(diào)
 * Created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public interface JsDownloadListener {

 void onStartDownload();

 void onProgress(int progress);

 void onFinishDownload();

 void onFail(String errorInfo);

}

這里就不用多說了,下載的回調(diào),就至少應(yīng)該有開始下載、下載進(jìn)度、下載完成、下載失敗 四個(gè)回調(diào)方法。

注意下在onProgress方法中返回進(jìn)度百分比,在onFail中返回失敗原因。

3、重寫ResponseBody,計(jì)算下載百分比

/**
 * Description: 帶進(jìn)度 下載請求體
 * Created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public class JsResponseBody extends ResponseBody {

 private ResponseBody responseBody;

 private JsDownloadListener downloadListener;

 // BufferedSource 是okio庫中的輸入流,這里就當(dāng)作inputStream來使用。
 private BufferedSource bufferedSource;

 public JsResponseBody(ResponseBody responseBody, JsDownloadListener downloadListener) {
 this.responseBody = responseBody;
 this.downloadListener = downloadListener;
 }

 @Override
 public MediaType contentType() {
 return responseBody.contentType();
 }

 @Override
 public long contentLength() {
 return responseBody.contentLength();
 }

 @Override
 public BufferedSource source() {
 if (bufferedSource == null) {
 bufferedSource = Okio.buffer(source(responseBody.source()));
 }
 return bufferedSource;
 }

 private Source source(Source source) {
 return new ForwardingSource(source) {
 long totalBytesRead = 0L;

 @Override
 public long read(Buffer sink, long byteCount) throws IOException {
 long bytesRead = super.read(sink, byteCount);
 // read() returns the number of bytes read, or -1 if this source is exhausted.
 totalBytesRead += bytesRead != -1 ? bytesRead : 0;
 Log.e("download", "read: "+ (int) (totalBytesRead * 100 / responseBody.contentLength()));
 if (null != downloadListener) {
  if (bytesRead != -1) {
  downloadListener.onProgress((int) (totalBytesRead * 100 / responseBody.contentLength()));
  }

 }
 return bytesRead;
 }
 };

 }
}

將網(wǎng)絡(luò)請求的ResponseBody 和JsDownloadListener 在構(gòu)造中傳入。

這里的核心是source方法,返回ForwardingSource對象,其中我們重寫其read方法,在read方法中計(jì)算百分比,并將其傳給回調(diào)downloadListener。

4、攔截器

只封裝ResponseBody 是不夠的,關(guān)鍵我們需要拿到請求的ResponseBody ,這里我們就用到了攔截器Interceptor 。

/**
 * Description: 帶進(jìn)度 下載 攔截器
 * Created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public class JsDownloadInterceptor implements Interceptor {

 private JsDownloadListener downloadListener;

 public JsDownloadInterceptor(JsDownloadListener downloadListener) {
 this.downloadListener = downloadListener;
 }

 @Override
 public Response intercept(Chain chain) throws IOException {
 Response response = chain.proceed(chain.request());
 return response.newBuilder().body(
 new JsResponseBody(response.body(), downloadListener)).build();
 }
}

通常情況下攔截器用來添加,移除或者轉(zhuǎn)換請求或者回應(yīng)的頭部信息。

在攔截方法intercept中返回我們剛剛封裝的ResponseBody 。

5、網(wǎng)絡(luò)請求service

/**
 * Description:
 * Created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public interface DownloadService {

 @Streaming
 @GET
 Observable<ResponseBody> download(@Url String url);

}

注意:

這里@Url是傳入完整的的下載URL;不用截取
使用@Streaming注解方法

6、最后開始請求

/**
 1. Description: 下載工具類
 2. Created by jia on 2017/11/30.
 3. 人之所以能,是相信能
 */
public class DownloadUtils {

 private static final String TAG = "DownloadUtils";

 private static final int DEFAULT_TIMEOUT = 15;

 private Retrofit retrofit;

 private JsDownloadListener listener;

 private String baseUrl;

 private String downloadUrl;

 public DownloadUtils(String baseUrl, JsDownloadListener listener) {

 this.baseUrl = baseUrl;
 this.listener = listener;

 JsDownloadInterceptor mInterceptor = new JsDownloadInterceptor(listener);

 OkHttpClient httpClient = new OkHttpClient.Builder()
 .addInterceptor(mInterceptor)
 .retryOnConnectionFailure(true)
 .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
 .build();

 retrofit = new Retrofit.Builder()
 .baseUrl(baseUrl)
 .client(httpClient)
 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build();
 }

 /**
 * 開始下載
 *
 * @param url
 * @param filePath
 * @param subscriber
 */
 public void download(@NonNull String url, final String filePath, Subscriber subscriber) {

 listener.onStartDownload();

 // subscribeOn()改變調(diào)用它之前代碼的線程
 // observeOn()改變調(diào)用它之后代碼的線程
 retrofit.create(DownloadService.class)
 .download(url)
 .subscribeOn(Schedulers.io())
 .unsubscribeOn(Schedulers.io())
 .map(new Func1<ResponseBody, InputStream>() {

  @Override
  public InputStream call(ResponseBody responseBody) {
  return responseBody.byteStream();
  }
 })
 .observeOn(Schedulers.computation()) // 用于計(jì)算任務(wù)
 .doOnNext(new Action1<InputStream>() {
  @Override
  public void call(InputStream inputStream) {

  writeFile(inputStream, filePath);

  }
 })
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(subscriber);

 }

 /**
 * 將輸入流寫入文件
 *
 * @param inputString
 * @param filePath
 */
 private void writeFile(InputStream inputString, String filePath) {

 File file = new File(filePath);
 if (file.exists()) {
 file.delete();
 }

 FileOutputStream fos = null;
 try {
 fos = new FileOutputStream(file);

 byte[] b = new byte[1024];

 int len;
 while ((len = inputString.read(b)) != -1) {
 fos.write(b,0,len);
 }
 inputString.close();
 fos.close();

 } catch (FileNotFoundException e) {
 listener.onFail("FileNotFoundException");
 } catch (IOException e) {
 listener.onFail("IOException");
 }

 }
}
  • 在構(gòu)造中將下載地址和最后回調(diào)傳入,當(dāng)然,也可以將保存地址傳入;
  • 在OkHttpClient添加我們自定義的攔截器;
  • 注意.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 支持RxJava;
  • 使用RxJava的map方法將responseBody轉(zhuǎn)為輸入流;
  • 在doOnNext中將輸入流寫入文件;

當(dāng)然也需要注意下載回調(diào)的各個(gè)位置。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)戰(zhàn)之醫(yī)院管理系統(tǒng)的實(shí)現(xiàn)

    Java實(shí)戰(zhàn)之醫(yī)院管理系統(tǒng)的實(shí)現(xiàn)

    這篇文章主要介紹了如何利用Java實(shí)現(xiàn)醫(yī)院管理系統(tǒng),文中用到的技術(shù)有:SpringBoot、Layui、Freemaker等,感興趣的同學(xué)可以了解一下
    2022-04-04
  • 解析Jmeter脫離Jenkins后Ant集成郵件通知問題

    解析Jmeter脫離Jenkins后Ant集成郵件通知問題

    今天來講下本地的ant構(gòu)建并發(fā)送郵件。配置下來挺順利也挺簡單的,對Jmeter脫離Jenkins后Ant集成郵件通知問題感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • Java編程生產(chǎn)者消費(fèi)者實(shí)現(xiàn)的四種方法

    Java編程生產(chǎn)者消費(fèi)者實(shí)現(xiàn)的四種方法

    Java生產(chǎn)者和消費(fèi)者問題是線程安全模型中的經(jīng)典問題:生產(chǎn)者和消費(fèi)者在同一個(gè)時(shí)間段共用同一個(gè)存儲空間,生產(chǎn)者向存儲空間中添加產(chǎn)品呢,消費(fèi)者取走產(chǎn)品,當(dāng)存儲空間為空時(shí),消費(fèi)者阻塞,當(dāng)存儲空間滿時(shí),生產(chǎn)者阻塞
    2021-10-10
  • 關(guān)于Java中靜態(tài)代碼塊的執(zhí)行淺析

    關(guān)于Java中靜態(tài)代碼塊的執(zhí)行淺析

    這篇文章主要給大家介紹了關(guān)于Java中靜態(tài)代碼塊執(zhí)行的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • Spring中自動(dòng)注入的兩種方式總結(jié)

    Spring中自動(dòng)注入的兩種方式總結(jié)

    Spring的核心技術(shù)IOC(Intorol of Converse控制反轉(zhuǎn))的實(shí)現(xiàn)途徑是DI(dependency Insert依賴注入)。而依賴注入(DI)的實(shí)現(xiàn)方式又有兩種,xml方式和注解方式。本文就來詳細(xì)聊聊這兩個(gè)方式,需要的可以了解一下
    2022-10-10
  • springboot2.0.0配置多數(shù)據(jù)源出現(xiàn)jdbcUrl is required with driverClassName的錯(cuò)誤

    springboot2.0.0配置多數(shù)據(jù)源出現(xiàn)jdbcUrl is required with driverClassN

    這篇文章主要介紹了springboot2.0.0配置多數(shù)據(jù)源出現(xiàn)jdbcUrl is required with driverClassName的錯(cuò)誤,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 使用java代碼獲取新浪微博應(yīng)用的access token代碼實(shí)例

    使用java代碼獲取新浪微博應(yīng)用的access token代碼實(shí)例

    這篇文章主要介紹了使用java代碼獲取新浪微博應(yīng)用的access token實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • 一文帶你深入了解Java的自動(dòng)拆裝箱

    一文帶你深入了解Java的自動(dòng)拆裝箱

    Java推出了對于基本數(shù)據(jù)類型的對應(yīng)的對象,將基本數(shù)據(jù)類型轉(zhuǎn)換為對象就稱為裝箱,反之則是拆箱,本文主要為大家介紹了Java自動(dòng)拆裝箱的原理與應(yīng)用,需要的可以參考下
    2023-11-11
  • springmvc流程圖以及配置解析

    springmvc流程圖以及配置解析

    這篇文章主要介紹了springmvc流程圖以及配置解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Spring Boot利用@Async如何實(shí)現(xiàn)異步調(diào)用:自定義線程池

    Spring Boot利用@Async如何實(shí)現(xiàn)異步調(diào)用:自定義線程池

    這篇文章主要給大家介紹了關(guān)于Spring Boot利用@Async如何實(shí)現(xiàn)異步調(diào)用:自定義線程池的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2018-05-05

最新評論