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执行重试。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,793评论 19 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,843评论 25 709
  • 前言 分块上传和断点下载很像,就是讲文件分为多份来传输,从而实现暂停和继续传输。区别是断点下载的进度保存在客户端,...
    08_carmelo阅读 14,318评论 7 29
  • 枯叶落在屋檐 心没有真实的平静 曾记住一整个落日和暮霭 那时,我有一半的荒凉, 只字未提 停电的村庄,秋意更凉 在...
    惊蛰夕阅读 916评论 5 10
  • 又一天上班的日子开始了,和往常一样,女孩依然是早上6.40起床,生怕路上堵车,所以在路上走的更快,很快到了地铁站,...
    霞霞思密达阅读 1,638评论 0 0