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

来源:http://www.cnblogs.com/cxk1995/archive/2016/10/25/5996586.html
-Advertisement-
Play Games

關於Retrofit+OkHttp的強大這裡就不多說了,還沒瞭解的同學可以自行去百度。這篇文章主要講如何利用Retrofit+OkHttp來實現一個較為簡單的緩存策略:即有網環境下我們請求數據時,如果沒有緩存或者緩存過期了,就去伺服器拿數據,並且將新緩存保存下來,如果有緩存而且沒有過期,則直接使用緩 ...


關於Retrofit+OkHttp的強大這裡就不多說了,還沒瞭解的同學可以自行去百度。這篇文章主要講如何利用Retrofit+OkHttp來實現一個較為簡單的緩存策略:
即有網環境下我們請求數據時,如果沒有緩存或者緩存過期了,就去伺服器拿數據,並且將新緩存保存下來,如果有緩存而且沒有過期,則直接使用緩存。無網環境下我們請求數據時,緩存沒過期則直接使用緩存,緩存過期了則無法使用,需要重新聯網獲取伺服器數據。

緩存處理還是很有必要的,它有效的減少伺服器負荷,降低延遲提升用戶體驗,同時也方便用戶即使在沒網路的情況下也能使用APP。

之前一直有一個疑惑,既然Retrofit已經是對OkHttp的一個封裝了,為什麼還一直說Retrofit+OkHttp要一起搭配使用,後來才知道其實OKHttp很重要的一個作用,就是對一些網路請求的配置,例如連接超時,讀取超時,以及一些緩存配置等。

 

一、添加依賴
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'

 

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

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();

 

三、配置Retrofit

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

 

四、編寫攔截器

  我們知道其實Retrofit+OkHttp的緩存主要通過攔截器實現,所以主要做的功夫也在攔截器裡面。

 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;
        }
    };

到這裡,其實已經可以實現了我們開頭所說的緩存效果了。

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

首先我們只需要在介面前面添加@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;
        }
    };
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 20161024 打算轉ios開發工程師的崗位 今天看了下視頻,自己吭呲吭呲幾下開始寫UI 先把Xcode8 的界面總結下 navigator ['nævɪɡetɚ] 導航器、瀏覽器 symbol navigator 符號導航器 此導航器提供快速定位至項目中局部標識符的方法,例如組成應用程式的類、協 ...
  • 最近太忙了,一直沒時間 寫博客,項目基本搞完了,這幾天沒事多寫幾篇博客。歡迎加群交流iOS技術,QQ交流群:45992174。 剛裝的xcode8,不知道從哪來的一堆log 去除方法:Xcode8 >Product Edit Scheme... -> Run -> Arguments, 在Envir ...
  • 在這裡只粘貼部分代碼 在第一課中,只有View滑動完畢,才觸發動畫效果,令滑塊移動,在第二課中,將實現滑塊與View同步運行。 SecondActivity.java 下麵詳細介紹ViewPager.OnPageChangeListener監聽器的三個重寫方法: 當從手指按下,到頁面滑動停止的過程: ...
  • 有一種方法可以阻止父層的View截獲touch事件,就是調用 getParent().requestDisallowInterceptTouchEvent(true);方法。一旦底層View收到touch的 action後調用這個方法那麼父層View就不會再調用onInterceptTouchEve ...
  • 在學校開課學習了android的一些簡單的UI組件,佈局,四大組件學習了2個,數據存儲及網路通信,都是一些簡單的概念,入門而已。許多東西需要自己去學習。 學習一下 Android開發環境的搭建,兩種方式開發:一種是Eclipse,另一種是Android Studio。 Eclipse 一、下載and ...
  • 1. JSONObject對象的optXXX和getXXX的區別? getInt("key") 取值 不存在 或者類型不對 報錯optInt("key") 取值 不存在 返回預設值 getDouble("key") 取值 不存在 或者類型不對 報錯optDouble("key",0) 取值 不存在 ...
  • 在Android 4.4系統中,外置存儲卡(SD卡)被稱為二級外部存儲設備(secondary storage),應用程式已無法往外置存儲卡(SD卡)寫入數據,並且WRITE_EXTERNAL_STORAGE只為設備上的主要外部存儲(primary storage)授予寫許可權,對於其他外部存儲,其上 ...
  • 滿網都是微信小程式,技術dog們不關註都不行了。先別忙著去學怎麼開發小程式,先糾正一下你對微信小程式的三觀吧~~~~ 小程式目前被炒得沸沸揚揚,無數媒體和企業藉機獲取閱讀流量。 這再次證明一點,微信想讓什麼火,真的就能讓什麼火。 先列出8個多數人都搞錯的問題: 以上8個是很多人憑直覺得出的結論,但真 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...