MVP架構實現的Github客戶端(4-加入網絡緩存)

系列文章:
1-準備工作
2-搭建項目框架
3-功能實現
4-加入網絡緩存

經過前面的幾項工作, 項目框架和功能開發(fā)規(guī)范已經差不過出來了. 接下來要做的就說迭代功能, 和完善細節(jié)了.

今天我們要做的是給我們的網絡請求加入緩存機制. 類似于一般的閱讀類App, 緩存機制一般如下:

  1. 有網時根據設置的Cache Control時間來判斷是使用緩存還是重新做網絡請求.
  2. 無網絡環(huán)境下直接使用緩存, 保證閱讀體驗.

1, 為什么要加緩存

緩存之所以必要, 最重要的是能給用戶以良好的體驗.
另外網絡數據緩存也是App網絡流量優(yōu)化, 電量優(yōu)化的一個必要手段.

2, 好了, 廢話還是少說, 直接開始

要做到緩存僅需要三步:

  1. 請求客戶端配置緩存目錄.
  2. Request中須帶有Cache-Control的header, 以便請求時決定是否使用緩存.
  3. Response中須帶有Cache-Control的header, 以告知Client端該響應是否可以緩存, 以及緩存時效.

2.1 配置OkHttp的緩存目錄

  • 設置Cache Dir
private static final long CACHE_SIZE = 1024 * 1024 * 50;

@Override
public OkHttpClient.Builder customize(OkHttpClient.Builder builder) {
   // set cache dir
   File cacheFile = new File(mContext.getCacheDir(), "github_repo");
   Cache cache = new Cache(cacheFile, CACHE_SIZE);
   builder.cache(cache);

   ...
   
   return builder;
}

2.2 配置Retrofit Request接口的"Cache-Control" Header

顧名思義, "Cache-Control"請求頭就是用來控制緩存的. 它有一些屬性值來指定緩存的屬性, 諸如公共屬性, 是否可緩存以及緩存的有效期等.

關于"Cache-Control"的詳細解釋和使用請自行google...在此略過.
個人也有計劃寫一些關于HTTP協議相關的基礎知識, 會聊到Cache-Control, 敬請期待.

以獲取Github Trending這個接口為例:

@Headers("Cache-Control: public, max-age=180")
@GET("trending?languages[]=java&languages[]=swift&languages[]=objective-c&languages[]=bash&languages[]=python&languages[]=html")
Observable<TrendingResultResp> getTrendingRepos();
  • public 指示響應可被任何緩存區(qū)緩存
  • max-age=180 指示該請求的緩存的有效期為3分鐘(以秒為單位).

2.3 配置Response中的"Cache-Control" Header

眾所周知, Response是由服務器控制的, 我們如何加入"Cache-Control"頭呢? 方法有二:

  1. 說服服務器的開發(fā)人員按照你的需求在response中加入Cache-Control.
  2. 使用我們接下來要說的OkHttp的攔截器interceptor.

大多數情況下, 服務器可能并不受我們控制. 服務器開發(fā)人員開發(fā)多個系統, 對端的緩存需求不熟悉, 又或是服務器接口并不是我們自己開發(fā)的, 例如本系列做的這個GithubApp.

所幸, OkHttp提供了interceptor來讓我們對request, response進行攔截處理, 加入我們想要的請求頭等.

如下是本例使用的Cache Interceptor:

private final Interceptor mCacheControlInterceptor = new Interceptor() {
   @Override
   public Response intercept(Chain chain) throws IOException {
       Request request = chain.request();
       if (!NetworkUtil.isNetworkAvailable(mContext)) {
           request = request.newBuilder()
                   .cacheControl(CacheControl.FORCE_CACHE)
                   .build();
       }

       Response originalResponse = chain.proceed(request);

       if (NetworkUtil.isNetworkAvailable(mContext)) {

           String cacheControl = request.cacheControl().toString();

           return originalResponse.newBuilder()
                   .header("Cache-Control", cacheControl)
                   .build();
       } else {
           return originalResponse.newBuilder()
                   .header("Cache-Control", CacheControl.FORCE_CACHE.toString())
                   .build();
       }
   }
};

如下攔截器, 做了:

  1. 對于request, 當沒有網絡時, 使用CacheControl.FORCE_CACHE, 即使用緩存. (正常情況使用2.2配置的Cache-Control)
  2. 對于response, 有網時, 加入和request一樣的Cache-Control;
  3. 對于response, 無網, 使用CacheControl.FORCE_CACHE(這種情況較為少見).

做好了攔截器, 不要忘記加到OkHttpClient中:

builder.addNetworkInterceptor(mCacheControlInterceptor);

3, 嚴重提醒

嚴重注意, 在加入interceptor時:
使用的是addNetworkInterceptor, 而非addInterceptor.

二者區(qū)別參見OkHttp wiki的Interceptor介紹, 在此就借個圖來用下:

okhttp interceptor

正所謂一圖千字, 可以很清楚的看到CACHE的層次了...具體的分析大家還是Read the fucking source code吧:)

這里就說明下為什么要使用addNetworkInterceptor吧.

某些情況下, 服務器返回的response是會帶有Cache-Control的, 如果這個Cache-Control的時效配置和你想要的不一致, 或是更甚者服務器傳回類似這樣的:

no cache

那么我們就悲劇了, no-cache, 意味著響應不會被緩存.

  • 當然, 如果服務器沒有定制response的Cache-Control屬性的話, 我們使用addInterceptor來添加攔截器, 還是可以給reponse加入Cache-Control并使其緩存的.

  • 關于Interceptor和NetworkInterceptor的區(qū)別, 建議大家還是讀源碼...在此略過.

  • 穩(wěn)妥起見, 完全由客戶端可控的話, 還是使用addNetworkInterceptor吧.

4, 結語

回顧下, 加入網絡緩存的幾步:

  1. 配置緩存目錄
  2. 配置request Cache-Control
  3. 配置response Cache-Control

雖說簡單, 但是個中的確包含了很多知識點. Cache-Control屬性的使用, 意義; OkHttp的攔截器; Retrofit的header配置等等.

還是那句話, 更多的是希望大家能夠在學到東西的同時, 了解更多其相關的原理, 或是學習方法.

知其然, 知其所以然.

本文例子, 完整代碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容