由于前段时间升级了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里面的我加入详细注释,应该很容易看懂> 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 )" ); } //获得SmartCall中的类型 final Type responseType = ((ParameterizedType) returnType).getActualTypeArguments()[0]; final Executor callbackExecutor = asyncExecutor; return new CallAdapter>() { @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使用自定义的SmartCallgetImageList();
其他的使用方法和retrofit一致
demo地址:github记得star给星,如若有问题请留言或者在github上提issue