33
44import java .io .IOException ;
55
6- import rxhttp .wrapper .callback .ProgressCallback ;
76import okhttp3 .MediaType ;
7+ import okhttp3 .Response ;
88import okhttp3 .ResponseBody ;
9- import okio .*;
9+ import okio .Buffer ;
10+ import okio .BufferedSource ;
11+ import okio .ForwardingSource ;
12+ import okio .Okio ;
13+ import okio .Source ;
14+ import rxhttp .wrapper .callback .ProgressCallback ;
1015
1116/**
1217 * 文件下载,带进度的响应实体
1318 */
1419public class ProgressResponseBody extends ResponseBody {
15- public static final int MIN_INTERVAL = 50 ;
20+ private static final int MIN_INTERVAL = 50 ;
1621
1722 //实际的待包装响应体
18- private final ResponseBody responseBody ;
23+ private final ResponseBody responseBody ;
1924 //进度回调接口
2025 private volatile ProgressCallback callback ;
2126 //包装完成的BufferedSource
22- private BufferedSource bufferedSource ;
27+ private BufferedSource bufferedSource ;
28+
29+ private long contentLength ; //ResponseBody 内容长度,部分接口拿不到,会返回-1,此时会没有进度回调
2330
2431 /**
2532 * 构造函数,赋值
2633 *
27- * @param responseBody 待包装的响应体
28- * @param callback 回调接口
34+ * @param response 响应体
35+ * @param callback 回调接口
2936 */
30- public ProgressResponseBody (ResponseBody responseBody , ProgressCallback callback ) {
31- this .responseBody = responseBody ;
37+ public ProgressResponseBody (Response response , ProgressCallback callback ) {
38+ this .responseBody = response . body () ;
3239 this .callback = callback ;
40+ if (responseBody != null ) {
41+ contentLength = responseBody .contentLength ();
42+ }
43+ if (contentLength == -1 ) {
44+ contentLength = getContentLengthByHeader (response );
45+ }
3346 }
3447
3548
@@ -50,7 +63,7 @@ public MediaType contentType() {
5063 */
5164 @ Override
5265 public long contentLength () {
53- return responseBody . contentLength () ;
66+ return contentLength ;
5467 }
5568
5669 /**
@@ -84,23 +97,25 @@ private Source source(Source source) {
8497 @ Override
8598 public long read (Buffer sink , long byteCount ) throws IOException {
8699 long bytesRead = super .read (sink , byteCount );
87- //增加当前读取的字节数,如果读取完成了bytesRead会返回-1
88- totalBytesRead += bytesRead != -1 ? bytesRead : 0 ;
89- final long fileSize = responseBody .contentLength ();
90- //回调,如果contentLength()不知道长度,会返回-1
91- final int currentProgress = (int ) ((totalBytesRead * 100 ) / fileSize );
92- //当前进度较上次没有更新,直接返回
93- if (currentProgress <= lastProgress ) return bytesRead ;
94- //当前进度小于100,需要判断两次回调时间间隔是否小于一定时间,是的话直接返回
95- if (currentProgress < 100 ) {
96- long currentTime = System .currentTimeMillis ();
97- //两次回调时间小于 MIN_INTERVAL 毫秒,直接返回,避免更新太频繁
98- if (currentTime - lastTime < MIN_INTERVAL ) return bytesRead ;
99- lastTime = currentTime ;
100+ if (bytesRead == -1 ) { //-1 代表读取完毕
101+ if (contentLength == -1 ) contentLength = totalBytesRead ;
102+ } else {
103+ totalBytesRead += bytesRead ; //未读取完,则累加已读取的字节
104+ }
105+
106+ //当前进度 = 当前已读取的字节 / 总字节
107+ final int currentProgress = (int ) ((totalBytesRead * 100 ) / contentLength );
108+ if (currentProgress > lastProgress ) { //前进度大于上次进度,则更新进度
109+ if (currentProgress < 100 ) {
110+ long currentTime = System .currentTimeMillis ();
111+ //两次回调时间小于 MIN_INTERVAL 毫秒,直接返回,避免更新太频繁
112+ if (currentTime - lastTime < MIN_INTERVAL ) return bytesRead ;
113+ lastTime = currentTime ;
114+ }
115+ lastProgress = currentProgress ;
116+ //回调,更新进度
117+ updateProgress (lastProgress , totalBytesRead , contentLength );
100118 }
101- lastProgress = currentProgress ;
102- //回调,更新进度
103- updateProgress (lastProgress , totalBytesRead , fileSize );
104119 return bytesRead ;
105120 }
106121 };
@@ -110,4 +125,24 @@ private void updateProgress(final int progress, final long currentSize, final lo
110125 if (callback == null ) return ;
111126 callback .onProgress (progress , currentSize , totalSize );
112127 }
128+
129+ //从响应头 Content-Range 中,取 contentLength
130+ private long getContentLengthByHeader (Response response ) {
131+ String headerValue = response .header ("Content-Range" );
132+ long contentLength = -1 ;
133+ if (headerValue != null ) {
134+ //响应头Content-Range格式 : bytes 100001-20000000/20000001
135+ try {
136+ int divideIndex = headerValue .indexOf ("/" ); //斜杠下标
137+ int blankIndex = headerValue .indexOf (" " );
138+ String fromToValue = headerValue .substring (blankIndex + 1 , divideIndex );
139+ String [] split = fromToValue .split ("-" );
140+ long start = Long .parseLong (split [0 ]); //开始下载位置
141+ long end = Long .parseLong (split [1 ]); //结束下载位置
142+ contentLength = end - start + 1 ; //要下载的总长度
143+ } catch (Exception ignore ) {
144+ }
145+ }
146+ return contentLength ;
147+ }
113148}
0 commit comments