本文使用okhttp作为client来做,其实说白了跟用okhttp做下载上传进度监听几乎一样,参考了这篇文章:Android OkHttp文件上传与下载的进度监听扩展

1. 首先我们写两个接口用来下载和上传的进度监听回调:

/*** 请求体进度回调接口,用于文件上传进度回调*/
public interface ProgressRequestListener {void onRequestProgress(long bytesWritten, long contentLength, boolean done);
}/*** 响应体进度回调接口,用于文件下载进度回调*/
public interface ProgressResponseListener {void onResponseProgress(long bytesRead, long contentLength, boolean done);
}

2. 实现 ProgressRequestBody、ProgressResponseBody

ProgressRequestBody类继承RequestBody用于请求进度监听,用于文件上传进度监听:

import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
import rx.Observable;/*** 包装的请求体,处理进度*/
public  class ProgressRequestBody extends RequestBody {//实际的待包装请求体private  RequestBody requestBody;//进度回调接口private  ProgressRequestListener progressListener;//包装完成的BufferedSinkprivate BufferedSink bufferedSink;/*** 构造函数,赋值* @param requestBody 待包装的请求体* @param progressListener 回调接口*/public ProgressRequestBody(RequestBody requestBody, ProgressRequestListener progressListener) {this.requestBody = requestBody;this.progressListener = progressListener;}/*** 重写调用实际的响应体的contentType* @return MediaType*/@Overridepublic MediaType contentType() {return requestBody.contentType();}/*** 重写调用实际的响应体的contentLength* @return contentLength* @throws IOException 异常*/@Overridepublic long contentLength() throws IOException {return requestBody.contentLength();}/*** 重写进行写入* @param sink BufferedSink* @throws IOException 异常*/@Overridepublic void writeTo(BufferedSink sink) throws IOException {if (bufferedSink == null) {//            //包装bufferedSink = Okio.buffer(sink(sink));}//写入requestBody.writeTo(bufferedSink);//必须调用flush,否则最后一部分数据可能不会被写入bufferedSink.flush();}/*** 写入,回调进度接口* @param sink Sink* @return Sink*/private Sink sink(Sink sink) {return new ForwardingSink(sink) {//当前写入字节数long bytesWritten = 0L;//总字节长度,避免多次调用contentLength()方法long contentLength = 0L;@Overridepublic void write(Buffer source, long byteCount) throws IOException {super.write(source, byteCount);if (contentLength == 0) {//获得contentLength的值,后续不再调用contentLength = contentLength();}//增加当前写入的字节数bytesWritten += byteCount;//回调if(progressListener != null){progressListener.onRequestProgress(bytesWritten, contentLength, bytesWritten == contentLength);}}};}
}

ProgressResponseBody 继承 ResponseBody 用于下载进度监听:

package com.cm.retrofit.http;/*** Created by Cmad on 2016/4/28.*/import java.io.IOException;import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;/*** 包装的响体,处理进度*/
public class ProgressResponseBody extends ResponseBody {//实际的待包装响应体private final ResponseBody responseBody;//进度回调接口private final ProgressResponseListener progressListener;//包装完成的BufferedSourceprivate BufferedSource bufferedSource;/*** 构造函数,赋值** @param responseBody     待包装的响应体* @param progressListener 回调接口*/public ProgressResponseBody(ResponseBody responseBody, ProgressResponseListener progressListener) {this.responseBody = responseBody;this.progressListener = progressListener;}/*** 重写调用实际的响应体的contentType** @return MediaType*/@Overridepublic MediaType contentType() {return responseBody.contentType();}/*** 重写调用实际的响应体的contentLength** @return contentLength* @throws IOException 异常*/@Overridepublic long contentLength() {return responseBody.contentLength();}/*** 重写进行包装source** @return BufferedSource*/@Overridepublic BufferedSource source() {if (bufferedSource == null) {//包装bufferedSource = Okio.buffer(source(responseBody.source()));}return bufferedSource;}/*** 读取,回调进度接口** @param source Source* @return Source*/private Source source(Source source) {return new ForwardingSource(source) {//当前读取字节数long totalBytesRead = 0L;@Overridepublic long read(Buffer sink, long byteCount) throws IOException {long bytesRead = super.read(sink, byteCount);//增加当前读取的字节数,如果读取完成了bytesRead会返回-1totalBytesRead += bytesRead != -1 ? bytesRead : 0;//回调,如果contentLength()不知道长度,会返回-1if(progressListener != null){progressListener.onResponseProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1);}return bytesRead;}};}
}

上面两个类里的writeTo跟source方法用到了sink跟Source,这两个类属于Okio,也是Square开源的java io补充库,有兴趣的可以去了解一下,这里就不做详细介绍了.

3. 实现HttpClientHelper类

HttpClientHelper用于创建okhttp client,并对okhttpclient添加拦截事件,将requestBody和responseBody替换成我们自己实现的ProgressRequestBody和ProgressResponseBody

package com.cm.retrofit.http;import java.io.IOException;import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;/*** Created by Cmad on 2016/4/28.*/
public class HttpClientHelper {/*** 包装OkHttpClient,用于下载文件的回调* @param progressListener 进度回调接口* @return 包装后的OkHttpClient*/public static OkHttpClient addProgressResponseListener(final ProgressResponseListener progressListener){OkHttpClient.Builder client = new OkHttpClient.Builder();//增加拦截器client.addInterceptor(new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {//拦截Response originalResponse = chain.proceed(chain.request());//包装响应体并返回return originalResponse.newBuilder().body(new ProgressResponseBody(originalResponse.body(), progressListener)).build();}});return client.build();}/*** 包装OkHttpClient,用于上传文件的回调* @param progressListener 进度回调接口* @return 包装后的OkHttpClient*/public static OkHttpClient addProgressRequestListener(final ProgressRequestListener progressListener){OkHttpClient.Builder client = new OkHttpClient.Builder();//增加拦截器client.addInterceptor(new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request original = chain.request();Request request = original.newBuilder().method(original.method(), new ProgressRequestBody(original.body(),progressListener)).build();return chain.proceed(request);}});return client.build();}
}

4. 使用

File file = new File(fileUri);
RequestBody requestFile =RequestBody.create(MediaType.parse("multipart/form-data"), file);
//将requestFile封装成ProgressRequestBody传入
MultipartBody.Part body =MultipartBody.Part.createFormData("file", file.getName(), new ProgressRequestBody(requestFile,this));//this是在当前类实现了ProgressRequestListener接口
Call<ResponseBody> call = service.upload(body);

service 需要自己封装

Android --- Retrofit 上传/下载文件扩展实现进度的监听相关推荐

  1. python ftp上传/下载文件,带进度条显示

    文章目录 想法 最终效果 python代码 补充:下载带进度显示 想法 用python写个ftp上传文件的功能,想要实时看到上传进度,进度条ui部分,使用python的tkinter库实现. 最终效果 ...

  2. [Android]安卓上传下载文件

    Android Studio 2020.3.0 主要是参考资料1 的源码. 相关资料1 里面的文件解压到安卓项目 的android library的libs文件夹内,并添加依赖 JAVA上传 publ ...

  3. 2020-12-04使用retrofit上传下载文件,监听下载进度

    retrofit2上传.下载文件 一.上传文件 1.使用表单上传文件:结合Rxjava 先定义ApiService接口 @Multipart //Multipart表单 @POST("{ur ...

  4. android ftp同步程序,ftp同步 安卓,安卓手机ftp上传下载文件功能同步视频照片

    手机拍照越来方便,手机里的照片也越积越多,手机运行缓慢,本文利用安卓的每步FTP服务APP来自动实现手机视频照片的同步,释放手机被占用的存储空间.在机顶盒上运行每步FTP服务,机顶盒USB口连接U盘做 ...

  5. JavaWeb:上传下载文件

    1. 文件上传概述 1.1 文件上传的作用 例如网络硬盘!就是用来上传下载文件的. 在智联招聘上填写一个完整的简历还需要上传照片呢. 1.2 文件上传对页面的要求 上传文件的要求比较多,需要记一下: ...

  6. ASP.NET上传下载文件

    ASP.NET上传下载文件 上传文件: using System; using System.Collections.Generic; using System.Linq; using System. ...

  7. msf后渗透之文件交互指令、上传下载文件、屏幕截图、键盘记录、创建账户、音频录像和提权(上)

    目录 1.文件交互指令 2.上传下载文件(windows) 3.屏幕截图(windows) 4.键盘记录(windows) 1.先启动记录keyscan_start 2.显示键盘输入内容keyscan ...

  8. ftp上传下载文件详解

    首先导入包 import org.apache.commons.NET.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; FTPCli ...

  9. ftp上传-下载文件通用工具类,已实测

    话不多说直接上代码 package com.springboot.demo.utils;import lombok.extern.slf4j.Slf4j; import org.apache.comm ...

最新文章

  1. Qt识别输入文件后缀
  2. java怎么快速创建构造方法,详解系列文章
  3. GitHub Copilot 现已登陆 Visual Studio!
  4. border,padding,margin盒模型理解
  5. MS SQL查询库、表、列数据结构信息汇总
  6. iosApp上传app遇到的问题
  7. AI攻城狮,你需要那个数据集的种子么?
  8. bilibili怎么用用户名登录_bilibili账号安全中心 | 手游网游页游攻略大全
  9. EntityFramework Code-First 简易教程(八)-------一对一
  10. linux 内核源码牛人分析 链接分享
  11. Altium Designer 18安装教程
  12. HiJson工具 火狐浏览器中的jsonHandle插件(以及乱码问题的解决)--来转换json串的格式
  13. ubuntu 安装搜狗输入法
  14. sensor 驱动调试小结
  15. 电视盒子线刷固件教程B860AV2.1-A-M-T版
  16. win10共享打印错误0x0000006_win7系统局域网无法共享惠普打印机提示0x000006be错误的解决方法...
  17. 3D刷脸支付推动新零售行业发展
  18. uniapp中使用svga动画
  19. 微信小程序--优购商城项目(4)
  20. F - Color the ball

热门文章

  1. 数据结构与算法,每日一道
  2. 【Hibernate框架开发之五】Hibernate对象的三种状态Session常用方法
  3. 南通市交巡警支队同城异地容灾备份系统项目中标结果公告
  4. webwork 标签 基本用法 例子
  5. Tensorflow2.0与Tensorflow1.x不兼容问题
  6. CentOS 7 安装Golang
  7. FFmpeg学习5:多线程播放视音频
  8. 解决TIME_WAIT过多造成的问题
  9. 编译安装mysql5.6.16_CentOS 6.4下编译安装MySQL 5.6.16
  10. 获取另一个驱动的设备结构体_《rt-thread驱动框架分析》-i2c驱动