-
Notifications
You must be signed in to change notification settings - Fork 289
Expand file tree
/
Copy pathProgressResponseBody.java
More file actions
130 lines (119 loc) · 5.28 KB
/
ProgressResponseBody.java
File metadata and controls
130 lines (119 loc) · 5.28 KB
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* Copyright 2017 JessYan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.jessyan.progressmanager.body;
import android.os.Handler;
import android.os.SystemClock;
import java.io.IOException;
import java.util.Set;
import me.jessyan.progressmanager.ProgressListener;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
/**
* ================================================
* 继承于 {@link ResponseBody}, 通过此类获取 Okhttp 下载的二进制数据
* <p>
* Created by JessYan on 02/06/2017 18:25
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* ================================================
*/
public class ProgressResponseBody extends ResponseBody {
protected Handler mHandler;
protected int mRefreshTime;
protected final ResponseBody mDelegate;
protected final Set<ProgressListener> mListeners;
protected final ProgressInfo mProgressInfo;
private BufferedSource mBufferedSource;
public ProgressResponseBody(Handler handler, ResponseBody responseBody, Set<ProgressListener> listeners, int refreshTime) {
this.mDelegate = responseBody;
this.mListeners = listeners;
this.mHandler = handler;
this.mRefreshTime = refreshTime;
this.mProgressInfo = new ProgressInfo(System.currentTimeMillis());
}
@Override
public MediaType contentType() {
return mDelegate.contentType();
}
@Override
public long contentLength() {
return mDelegate.contentLength();
}
@Override
public BufferedSource source() {
if (mBufferedSource == null) {
mBufferedSource = Okio.buffer(source(mDelegate.source()));
}
return mBufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
private long totalBytesRead = 0L;
private long lastRefreshTime = 0L; //最后一次刷新的时间
private long tempSize = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = 0L;
try {
bytesRead = super.read(sink, byteCount);
} catch (IOException e) {
e.printStackTrace();
for (ProgressListener listener:mListeners) {
listener.onError(mProgressInfo.getId(), e);
}
throw e;
}
if (mProgressInfo.getContentLength() == 0) { //避免重复调用 contentLength()
mProgressInfo.setContentLength(contentLength());
}
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
tempSize += bytesRead != -1 ? bytesRead : 0;
if (!mListeners.isEmpty()) {
long curTime = SystemClock.elapsedRealtime();
if (curTime - lastRefreshTime >= mRefreshTime || bytesRead == -1 || totalBytesRead == mProgressInfo.getContentLength()) {
final long finalBytesRead = bytesRead;
final long finalTempSize = tempSize;
final long finalTotalBytesRead = totalBytesRead;
final long finalIntervalTime = curTime - lastRefreshTime;
for (final ProgressListener listener:mListeners) {
mHandler.post(new Runnable() {
@Override
public void run() {
// Runnable 里的代码是通过 Handler 执行在主线程的,外面代码可能执行在其他线程
// 所以我必须使用 final ,保证在 Runnable 执行前使用到的变量,在执行时不会被修改
mProgressInfo.setEachBytes(finalBytesRead != -1 ? finalTempSize : -1);
mProgressInfo.setCurrentbytes(finalTotalBytesRead);
mProgressInfo.setIntervalTime(finalIntervalTime);
mProgressInfo.setFinish(finalBytesRead == -1 && finalTotalBytesRead == mProgressInfo.getContentLength());
listener.onProgress(mProgressInfo);
}
});
}
lastRefreshTime = curTime;
tempSize = 0;
}
}
return bytesRead;
}
};
}
}