關於okhttp的緩存,網上有大量的文章,或相同,或不一樣,方式不一,但都八九不離十,原理都是經過CacheControl的設置策略不一樣來實現的。 可是,真正實踐過的人會發現,好像有這樣那樣的問題。 好比:html
簡直不明白。 因而乎,我我的作了不少不少的嘗試,幾乎把網上的方法都試了一遍,看了大量換湯不換藥的文章。下面是借鑑文章出處,可是個人方法都與他們的不一樣。android
blog.csdn.net/u014614038/… blog.csdn.net/Picasso_L/a… blog.csdn.net/briblue/art… www.jianshu.com/p/412157e23… stackoverflow.com/questions/2… newfivefour.com/android-ret…數據庫
一、有網的時候也能夠讀取緩存,而且能夠控制緩存的過時時間,這樣能夠減輕服務器壓力 二、有網的時候不讀取緩存,好比一些及時性較高的接口請求 三、無網的時候讀取緩存,而且能夠控制緩存過時的時間緩存
說了那麼多,先直接上解決方案bash
/**
* 有網時候的緩存
*/
final Interceptor NetCacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
int onlineCacheTime = 30;//在線的時候的緩存過時時間,若是想要不緩存,直接時間設置爲0
return response.newBuilder()
.header("Cache-Control", "public, max-age="+onlineCacheTime)
.removeHeader("Pragma")
.build();
}
};
/**
* 沒有網時候的緩存
*/
final Interceptor OfflineCacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!SystemTool.checkNet(AppContext.context)) {
int offlineCacheTime = 60;//離線的時候的緩存的過時時間
request = request.newBuilder()
// .cacheControl(new CacheControl
// .Builder()
// .maxStale(60,TimeUnit.SECONDS)
// .onlyIfCached()
// .build()
// ) 兩種方式結果是同樣的,寫法不一樣
.header("Cache-Control", "public, only-if-cached, max-stale=" + offlineCacheTime)
.build();
}
return chain.proceed(request);
}
};
//setup cache
File httpCacheDirectory = new File(AppContext.context.getCacheDir(), "okhttpCache");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(NetCacheInterceptor)
.addInterceptor(OfflineCacheInterceptor)
.cache(cache)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
複製代碼
沒錯最終的解決方案就是,兩個interceptor,而且針對不一樣的網絡狀況進行不一樣的處理。(爲何是兩個interceptor後面會講到)服務器
若是趕時間的朋友,能夠直接拿去用,看到這裏就好了。若是以爲用起來就問題,歡迎下面留言。網絡
首先我最初的寫法就是來源於網上大多數人的寫法,相似ide
public class HttpCacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetWorkHelper.isNetConnected(MainApplication.getContext())) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (NetWorkHelper.isNetConnected(MainApplication.getContext())) {
int maxAge = 60 * 60; // read from cache for 1 minute
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
return response;
}
}
//設置緩存100M
Cache cache = new Cache(new File(MainApplication.getContext().getCacheDir(),"httpCache"),1024 * 1024 * 100);
return new OkHttpClient.Builder()
.cache(cache)
.addNetworkInterceptor(new HttpCacheInterceptor())
.build();
複製代碼
這段代碼知足不了個人需求,而且會發現,有些狀況離線的時候緩存過時的時間不可靠,有些狀況在線的時候緩存不可用。對於個人需求不可兼得。(故網上有人還分了2種不一樣狀況的寫法來針對不一樣的需求,但我想,爲何不綜合起來呢?)測試
對於這段代碼疑惑點: 一、max-age是啥,maxStale是啥,他們的區別是啥? 二、爲何沒有網絡的狀況下,request要cacheControl.FORCE_CACHE 三、爲何又要對response設置header的cache-control,到底request的設置跟response的設置有什麼區別? 四、addNetInterceptor和addInterceptor有什麼區別?ui
解答: 一、max-age是啥,maxStale是啥,他們的區別是啥?
maxAge和maxStale的區別在於: maxAge:沒有超出maxAge,無論怎麼樣都是返回緩存數據,超過了maxAge,發起新的請求獲取數據更新,請求失敗返回緩存數據。 maxStale:沒有超過maxStale,無論怎麼樣都返回緩存數據,超過了maxStale,發起請求獲取更新數據,請求失敗返回失敗
二、爲何沒有網絡的狀況下,request要cacheControl.FORCE_CACHE
public static final CacheControl FORCE_CACHE = new Builder() .onlyIfCached() .maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS) .build(); 能夠看到FORCE_CACHE是設置了maxStale的最大時間爲interger的最大時間,因此,意思就是不管如何,都不會超過這個時間,因此就是一直(強制)拿緩存,也是想要實現緩存的正確邏輯
通常控制緩存有兩種方式: 一、在request裏面去設置cacheControl()策略 二、在header裏面去添加cache-control
後面也會看到,在request裏面設置header的cache-control和調用cacheControl方法來設置實際上是同樣的,咱們就是經過在request裏面來控制無網緩存的maxStale過時時間的
三、爲何又要對response設置header的cache-control,到底request的設置跟response的設置有什麼區別?
其實我到如今都尚未搞清楚,爲啥那些人要這樣寫,只是後面我在測試的過程當中推斷出來,有網的時候和無網的時候對於interceptor的調用是不一樣的,產生的結果也是不一樣的。好比request設置的時候就對無網緩存及其時間控制有效,response就不行
四、addNetInterceptor和addInterceptor有什麼區別?
addNetInterceptor是添加網絡攔截器,addInterceptor是添加應用攔截器,若是看到okhttp的流程分析的知道:應用攔截器是在網絡攔截器前執行的。
若是我使用的是addNetInterceptor: 一、有網的狀況下,能夠在期限內拿到緩存,而沒有去請求接口(經過測試數據庫的數據改動來判斷的) 二、沒有網的狀況下,直接就ConnectException了,根本不會走到interceptor裏面去了。(網上不少人都提出了這樣的問題)
若是我使用的是addInterceptor: 一、有網的狀況下,明明設置的是60秒,可是每次都沒有去拿緩存而都是請求的接口。(經過測試數據庫的數據改動來判斷的) 二、沒有網的狀況下,能夠拿到緩存數據(猜測:多是由於應用攔截器在網絡攔截器前執行,沒有網的狀況下,自己就執行不到網絡攔截器裏面去),可是緩存過時時間是「永久」,由於FORCE_CACHE裏面已經設置爲了integer的最大值,21億秒左右,堪稱永久 可是,依舊沒有辦法控制無網時候的緩存過時時間
面對這些個問題,我也是很無奈。只得不停地嘗試,不停地摸索。因而就在嘗試的過程當中發現了它的一些規則,因而最終寫出了一個自認爲「萬全」的方法。
若是無網的時候,stale緩存時間過了,會怎麼樣呢? 會報504錯誤(屬於正常的邏輯)。
歡迎留言,歡迎提問題、交流。