激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Retrofit+RxJava實現帶進度下載文件

Retrofit+RxJava實現帶進度下載文件

2021-04-27 14:16jiashuai94 Java教程

這篇文章主要為大家詳細介紹了Retrofit+RxJava實現帶進度下載文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下

retrofit+rxjava已經是目前市場上最主流的網絡框架,使用它進行平常的網絡請求異常輕松,之前也用retrofit做過上傳文件和下載文件,但發現:使用retrofit做下載默認是不支持進度回調的,但產品大大要求下載文件時顯示下載進度,那就不得不深究下了。

接下來我們一起封裝,使用retrofit+rxjava實現帶進度下載文件。

github:jsdownload

先來看看uml圖:

Retrofit+RxJava實現帶進度下載文件大家可能還不太清楚具體是怎么處理的,別急,我們一步步來:

1、添依賴是必須的啦

?
1
2
3
4
5
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'

使用時注意版本號

2、寫回調

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * description: 下載進度回調
 * created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public interface jsdownloadlistener {
 
 void onstartdownload();
 
 void onprogress(int progress);
 
 void onfinishdownload();
 
 void onfail(string errorinfo);
 
}

這里就不用多說了,下載的回調,就至少應該有開始下載、下載進度、下載完成、下載失敗 四個回調方法。

注意下在onprogress方法中返回進度百分比,在onfail中返回失敗原因。

3、重寫responsebody,計算下載百分比

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
 * description: 帶進度 下載請求體
 * created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public class jsresponsebody extends responsebody {
 
 private responsebody responsebody;
 
 private jsdownloadlistener downloadlistener;
 
 // bufferedsource 是okio庫中的輸入流,這里就當作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;
 }
 };
 
 }
}

將網絡請求的responsebody 和jsdownloadlistener 在構造中傳入。

這里的核心是source方法,返回forwardingsource對象,其中我們重寫其read方法,在read方法中計算百分比,并將其傳給回調downloadlistener。

4、攔截器

只封裝responsebody 是不夠的,關鍵我們需要拿到請求的responsebody ,這里我們就用到了攔截器interceptor 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * description: 帶進度 下載 攔截器
 * 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();
 }
}

通常情況下攔截器用來添加,移除或者轉換請求或者回應的頭部信息。

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

5、網絡請求service

?
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * description:
 * created by jia on 2017/11/30.
 * 人之所以能,是相信能
 */
public interface downloadservice {
 
 @streaming
 @get
 observable<responsebody> download(@url string url);
 
}

注意:

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

6、最后開始請求

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
 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()改變調用它之前代碼的線程
 // observeon()改變調用它之后代碼的線程
 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()) // 用于計算任務
 .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");
 }
 
 }
}
  • 在構造中將下載地址和最后回調傳入,當然,也可以將保存地址傳入;
  • 在okhttpclient添加我們自定義的攔截器;
  • 注意.addcalladapterfactory(rxjavacalladapterfactory.create()) 支持rxjava;
  • 使用rxjava的map方法將responsebody轉為輸入流;
  • 在doonnext中將輸入流寫入文件;

當然也需要注意下載回調的各個位置。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/jiashuai94/article/details/78775314

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美日韩色 | 视频一区二区在线观看 | 极品国产91在线网站 | 欧美一区二区三区四区电影 | 最新一级毛片 | 精品国产一区二区三区四 | 性爱在线免费视频 | 午夜精品久久久久久久久久久久久蜜桃 | 国产精品久久久久久久久久10秀 | 亚州欧美在线 | 激情综合网俺也去 | 万圣街在线观看免费完整版 | 色视频在线播放 | 国产成人精品午夜视频' | 国产成人av一区 | 偿还电影免费 | 亚洲第一成av人网站懂色 | 亚洲成人精品视频 | 黄色美女免费 | 一级黄色a视频 | 久久这 | 久久综合给合久久狠狠狠97色69 | 中文字幕h| 日产精品久久久久久久 | 亚洲精品成人18久久久久 | 久久精品欧美一区二区三区不卡 | 黄色试看视频 | 国产jjizz一区二区三区视频 | 综合精品视频 | 天堂成人一区二区三区 | 久久久一区二区精品 | 成人做爰高潮片免费视频韩国 | 精品一区二区三区毛片 | 懂色粉嫩av久婷啪 | 国产亚洲网 | 国产亚洲综合精品 | 亚洲二区免费 | av免费在线不卡 | 色婷婷综合久久久中字幕精品久久 | 91看片淫黄大片欧美看国产片 | 日韩色视频 |