Retrofit+RxJava实现带进度下载文件

2025-05-29 0 100

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中将输入流写入文件;

当然也需要注意下载回调的各个位置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

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

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Retrofit+RxJava实现带进度下载文件 https://www.kuaiidc.com/111789.html

相关文章

发表评论
暂无评论