okhttp3.4.1+retrofit2.1.0實現離線緩存

關於Retrofit+OkHttp的強大這裏就很少說了,還沒了解的同窗能夠自行去百度。這篇文章主要講如何利用Retrofit+OkHttp來實現一個較爲簡單的緩存策略:
即有網環境下咱們請求數據時,若是沒有緩存或者緩存過時了,就去服務器拿數據,而且將新緩存保存下來,若是有緩存並且沒有過時,則直接使用緩存。無網環境下咱們請求數據時,緩存沒過時則直接使用緩存,緩存過時了則沒法使用,須要從新聯網獲取服務器數據。緩存

緩存處理仍是頗有必要的,它有效的減小服務器負荷,下降延遲提高用戶體驗,同時也方便用戶即便在沒網絡的狀況下也能使用APP。服務器

以前一直有一個疑惑,既然Retrofit已是對OkHttp的一個封裝了,爲何還一直說Retrofit+OkHttp要一塊兒搭配使用,後來才知道其實OKHttp很重要的一個做用,就是對一些網絡請求的配置,例如鏈接超時,讀取超時,以及一些緩存配置等。網絡

 

1、添加依賴
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'ide

 

2、配置OkHttpClient(設置緩存路徑和緩存文件大小) ui

File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");//這裏爲了方便直接把文件放在了SD卡根目錄的HttpCache中,通常放在context.getCacheDir()中
int cacheSize = 10 * 1024 * 1024;//設置緩存文件大小爲10M
Cache cache = new Cache(httpCacheDirectory, cacheSize);
httpClient = new OkHttpClient.Builder()
             .connectTimeout(10, TimeUnit.SECONDS)//設置鏈接超時
             .readTimeout(10, TimeUnit.SECONDS)//讀取超時
             .writeTimeout(10, TimeUnit.SECONDS)//寫入超時
             .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加自定義緩存攔截器(後面講解),注意這裏須要使用.addNetworkInterceptor
             .cache(cache)//把緩存添加進來
             .build();

 

3、配置Retrofitspa

retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(httpClient)//把OkHttpClient添加進來
                .addConverterFactory(GsonConverterFactory.create())
                .build();

 

4、編寫攔截器日誌

  咱們知道其實Retrofit+OkHttp的緩存主要經過攔截器實現,因此主要作的功夫也在攔截器裏面。code

 static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            //網上不少示例代碼都對在request請求前對其進行無網的判斷,其實無需判斷,無網自動訪問緩存
//            if(!NetworkUtil.getInstance().isConnected()){
//                request = request.newBuilder()
//                        .cacheControl(CacheControl.FORCE_CACHE)//只訪問緩存
//                        .build();
//            }
            Response response = chain.proceed(request);

            if (NetworkUtil.getInstance().isConnected()) {
                int maxAge = 60;//緩存失效時間,單位爲秒
                return response.newBuilder()
                        .removeHeader("Pragma")//清除頭信息,由於服務器若是不支持,會返回一些干擾信息,不清除下面沒法生效
                        .header("Cache-Control", "public ,max-age=" + maxAge)
                        .build();
            } else {
                //這段代碼設置無效
//                int maxStale = 60 * 60 * 24 * 28; // 無網絡時,設置超時爲4周
//                return response.newBuilder()
//                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
//                        .removeHeader("Pragma")
//                        .build();
            }
            return response;
        }
    };

到這裏,其實已經能夠實現了咱們開頭所說的緩存效果了。blog

  可是,上面設置的每一個接口緩存時間都同樣,例如我如今想讓不一樣接口的緩存數據失效時間都不同,甚至有些接口不緩存數據,應該怎麼作呢?其實也很簡單接口

首先咱們只須要在接口前面添加@Headers參數(max-age表明緩存時間,單位爲秒,示例中表示緩存失效時間爲60s,想要多少時間能夠自行設置),不設置@Headers參數則不進行緩存。

    @Headers("Cache-Control:public ,max-age=60")
    @GET("getBusiness.action")//商店信息
    Call<RestaurantInfoModel> getRestaurantInfo(@Query("userId") String userId,@Query("businessId") String businessId);

 同時,咱們的緩存攔截器也要作下簡單的修改(去掉了以前的註釋代碼)

    static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            Response response = chain.proceed(request);

            if (NetworkUtil.getInstance().isConnected()) {
                //獲取頭部信息
                String cacheControl =request.cacheControl().toString();
                return response.newBuilder()
                        .removeHeader("Pragma")//清除頭信息,由於服務器若是不支持,會返回一些干擾信息,不清除下面沒法生效
                        .header("Cache-Control", cacheControl)
                        .build();
            }
            return response;
        }
    };

 

*注意:

1.只能緩存Get請求的接口,不能緩存Post請求的接口

2.OkHttpClient須要用.addNetworkInterceptor添加緩存攔截器,不能使用.addInterceptor,也無需二者同時使用。

3.此方法無需服務器端任何操做,適用於服務器端沒有其餘緩存策略,若是服務器端有本身的緩存策略代碼應該作相應的修改,以適應服務器端。

 

附上全部代碼:

/**
 * 簡單封裝的Retroit初始化類
 */
public class initRetrofit {
    private static String baseUrl = "http://202.171.212.154:8080/hh/";
    private static OkHttpClient httpClient;
    private static Retrofit retrofit;

    public static Retrofit initRetrofit() {
        //緩存路徑和大小
        File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");
        int cacheSize = 10 * 1024 * 1024;
        Cache cache = new Cache(httpCacheDirectory, cacheSize);

        //日誌攔截器
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)//設置鏈接超時
                .readTimeout(10, TimeUnit.SECONDS)//讀取超時
                .writeTimeout(10, TimeUnit.SECONDS)//寫入超時
                .addInterceptor(interceptor)//添加日誌攔截器
                .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加緩存攔截器
                .cache(cache)//把緩存添加進來
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(httpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        return retrofit;
    }

    public static RetrofitAPI getService() {
        return initRetrofit().create(RetrofitAPI.class);
    }

//    //緩存攔截器,不一樣接口不一樣緩存
//    static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
//        @Override
//        public Response intercept(Chain chain) throws IOException {
//
//            Request request = chain.request();
//            Response response = chain.proceed(request);
//
//            if (NetworkUtil.getInstance().isConnected()) {
//                String cacheControl =request.cacheControl().toString();
//                return response.newBuilder()
//                        .removeHeader("Pragma")//清除頭信息,由於服務器若是不支持,會返回一些干擾信息,不清除下面沒法生效
//                        .header("Cache-Control", cacheControl)
//                        .build();
//            }
//            return response;
//        }
//    };

    //緩存攔截器,統一緩存60s
    static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            Response response = chain.proceed(request);

            if (NetworkUtil.getInstance().isConnected()) {
                int maxAge = 60*60*24*2;//緩存失效時間,單位爲秒
                return response.newBuilder()
                        .removeHeader("Pragma")//清除頭信息,由於服務器若是不支持,會返回一些干擾信息,不清除下面沒法生效
                        .header("Cache-Control", "public ,max-age=" + maxAge)
                        .build();
            }
            return response;
        }
    };
}
相關文章
相關標籤/搜索