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

由于前段时间升级了retrofit版本到了2.1,导致原来写的缓存框架出现了点问题,后来在github上看到一个smartCache缓存框架

而其版本是2.0beta版和正式版有点差距,于是就自己更改了一下框架代码,现在分享给大家

retrofit2.0增加先读缓存后请求网络的功能_第1张图片

项目只有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 getImageList();
使用自定义的SmartCall

其他的使用方法和retrofit一致

demo地址:github记得star给星,如若有问题请留言或者在github上提issue




你可能感兴趣的:(网络请求,retrofit)