您的位置:首页 > 理论基础 > 计算机网络

retrofit2.0增加先读缓存后请求网络的功能

2016-08-05 15:49 549 查看
由于前段时间升级了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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐