1.创建一个ApiMnanager类用来管理Retrofit的实例化操作
/**
* Created by ccwant on 2016/9/6.
*/
public class ApiManager {
private Context context;
//网络缓存目录
private File httpCacheDir ;
//网络缓存大小
private int cacheSize = 10 * 1024 * 1024; // 10 MiB
//网络连接超时时间,单位/秒
private int connTimeout=6;
//网络缓存对象
private Cache cache;
//OkHttp
private OkHttpClient client;
public ApiManager(Context context){
this.context=context;
}
/**
* 初始化
*/
private void initClient(){
httpCacheDir=new File(context.getCacheDir(),"okhttp");
cache= new Cache(httpCacheDir, cacheSize);
//创建OkHttp
client = new OkHttpClient();
client.setConnectTimeout(connTimeout, TimeUnit.SECONDS);
client.setCache(cache);
}
/**
* 获取对应服务
* @param service
* @param <T>
* @return
*/
public <T> T getApi(String url,Class<T> service){
return getApi(url,service,null);
}
/**
* 获取对应服务
* @param service
* @param listener
* @param <T>
* @return
*/
public <T> T getApi(String url,Class<T> service,ProgressResponseListener listener){
initClient();
if(listener!=null){
client.interceptors().add(new DownloadProgressInterceptor(listener));
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)//传递url
.client(client)
.addConverterFactory(JsonConverterFactory.create())//添加返回值解析器
.build();
return retrofit.create(service);
}
}
2.设置文件上传与下载的监听方法
第一步:封装一个的网络回调方法
/**
* Created by ccwant on 2016/8/19.
* 网络通讯回调接口
*/
public interface OnHttpCallBack<T> {
public void onSuccess(T entity);
public void onFailure(Throwable t);
public void onResponseProgress(long progress, long total, boolean done);
public void onRequestProgress(long progress, long total, boolean done);
}
第二步:单独封装文件上传的监听方法
/**
* 请求体进度回调接口,比如用于文件上传中
* Created by ccwant on 2016/9/7.
*/
public interface ProgressRequestListener {
void onProgress(long progress, long total, boolean done);
}
第三步:单独封装文件下载的监听方法
/**
* Created by ccwant on 2016/9/7.
*/
public interface ProgressResponseListener {
/**
* @param progress 已经下载或上传字节数
* @param total 总字节数
* @param done 是否完成
*/
void onProgress(long progress, long total, boolean done);
}
第四步:创建网络下载进度拦截器
/**
* 网络下载进度拦截器
* Created by ccwant on 2016/9/7.
*/
public class DownloadProgressInterceptor implements Interceptor {
private String TAG="DownloadProgressInterceptor";
private ProgressResponseListener listener;
public DownloadProgressInterceptor(ProgressResponseListener listener){
this.listener=listener;
}
@Override
public Response intercept(Chain chain) throws IOException {
Response orginalResponse = chain.proceed(chain.request());
return orginalResponse.newBuilder().body(new ProgressResponseBody(orginalResponse.body(),listener)).build();
}
}
第五步:包装请求体
/**
* 包装的请求体,处理进度
* Created by ccwant on 2016/9/7.
*/
public class ProgressRequestBody extends RequestBody {
//实际的待包装请求体
private final RequestBody requestBody;
//进度回调接口
private final ProgressRequestListener progressListener;
//包装完成的BufferedSink
private BufferedSink bufferedSink;
/**
* 构造函数,赋值
*
* @param requestBody 待包装的请求体
* @param progressListener 回调接口
*/
public ProgressRequestBody(RequestBody requestBody, ProgressRequestListener progressListener) {
this.requestBody = requestBody;
this.progressListener = progressListener;
}
/**
* 重写调用实际的响应体的contentType
*
* @return MediaType
*/
@Override
public MediaType contentType() {
return requestBody.contentType();
}
/**
* 重写调用实际的响应体的contentLength
*
* @return contentLength
* @throws IOException 异常
*/
@Override
public long contentLength() throws IOException {
return requestBody.contentLength();
}
/**
* 重写进行写入
*
* @param sink BufferedSink
* @throws IOException 异常
*/
@Override
public 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;
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
if (contentLength == 0) {
//获得contentLength的值,后续不再调用
contentLength = contentLength();
}
//增加当前写入的字节数
bytesWritten += byteCount;
//回调
progressListener.onProgress(bytesWritten, contentLength, bytesWritten == contentLength);
}
};
}
}
第六步:包装返回体
/**
* 包装的接收体,处理进度
* Created by ccwant on 2016/9/7.
*/
public class ProgressResponseBody extends ResponseBody {
//实际的待包装响应体
private final ResponseBody responseBody;
//进度回调接口
private final ProgressResponseListener progressListener;
//包装完成的BufferedSource
private BufferedSource bufferedSource;
/**
* 构造函数,赋值
* @param responseBody 待包装的响应体
* @param progressListener 回调接口
*/
public ProgressResponseBody(ResponseBody responseBody, ProgressResponseListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
/**
* 重写调用实际的响应体的contentType
* @return MediaType
*/
@Override public MediaType contentType() {
return responseBody.contentType();
}
/**
* 重写调用实际的响应体的contentLength
* @return contentLength
* @throws IOException 异常
*/
@Override public long contentLength() throws IOException {
return responseBody.contentLength();
}
/**
* 重写进行包装source
* @return BufferedSource
* @throws IOException 异常
*/
@Override public BufferedSource source() throws IOException {
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;
@Override public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
//增加当前读取的字节数,如果读取完成了bytesRead会返回-1
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
//回调,如果contentLength()不知道长度,会返回-1
progressListener.onProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
第七步:创建Retrofit工具类
/**
* Retrofit工具类
* Created by ccwant on 2016/9/7.
*/
public class RetrofitUtils {
/**
* 获取RequestBody请求体
* 主要用于文件上传
* @param file 文件
* @param callBack 网络回调
* @return ProgressRequestBody
*/
public static ProgressRequestBody getRequestBody(File file, Context context, OnHttpCallBack callBack){
RequestBody requetBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
return new ProgressRequestBody(requetBody,new RequestProgressTransferCallback(context,callBack));
}
/**
* 获取RequestBody请求体
* 主要用于文件上传
* @param file 文件
* @return RequestBody
*/
public static RequestBody getRequestBody(File file){
return RequestBody.create(MediaType.parse("multipart/form-data"), file);
}
}
第八步:在之前封装的ApiManager中修改添加拦截器
/**
* 获取对应服务
* @param service
* @param listener
* @param <T>
* @return
*/
public <T> T getApi(String url,Class<T> service,ProgressResponseListener listener){
initClient();
if(listener!=null){
client.interceptors().add(new DownloadProgressInterceptor(listener));
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)//传递url
.client(client)
.addConverterFactory(JsonConverterFactory.create())//添加返回值解析器
.build();
return retrofit.create(service);
}
3.文件上传
LoginApi service=mApiManager.getApi(Config.baseUrl2,LoginApi.class);
Map<String, RequestBody> params = new HashMap<>();
params.put("file\"; filename=\""+file.getName()+"", RetrofitUtils.getRequestBody(file,context,callBack));
Call<JSONObject> call= service.uploadImage(params);
4.文件下载
LoginApi service=mApiManager.getApi(Config.baseUrl3,LoginApi.class,new ResponseProgressTransferCallback(context,callBack));
Call<ResponseBody> call= service.downloadImage();