-
Notifications
You must be signed in to change notification settings - Fork 289
Expand file tree
/
Copy pathProgressRequestBody.java
More file actions
143 lines (130 loc) · 5.21 KB
/
ProgressRequestBody.java
File metadata and controls
143 lines (130 loc) · 5.21 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
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
* 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.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
/**
* ================================================
* 继承于 {@link RequestBody}, 通过此类获取 Okhttp 上传的二进制数据
* <p>
* Created by JessYan on 02/06/2017 18:05
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* ================================================
*/
public class ProgressRequestBody extends RequestBody {
protected Handler mHandler;
protected int mRefreshTime;
protected final RequestBody mDelegate;
protected final Set<ProgressListener> mListeners;
protected final ProgressInfo mProgressInfo;
private BufferedSink mBufferedSink;
public ProgressRequestBody(Handler handler, RequestBody delegate, Set<ProgressListener> listeners, int refreshTime) {
this.mDelegate = delegate;
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() {
try {
return mDelegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
if (mBufferedSink == null) {
mBufferedSink = Okio.buffer(new CountingSink(sink));
}
try {
mDelegate.writeTo(mBufferedSink);
mBufferedSink.flush();
} catch (IOException e) {
e.printStackTrace();
for (ProgressListener listener:mListeners) {
listener.onError(mProgressInfo.getId(), e);
}
throw e;
}
}
protected final class CountingSink extends ForwardingSink {
private long totalBytesRead = 0L;
private long lastRefreshTime = 0L; //最后一次刷新的时间
private long tempSize = 0L;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
try {
super.write(source, 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());
}
totalBytesRead += byteCount;
tempSize += byteCount;
if (!mListeners.isEmpty()) {
long curTime = SystemClock.elapsedRealtime();
if (curTime - lastRefreshTime >= mRefreshTime || totalBytesRead == mProgressInfo.getContentLength()) {
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(finalTempSize);
mProgressInfo.setCurrentbytes(finalTotalBytesRead);
mProgressInfo.setIntervalTime(finalIntervalTime);
mProgressInfo.setFinish(finalTotalBytesRead == mProgressInfo.getContentLength());
listener.onProgress(mProgressInfo);
}
});
}
lastRefreshTime = curTime;
tempSize = 0;
}
}
}
}
}