Android --- Retrofit 上传/下载文件扩展实现进度的监听
生活随笔
收集整理的这篇文章主要介绍了
Android --- Retrofit 上传/下载文件扩展实现进度的监听
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
本文使用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 上传/下载文件扩展实现进度的监听的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: mysql - 要问 varchar 能
- 下一篇: Android --- 漂亮的 Load