OkHttp文件上传(1):实现文件上传进度监听

前言

OkHttp已经支持标准表单形式上传文件,具体方法参考OkHttp相关教程,本文实现文件上传的进度监听。

原理

关键点是自定义 支持进度反馈的RequestBody: 重写write方法按照自定义的SEGMENT_SIZE 来写文件,从而监听进度。

public class FileProgressRequestBody extends RequestBody {

    public interface ProgressListener {
        void transferred( long size );
    }

    public static final int SEGMENT_SIZE = 2*1024; // okio.Segment.SIZE

    protected File file;
    protected ProgressListener listener;
    protected String contentType;

    public FileProgressRequestBody(File file, String contentType, ProgressListener listener) {
        this.file = file;
        this.contentType = contentType;
        this.listener = listener;
    }

    protected FileProgressRequestBody() {}

    @Override
    public long contentLength() {
        return file.length();
    }

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

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        Source source = null;
        try {
            source = Okio.source(file);
            long total = 0;
            long read;

            while ((read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
                total += read;
                sink.flush();
                this.listener.transferred(total);

            }
        } finally {
            Util.closeQuietly(source);
        }
    }

}
复制代码

FileProgressRequestBody 以2KB为单位上传,对外暴露回调ProgressListener来发布进度。接着写一个上传管理类:HttpUploader,先构造Request对象:

    protected Request generateRequest(String url){

        // 构造上传请求,模拟表单提交文件
        String formData = String.format("form-data;name=file; filename=%s", FileUtil.pickFileNameFromPath(fileInfo.filePath) );
        FileProgressRequestBody filePart = new FileProgressRequestBody( new File(fileInfo.filePath) , "application/octet-stream" , this );
        MultipartBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addPart( Headers.of("Content-Disposition",formData), filePart )
                .build();

        // 创建Request对象
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        return request;
    }
复制代码

传入文件路径,formData是与服务端的header约定,此处约定:name是文件名称 定义文件上传的执行方法doUpload:

    protected int doUpload(String url){
        try {
            OkHttpClient httpClient = OkHttpClientMgr.Instance().getOkHttpClient();
            call = httpClient.newCall( generateRequest(url) );
            Response response = call.execute();
            if (response.isSuccessful()) {
                sbFileUUID = new StringBuilder();
                return readResponse(response,sbFileUUID);
            } else( ... ) { // 重试
                return STATUS_RETRY;
            }
        } catch (IOException ioe) {
            LogUtil.e(LOG_TAG, "exception occurs while uploading file!",ioe);
        }
        return isCancelled() ? STATUS_CANCEL : STATUS_FAILED_EXIT;
    }
复制代码

上半部分是OkHttp请求的标准写法,然后对上传结果进行分析,和服务端约定返回结果。 里面的readResponse()方法就是每次上传后读取服务端的结果: 上传成功,可以让服务端返回文件的uuid,从response.body() 读取uuid 上传失败,和服务端约定一个状态码,比如500执行重试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值