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();