版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhujiangtaotaise/article/details/82182955
最近项目需要知道上传进度,然后网上找方法,方法代码如下:
/**
* Created by za-zhujiangtao on 2018/8/23.
*/
public class UploadFileRequestBody extends RequestBody {
private RequestBody mRequestBody;
private BufferedSink bufferedSink;
private UploadProgressListener listener;
public UploadFileRequestBody(String jsonData, UploadProgressListener listener){
mRequestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), jsonData);
this.listener = listener;
}
@Override
public MediaType contentType() {
return mRequestBody.contentType();
}
@Override
public long contentLength() throws IOException {
return mRequestBody.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
if (sink instanceof Buffer){
//因为项目重写了日志拦截器,而日志拦截器里面调用了 RequestBody.writeTo方法,但是 它的sink类型是Buffer类型,所以直接写入
//如果不这么做的话,上传进度最终会达到200%,因为被调用2次,而且日志拦截的writeTo是直接写入到 buffer 对象中,所以会很快;
mRequestBody.writeTo(sink);
return;
}
if (bufferedSink == null) {
bufferedSink = Okio.buffer(sink(sink));
}
//写入
mRequestBody.writeTo(bufferedSink);
//必须调用flush,否则最后一部分数据可能不会被写入
bufferedSink.flush();
}
private Sink sink(Sink sink) {
return new ForwardingSink(sink) {
//当前写入字节数
long bytesWritten = 0L;
//总字节长度,避免多次调用contentLength()方法
long contentLength = 0L;
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
if (contentLength == 0) {
//获得contentLength的值,后续不再调用
contentLength = contentLength();
}
//增加当前写入的字节数
bytesWritten += byteCount;
Log.e("LogUtils", "bytesWritten = "+bytesWritten+", contentLength = "+contentLength);
//回调
if (listener != null){
listener.uploadProgress(bytesWritten, contentLength);
}
}
};
}
}
代码注释清除了,坑点有2个:
1. java.net.ProtocolException: unexpected end of stream。
2. 上传进度很快,一会就100%,而且会继续到200%。
这两个坑都是由同一个原因造成的,那就是因为我们项目中有日志上报,重写了LoggingInterceptor 类。而这个类也调用了 RequestBody的write方法,如下:
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
那么怎么解决了,日志上报是项目要求,肯定不能去掉了,。。。我们发现日志拦截器中的 BufferedSink 是 Buffer 类型,而上传进度获取的BufferedSink 是 ForwardingSink 类型,所以我就像上面代码中那样处理了,如果是Buffer 类型,直接写入,然后return。