關(guān)于Okhttp緩存

Okhttp的緩存策略有如下幾種:

boolean noCache;//等于FORCE_NETWORK颖侄,不使用緩存
boolean noStore;//不緩存衣屏,不存儲(chǔ)
int maxAgeSeconds = -1;//緩存的有效時(shí)間
int maxStaleSeconds = -1;//緩存的延長有效時(shí)間
int minFreshSeconds = -1;//增加額外的緩存的有效時(shí)間,在stale前計(jì)算
boolean onlyIfCached;//等于FORCE_CACHE溯革,有緩存就用緩存
boolean noTransform;//不接受經(jīng)過轉(zhuǎn)碼的響應(yīng)
boolean immutable;//緩存有效時(shí)間內(nèi),響應(yīng)不會(huì)變化谷醉,避免服務(wù)器處理304響應(yīng)

如果這些緩存策略可以滿足需求致稀,那就不用再往下看了,相關(guān)的文章有很多

如果需要有網(wǎng)絡(luò)用網(wǎng)絡(luò)俱尼,無網(wǎng)絡(luò)(網(wǎng)絡(luò)請求失敹兜ァ)時(shí)使用緩存,或其他自定義策略,可以參考下面的方法

首先需要明確幾個(gè)要求
1.使用攔截器來實(shí)現(xiàn)矛绘,改動(dòng)小耍休,作用全局
2.方便控制每個(gè)接口是否緩存
3.接口參數(shù)有改動(dòng)時(shí)也能命中緩存

實(shí)現(xiàn)

一.存取

理想的情況下最好是將整個(gè)Response都存儲(chǔ)起來,但是看一眼源代碼

public final class Response implements Closeable

public interface Closeable extends AutoCloseable
 
public interface AutoCloseable

整個(gè)繼承和實(shí)現(xiàn)的鏈條里跟序列化沒有一毛錢關(guān)系货矮,并且是不能被繼承的final class
\color{red}{------所以羊精,如果是在內(nèi)存中臨時(shí)緩存,可以保存整個(gè)Response囚玫,持久化保存就別想了}

那既然不能保存Response喧锦,是否可以自己組裝一個(gè),答案是肯定的

Response通過Builder方式創(chuàng)建抓督,這個(gè)Builder也是public的可以調(diào)用到

public Builder() {
  headers = new Headers.Builder();
}

那組裝時(shí)需要哪些參數(shù)呢燃少,點(diǎn)一下試試

Response的參數(shù)們

emmm...有點(diǎn)多,以后再詳細(xì)說明這些參數(shù)本昏,先偷個(gè)懶供汛,可以先看一下哪里用到了這個(gè)Builder


image.png

這里有okhttp自己實(shí)現(xiàn)的緩存攔截器,進(jìn)去看看

return new Response.Builder()
    .request(chain.request())//原始請求涌穆,這個(gè)在攔截器中可以直接拿到
    .protocol(Protocol.HTTP_1_1)//協(xié)議怔昨,直接填就行
    .code(504)//code碼,可以直接填200
    .message("Unsatisfiable Request (only-if-cached)")//可以隨便寫宿稀,我這里寫得“use cache”便于以后統(tǒng)計(jì)
    .body(Util.EMPTY_RESPONSE)//數(shù)據(jù)內(nèi)容*
    .sentRequestAtMillis(-1L)//請求時(shí)間
    .receivedResponseAtMillis(System.currentTimeMillis())//返回時(shí)間
    .build();

這里有一個(gè)現(xiàn)成的例子

上面代碼中的*位置就是數(shù)據(jù)內(nèi)容保存的地方趁舀,這里需要添加一個(gè)ResponseBody類型的參數(shù),好在該類中有方便創(chuàng)建對象的方法

public static ResponseBody create(@Nullable MediaType contentType, String content)

這個(gè)方法有兩個(gè)參數(shù)祝沸,第一個(gè)是內(nèi)容類型矮烹,這個(gè)類中也有方便的方法

public static @Nullable MediaType parse(String string)//在一般返回的請求中直接使用MediaType.parse("application/json; charset=UTF-8")即可

第二個(gè)參數(shù)就是內(nèi)容主體了,就是服務(wù)端返回的數(shù)據(jù)內(nèi)容

構(gòu)造Response現(xiàn)在已經(jīng)清楚了罩锐,那現(xiàn)在就可以在保存緩存時(shí)只進(jìn)行數(shù)據(jù)內(nèi)容的保存即可奉狈,那應(yīng)該如何保存呢

這里可以使用下面的代碼獲取到body中的數(shù)據(jù)并轉(zhuǎn)為string類型

response.peekBody(Long.MAX_VALUE).string()

然后拿到這個(gè)數(shù)據(jù)可以用自己喜歡的方式進(jìn)行持久化保存

簡單使用可以用HashTable進(jìn)行<Url,data>鍵值對保存,然后將其這個(gè)map整個(gè)寫入到一個(gè)文件中涩惑,在使用時(shí)再整個(gè)讀取出來仁期,方便使用(或者使用xml,json等格式化數(shù)據(jù))竭恬,ps:為了安全起見只應(yīng)該保存Get方法的數(shù)據(jù)跛蛋,最好使用數(shù)據(jù)庫進(jìn)行持久化存儲(chǔ)

這里需要注意如果使用HashMap可能會(huì)出現(xiàn)java.util.ConcurrentModificationException異常

二.根據(jù)接口選擇是否緩存

這里的方法就很多了,說一個(gè)比較簡單的

可以在請求時(shí)添加一個(gè)臨時(shí)header痊硕,然后再攔截器中讀取這個(gè)header進(jìn)行辨認(rèn)并將這個(gè)header刪除(以免對請求產(chǎn)生不必要的影響)

如果使用retrofit進(jìn)行網(wǎng)絡(luò)請求赊级,這種方式在Retrofit中使用多個(gè)baseUrl有詳細(xì)說明

三.網(wǎng)絡(luò)請求失敗時(shí)命中緩存

這里只需要對攔截器中請求得部分進(jìn)行try-catch即可,在網(wǎng)絡(luò)請求失敗時(shí)okhttp會(huì)拋錯(cuò)岔绸,這時(shí)再catch塊中進(jìn)行緩存的返回即可

需要注意的是下面的集中情況需要過濾理逊,這是主動(dòng)打斷請求時(shí)會(huì)拋出的錯(cuò)誤

e.toString().contains("Canceled")
e.toString().contains("InterruptedIOException")
e.toString().contains("CANCEL")

四.在請求參數(shù)改變時(shí)仍然命中(忽略某些參數(shù))

這里需要對請求參數(shù)的改變有把握橡伞,比如net_type在使用移動(dòng)網(wǎng)絡(luò)的情況下應(yīng)該可以命中wifi時(shí)緩存的數(shù)據(jù)

其實(shí)沒啥可說的,將請求中的參數(shù)通過字符串分割的方式去掉其中的某些參數(shù)即可挡鞍,需要注意的是保存和獲取前的對比都需要去掉這些參數(shù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骑歹,一起剝皮案震驚了整個(gè)濱河市预烙,隨后出現(xiàn)的幾起案子墨微,更是在濱河造成了極大的恐慌,老刑警劉巖扁掸,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翘县,死亡現(xiàn)場離奇詭異,居然都是意外死亡谴分,警方通過查閱死者的電腦和手機(jī)锈麸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牺蹄,“玉大人忘伞,你說我怎么就攤上這事∩忱迹” “怎么了氓奈?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鼎天。 經(jīng)常有香客問我舀奶,道長,這世上最難降的妖魔是什么斋射? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任育勺,我火速辦了婚禮,結(jié)果婚禮上罗岖,老公的妹妹穿的比我還像新娘涧至。我一直安慰自己,他們只是感情好桑包,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布南蓬。 她就那樣靜靜地躺著,像睡著了一般捡多。 火紅的嫁衣襯著肌膚如雪蓖康。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天垒手,我揣著相機(jī)與錄音蒜焊,去河邊找鬼。 笑死科贬,一個(gè)胖子當(dāng)著我的面吹牛泳梆,可吹牛的內(nèi)容都是我干的鳖悠。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼优妙,長吁一口氣:“原來是場噩夢啊……” “哼乘综!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起套硼,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對情侶失蹤卡辰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后邪意,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體九妈,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年雾鬼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了萌朱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡策菜,死狀恐怖晶疼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情又憨,我是刑警寧澤翠霍,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站竟块,受9級(jí)特大地震影響壶运,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浪秘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一蒋情、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耸携,春花似錦棵癣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沟沙,卻和暖如春河劝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矛紫。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工赎瞎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颊咬。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓务甥,卻偏偏與公主長得像牡辽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子敞临,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350