使用Retrofit上传文件的问题

自定义了RequestBody,我点击上传,会出现这种情况: progressbar会走完一次,然后再从零开始正常走.想要实现的是,点击上传,正常从零开始走.
下面是上传的代码函数和自定义RequstBody
1.上传类的函数:

 /**
     * 上传视频
     */
    private void uploadVideo() {
        String title = mTitle.getText().toString().trim();
        if (TextUtils.isEmpty(title)) {
            ToastUtil.showMessage(R.string.title_cannot_empty);
            return;
        }
        HashMap<String, String> map = new HashMap<>();
        File file = new File(url);

        RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        //无进度
//        MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestBody);

        //自定义RequestBody显示进度
        MyBody myBody = new MyBody(requestBody, new MyBody.ProgressListener() {
            @Override
            public void onProgress(long currentBytes, long contentLength) {
                int current = new Long(currentBytes).intValue();
                int total = new Long(contentLength).intValue();
                if (seted) {
                    numberProgressBar.setVisibility(View.VISIBLE);
                    numberProgressBar.setMax(total);                //只设置一次最大值
                    seted = false;
                Log.d(TAG, "onProgress: 1040  "+  total);
                }
                numberProgressBar.setProgress(current);
            }
        });
        MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), myBody);
        String uid = UserManager.getInstance().getUid();
        map.put("type", "user");
        map.put("dataType", "1");
        map.put("videoType", "video");
        map.put("dataName", title);
        map.put("userId", uid);
        RxManager.getMethod().uploadVideo(body, map)
                .compose(RxUtil.schedulers(this))
                .subscribe(new RxCallback<UploadVideoBean>(this) {

                    @Override
                    public void onSuccess(UploadVideoBean uploadVideoBean, String msg) {
                        ToastUtil.showMessage(R.string.upload_success_please_wait_audit, 4000);
                        MainActivity.open(PreviewActivity.this);
                        finish();
                    }
                });
    }

2.自定义RequstBody:

public class MyBody extends RequestBody {

    private static final String TAG = "MyBody";

    public interface ProgressListener {
        void onProgress(long currentBytes, long contentLength);
    }

    public class ProgressModel {
        private long currentBytes = 0;
        private long contentLength = 0;
        public ProgressModel(long currentBytes, long contentLength) {
            this.currentBytes = currentBytes;
            this.contentLength = contentLength;
        }
        public long getCurrentBytes() {
            return currentBytes;
        }
        public long getContentLength() {
            return contentLength;
        }
    }

    public static final int UPDATE = 0x01;
    private RequestBody requestBody;
    private ProgressListener mListener;
    private MyHandler myHandler;
    private BufferedSink bufferedSink;

    public MyBody(RequestBody body, ProgressListener listener) {
        requestBody = body;
        mListener = listener;
        if (myHandler == null) {
            myHandler = new MyHandler();
        }
    }

    class MyHandler extends Handler {
        //放在主线程中显示
        public MyHandler() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE:
                    ProgressModel progressModel = (ProgressModel) msg.obj;
                    if (mListener != null)
                        mListener.onProgress(progressModel.getCurrentBytes(), progressModel.getContentLength());
                    break;

            }
        }
    }

    @Nullable
    @Override
    public MediaType contentType() {
        return requestBody.contentType();
    }

    @Override
    public long contentLength() throws IOException {
        return requestBody.contentLength();
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
//        if (bufferedSink == null) {
            bufferedSink = Okio.buffer(sink(sink));
//        }

        //TODO:最初写法,这样会无法上传,注释掉空判断
//        if (bufferedSink == null) {
//        bufferedSink = Okio.buffer(sink(sink));
//        }

        //写入
        requestBody.writeTo(bufferedSink);
        //刷新
        bufferedSink.flush();
    }

    private Sink sink(BufferedSink sink) {

        return new ForwardingSink(sink) {
            long bytesWritten = 0L;
            long contentLength = 0L;

            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                if (contentLength == 0) {
                    contentLength = contentLength();
                }
                bytesWritten += byteCount;
                //走了两次
                Log.d(TAG, "write: 1029=  bytesWritten: "+bytesWritten+"    ,contenglenth:"+contentLength);
                Message msg = Message.obtain();     //回调
                msg.what = UPDATE;
                msg.obj = new ProgressModel(bytesWritten, contentLength);
                myHandler.sendMessage(msg);
            }
        };
    }
}
阅读 3.1k
1 个回答

因为项目中重写了LoggingInterceptor 类。而这个类也调用了 RequestBody的write方法.只要判断BufferedSink为Buffer类型才上传数据就行了

   @Override
    public void writeTo(BufferedSink sink) throws IOException {
        if (sink instanceof Buffer) {
            //因为项目重写了日志拦截器,而日志拦截器里面调用了 RequestBody.writeTo方法,但是 它的sink类型是Buffer类型,所以直接写入
            //如果不这么做的话,上传进度最终会达到200%,因为被调用2次,而且日志拦截的writeTo是直接写入到 buffer 对象中,所以会很快;
            requestBody.writeTo(sink);
            return;
        }
        if (bufferedSink == null) {
            bufferedSink = Okio.buffer(sink(sink));
        }
        //写入
        requestBody.writeTo(bufferedSink);
        //必须调用flush,否则最后一部分数据可能不会被写入
        bufferedSink.flush();
    }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题