Retrofit2 获取post上传进度的坑点

版权声明:本文为博主原创文章,未经博主允许不得转载。 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。

猜你喜欢

转载自blog.csdn.net/zhujiangtaotaise/article/details/82182955
今日推荐