Skip to content

Commit cf41fa3

Browse files
ResponseBody#contentLength()等于-1时,从响应头 Content-Range 中取 contentLength;如果再取不到,则下载进度回调失效
1 parent 12538ac commit cf41fa3

2 files changed

Lines changed: 62 additions & 27 deletions

File tree

rxhttp/src/main/java/rxhttp/wrapper/progress/ProgressInterceptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public Response intercept(Chain chain) throws IOException {
2626
Response originalResponse = chain.proceed(chain.request());
2727
//包装响应体并返回
2828
return originalResponse.newBuilder()
29-
.body(new ProgressResponseBody(originalResponse.body(), progressCallback))
29+
.body(new ProgressResponseBody(originalResponse, progressCallback))
3030
.build();
3131
}
3232
}

rxhttp/src/main/java/rxhttp/wrapper/progress/ProgressResponseBody.java

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,46 @@
33

44
import java.io.IOException;
55

6-
import rxhttp.wrapper.callback.ProgressCallback;
76
import okhttp3.MediaType;
7+
import okhttp3.Response;
88
import 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
*/
1419
public 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

Comments
 (0)