由于前段時間更新了retrofit版本到了2.1,導緻原來寫的緩存架構出現了點問題,後來在github上看到一個smartCache緩存架構
而其版本是2.0beta版和正式版有點差距,于是就自己更改了一下架構代碼,現在分享給大家
項目隻有6個類
AndroidExecutor:線程池裡面封裝了一個handler為了post資料到主線程種
CachingSystem:接口裡面就兩方法存緩存以及擷取緩存
BasicCaching:CachingSystem對應的實作類,實作了存取緩存方法,使用的是LruCache以及DiskLruCache算法對其進行緩存
SmartCall:自定義的一個回調接口,要使用這個架構就必須使用這個回調而不是retrofit對應的Call
SmartUtils:工具類,主要是用來把網絡資料轉化成byte資料,資料轉成byte
SmartCallFactory:關鍵類,所有的邏輯都在裡面
主要講解一下SmartCallFactory這個類
public class SmartCallFactory extends CallAdapter.Factory {
//緩存類
private final CachingSystem cachingSystem;
//線程池
private final Executor asyncExecutor;
public SmartCallFactory(CachingSystem cachingSystem){
this.cachingSystem = cachingSystem;
this.asyncExecutor = new AndroidExecutor();
}
public SmartCallFactory(CachingSystem cachingSystem, Executor executor){
this.cachingSystem = cachingSystem;
this.asyncExecutor = executor;
}
@Override
public CallAdapter<SmartCall<?>> get(final Type returnType, final Annotation[] annotations,
final Retrofit retrofit) {
TypeToken<?> token = TypeToken.of(returnType);
//如果不是對應的SmartCall則不會執行
if (token.getRawType() != SmartCall.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
//必須有實體類
throw new IllegalStateException(
"SmartCall must have generic type (e.g., SmartCall<ResponseBody>)");
}
//獲得SmartCall<T>中的類型
final Type responseType = ((ParameterizedType) returnType).getActualTypeArguments()[0];
final Executor callbackExecutor = asyncExecutor;
return new CallAdapter<SmartCall<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public <R> SmartCall<R> adapt(Call<R> call) {
return new SmartCallImpl<>(callbackExecutor, call, responseType(), annotations,
retrofit, cachingSystem);
}
};
}
/**
* 自定義一個回調執行個體
* 所有的邏輯都是在這裡面
* @param <T>
*/
static class SmartCallImpl<T> implements SmartCall<T>{
private final Executor callbackExecutor;
private final Call<T> baseCall;
private final Type responseType;
private final Annotation[] annotations;
private final Retrofit retrofit;
private final CachingSystem cachingSystem;
private final Request request;
public SmartCallImpl(Executor callbackExecutor, Call<T> baseCall, Type responseType,
Annotation[] annotations, Retrofit retrofit, CachingSystem cachingSystem){
this.callbackExecutor = callbackExecutor;
this.baseCall = baseCall;
this.responseType = responseType;
this.annotations = annotations;
this.retrofit = retrofit;
this.cachingSystem = cachingSystem;
// This one is a hack but should create a valid Response (which can later be cloned)
this.request = buildRequestFromCall();
}
/***
* 建構一個新的請求
* 這裡使用的反射機制
* * @return A valid Request (that contains query parameters, right method and endpoint)
*/
private Request buildRequestFromCall(){
try {
Field argsField = baseCall.getClass().getDeclaredField("args");
argsField.setAccessible(true);
Object[] args = (Object[]) argsField.get(baseCall);
//retrofit2.0更改了字段(1.0+)requestFactory-->(2.0+)serviceMethod
Field serviceMethodField = baseCall.getClass().getDeclaredField("serviceMethod");
serviceMethodField.setAccessible(true);
Object requestFactory = serviceMethodField.get(baseCall);
//retrofit2.0更改了方法(1.0+)create-->(2.0+)toRequest
Method createMethod = requestFactory.getClass().getDeclaredMethod("toRequest", Object[].class);
createMethod.setAccessible(true);
return (Request) createMethod.invoke(requestFactory, new Object[]{args});
}catch(Exception exc){
// Log.e("buildRequestFromCall"+exc.toString());
return null;
}
}
public void enqueueWithCache(final Callback<T> callback) {
Runnable enqueueRunnable = new Runnable() {
@Override
public void run() {
/* 讀取緩存 */
byte[] data = cachingSystem.getFromCache(buildRequest());
if(data != null) {
//獲得緩存資料
final T convertedData = SmartUtils.bytesToResponse(retrofit, responseType, annotations,
data);
Runnable cacheCallbackRunnable = new Runnable() {
@Override
public void run() {
//存在資料直接回調給調用者,
callback.onResponse(baseCall, Response.success(convertedData));
}
};
callbackExecutor.execute(cacheCallbackRunnable);
}
/* 運作網絡請求 */
baseCall.enqueue(new Callback<T>() {
@Override
public void onResponse(final Call<T> call,final Response<T> response) {
Runnable responseRunnable = new Runnable() {
@Override
public void run() {
if (response.isSuccessful()) {
//儲存資料
byte[] rawData = SmartUtils.responseToBytes(retrofit, response.body(),
responseType(), annotations);
cachingSystem.addInCache(response, rawData);
}
//再一次回調給調用者
callback.onResponse(call, response);
}
};
// Run it on the proper thread
callbackExecutor.execute(responseRunnable);
}
@Override
public void onFailure(final Call<T> call, final Throwable t) {
Runnable failureRunnable = new Runnable() {
@Override
public void run() {
callback.onFailure(call,t);
}
};
callbackExecutor.execute(failureRunnable);
}
});
}
};
Thread enqueueThread = new Thread(enqueueRunnable);
enqueueThread.start();
}
@Override
public void enqueue(final Callback<T> callback) {
if(buildRequest().method().equals("GET")){
//隻對GET請求有用
enqueueWithCache(callback);
}else{
//其他的請求和retrofit一樣
baseCall.enqueue(new Callback<T>() {
@Override
public void onResponse(final Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
callback.onResponse(call,response);
}
});
}
@Override
public void onFailure(final Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
callback.onFailure(call,t);
}
});
}
});
}
}
@Override
public Type responseType() {
return responseType;
}
@Override
public Request buildRequest() {
return request.newBuilder().build();
}
@Override
public SmartCall<T> clone() {
return new SmartCallImpl<>(callbackExecutor, baseCall.clone(), responseType(),
annotations, retrofit, cachingSystem);
}
@Override
public Response<T> execute() throws IOException {
return baseCall.execute();
}
@Override
public void cancel() {
baseCall.cancel();
}
}
}
裡面的我加入詳細注釋,應該很容易看懂
主要就是在自定義的SmartCallFactory的call執行個體中自己改寫了請求回調的方式,先看緩存中是否有資料,
有直接回調給調用者,請求資料成功後也會回調給調用者,而對應的使用方法為
Retrofit client = new Retrofit.Builder()
.baseUrl(HOST)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(smartFactory)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
mGuDong = client.create(MeoHttp.class);
建構retrofit時應增加一個自定義的CallAdapterFactory
接口調用則為
/**
* 獲得圖檔清單
*/
@GET("tnfs/api/list")
SmartCall<ImageListBean> getImageList();
使用自定義的SmartCall
其他的使用方法和retrofit一緻
demo位址:github記得star給星,如若有問題請留言或者在github上提issue