我正在尝试使用OkHttp跟踪上传的进度。我创建了一个自定义的RequestBody
,其主体如下(感谢此答案),它将写入sink并发布进度。
public class CountingFileRequestBody extends RequestBody {
private static final String TAG = "CountingFileRequestBody";
private final ProgressListener listener;
private final String key;
private final MultipartBody multipartBody;
protected CountingSink mCountingSink;
public CountingFileRequestBody(MultipartBody multipartBody,
String key,
ProgressListener listener) {
this.multipartBody = multipartBody;
this.listener = listener;
this.key = key;
}
@Override
public long contentLength() throws IOException {
return multipartBody.contentLength();
}
@Override
public MediaType contentType() {
return multipartBody.contentType();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
mCountingSink = new CountingSink(sink);
BufferedSink bufferedSink = Okio.buffer(mCountingSink);
multipartBody.writeTo(bufferedSink);
bufferedSink.flush();
}
public interface ProgressListener {
void transferred(String key, int num);
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
bytesWritten += byteCount;
listener.transferred(key, (int) (100F * bytesWritten / contentLength()));
super.write(source, byteCount);
delegate().flush(); // I have added this line to manually flush the sink
}
}
}
这里的问题是,数据被写入到接收端之后立即就会被发送,但实际上缓冲区的字节并没有真正传输到服务器。这意味着我的进度条很早就到达了终点,而实际上传却还未结束。
注意:有些人认为在每次迭代中都需要刷新接收端才能真正上传字节,但对我来说并没有起作用。