[老實李] Retrofit2+OKHttp3實現(xiàn)緩存

首先需要注意的是:使用OKHttp特有的方法只能對GET請求進行緩存赔桌。(我自己就在這個坑爬了很久,因為我們公司的所有接口全部是POST請求)望众。如果想要對POST請求進行緩存的話還需要進一步的處理跌前。這一點從OKHttp的源碼中也可以找到答案灵份。(Cache類中的put方法,當請求方法不是GET的時候直接返回一個null)

private CacheRequest put(Response response) throws IOException {
  String requestMethod = response.request().method();

  if (HttpMethod.invalidatesCache(response.request().method())) {
    try {
      remove(response.request());
    } catch (IOException ignored) {
      // The cache cannot be written.
    }
    return null;
  }
  if (!requestMethod.equals("GET")) {
    // Don't cache non-GET responses. We're technically allowed to cache
    // HEAD requests and some POST requests, but the complexity of doing
    // so is high and the benefit is low.
    return null;
  }

  if (OkHeaders.hasVaryAll(response)) {
    return null;
  }

  Entry entry = new Entry(response);
  DiskLruCache.Editor editor = null;
  try {
    editor = cache.edit(urlToKey(response.request()));
    if (editor == null) {
      return null;
    }
    entry.writeTo(editor);
    return new CacheRequestImpl(editor);
  } catch (IOException e) {
    abortQuietly(editor);
    return null;
  }
}

好瓦胎,下面我們就分別來看在GET和POST方法中緩存的實現(xiàn)根蟹。

一嘁扼、GET緩存

1姑裂、首先定義兩個Interceptor,分別作為有網絡時的攔截器和無網絡時的攔截器馋袜。關于攔截器的自定義,網上到處都是舶斧,我這里就寫了兩個最簡單的欣鳖。

public class NoNetInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {

    Request request = chain.request();
    boolean connected = HttpNetUtil.isNetConnected(ETApplication.getInstance());
    if (!connected) {
        request = request.newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .build();
        Log.e("etNet", "have not network and to read local cache");
        Response response = chain.proceed(request);
        return response.newBuilder()
                .header("Cache-Control", "public, only-if-cached, max-stale=3600")
                .removeHeader("Pragma")
                .build();
    }
    return chain.proceed(request);

}

}

public class NetInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
boolean connected = HttpNetUtil.isNetConnected(ETApplication.getInstance());
if(connected){
//if have network will cache 90s
Log.e("etNet","online cache 90s");
Response response = chain.proceed(request);
int maxTime = 90;
return response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxTime)
.build();
}
//if have not network will immediate return
return chain.proceed(request);
}

}

2、在Retrofit中使用

public class RetrofitUtil {
    private static Retrofit retrofit;
    //over time
    private static final long DUFAULT_TIME_OUT = 5;
    /**
    * @return retrofit instance
    */
    public static Retrofit getRetrofitInstance() {
        if (retrofit == null) {
            File file = new File(ETApplication.getInstance().getApplicationContext().getCacheDir(), "rxCache");
            //cache size 10M
            int cacheSize = 10 * 1024 * 1024;
            Cache cache = new Cache(file, cacheSize);
            OkHttpClient client = new OkHttpClient.Builder()
                    .cache(cache)
                    .addInterceptor(new NoNetInterceptor())
                    .addNetworkInterceptor(new NetInterceptor())
                    .connectTimeout(DUFAULT_TIME_OUT, TimeUnit.SECONDS) //連接超時
                    .writeTimeout(DUFAULT_TIME_OUT, TimeUnit.SECONDS)  //寫入超時
                    .readTimeout(DUFAULT_TIME_OUT, TimeUnit.SECONDS)  //讀取超時
                    .build();
            retrofit = new Retrofit.Builder()
                    .client(client)
                    .baseUrl(Urls.severURL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

        }
        return retrofit;
    }

    /**
    * @return interface instance
    *
    */
    public static APIRetrofit getAPIRetrofitInstance() {
        return getRetrofitInstance().create(APIRetrofit.class);
    }

}

二茴厉、POST請求緩存

我的做法是用GreenDao來進行緩存观堂。
攔截器參考:http://blog.csdn.net/u010429311/article/details/59116706
GreenDao參考:http://www.reibang.com/p/4986100eff90

public class RewriteCacheControlInterceptor implements Interceptor {

    private EtCacheDao mEtCacheDao;

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        String url = request.toString();
        Log.e("OkHttp","url:"+url);
        Buffer buffer = new Buffer();
        request.body().writeTo(buffer);
        String params = buffer.readString(Charset.forName("UTF-8"));
        Log.e("OkHttp","params:"+params);
        mEtCacheDao = ETApplication.getInstance().getDaoSession().getEtCacheDao();
        Response response;
        if (HttpNetUtil.isNetConnected(ETApplication.getInstance())) {
            int maxAge = 60 * 60*24;
            Response originalResponse = chain.proceed(request);
            MediaType type = originalResponse.body().contentType();
            byte[] bs = originalResponse.body().bytes();
            response = originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .removeHeader("Cache-Control")
                    .header("Cache-Control", "public, max-age=" + maxAge)
                    .body(ResponseBody.create(type, bs))
                    .build();
            Log.e("OKHttp","response:"+new String(bs,"UTF-8"));
            EtCache etCache = new EtCache(url+params, new String(bs, "UTF-8"));
            List<EtCache> list = mEtCacheDao.queryBuilder()
                    .where(EtCacheDao.Properties.UrlAndParams.eq(url+params))
                    .list();
            if (list==null||list.size()==0) {
                mEtCacheDao.insert(etCache);
            }

        } else {
            String b =  "";
            List<EtCache> list = mEtCacheDao.queryBuilder()
                    .where(EtCacheDao.Properties.UrlAndParams.eq(url+params))
                    .list();
            if (list != null && list.size() > 0) {
                b = list.get(0).getResponse();
            }

            Log.e("OkHttp", "request:" + url);
            Log.e("OkHttp", "request method:" + request.method());
            Log.e("OkHttp", "response body:" + b);
            int maxStale = 60 * 60 * 24 * 28;
            response = new Response.Builder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .body(ResponseBody.create(MediaType.parse("application/json"), b.getBytes()))
                    .request(request)
                    .protocol(Protocol.HTTP_1_1)
                    .code(200)
                    .build();
        }
        return response;
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末让网,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子师痕,更是在濱河造成了極大的恐慌,老刑警劉巖而账,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胰坟,死亡現(xiàn)場離奇詭異,居然都是意外死亡泞辐,警方通過查閱死者的電腦和手機笔横,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咐吼,“玉大人吹缔,你說我怎么就攤上這事【馇眩” “怎么了厢塘?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肌幽。 經常有香客問我晚碾,道長,這世上最難降的妖魔是什么喂急? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任格嘁,我火速辦了婚禮,結果婚禮上廊移,老公的妹妹穿的比我還像新娘糕簿。我一直安慰自己,他們只是感情好狡孔,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布懂诗。 她就那樣靜靜地躺著,像睡著了一般步氏。 火紅的嫁衣襯著肌膚如雪响禽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天荚醒,我揣著相機與錄音芋类,去河邊找鬼。 笑死界阁,一個胖子當著我的面吹牛侯繁,可吹牛的內容都是我干的。 我是一名探鬼主播泡躯,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贮竟,長吁一口氣:“原來是場噩夢啊……” “哼丽焊!你這毒婦竟也來了?” 一聲冷哼從身側響起咕别,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤技健,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惰拱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雌贱,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年偿短,在試婚紗的時候發(fā)現(xiàn)自己被綠了欣孤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡昔逗,死狀恐怖降传,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情勾怒,我是刑警寧澤婆排,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站控硼,受9級特大地震影響泽论,放射性物質發(fā)生泄漏。R本人自食惡果不足惜卡乾,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一翼悴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幔妨,春花似錦鹦赎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锁施,卻和暖如春陪踩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悉抵。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工肩狂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姥饰。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓傻谁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親列粪。 傳聞我的和親對象是個殘疾皇子审磁,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谈飒,服務發(fā)現(xiàn),斷路器态蒂,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 緩存的一般思路 下面是我理解的網絡請求框架的緩存基本實現(xiàn)杭措。大致的過程是有緩存用緩存的數(shù)據,沒緩存發(fā)起http請求取...
    原件閱讀 2,808評論 3 12
  • 本文包括:1吃媒、Filter簡介2瓤介、Filter是如何實現(xiàn)攔截的?3赘那、Filter開發(fā)入門4、Filter的生命周期...
    廖少少閱讀 7,272評論 3 56
  • 前一篇文章(也是我在簡書上的第一篇技術文章.)講了Android三劍客的基礎用法和簡單封裝氯质,有一些封裝只是一筆帶過...
    小楓閱讀 14,262評論 9 82
  • 告訴你一個秘密: 一開始募舟,我根本沒有意識到“輸出”的重要性,但是闻察,當我踐行了之后拱礁,同時思考了之后,發(fā)現(xiàn)它是必不可少...
    丁昆朋閱讀 512評論 3 4