
首選說下個(gè)人覺得網(wǎng)絡(luò)緩存控制的優(yōu)勢(shì):
- 1.幫app端用戶減少流量消耗(因?yàn)楹芏嗲闆r下,請(qǐng)求網(wǎng)絡(luò)返回的response并沒有變化),同時(shí)提升用戶體驗(yàn),可以在沒有網(wǎng)絡(luò)的情況下也可以查看上次的數(shù)據(jù);
- 2.根據(jù)業(yè)務(wù)場景,設(shè)置不同的緩存時(shí)間,app端的用戶體驗(yàn)提高,穩(wěn)定性能提高;
- 3.通過減少很多不必要的http請(qǐng)求,減輕服務(wù)器負(fù)載,同時(shí)也可以減少服務(wù)端消耗的數(shù)據(jù)流量。
常用的緩存方式:
如果你的網(wǎng)路請(qǐng)求框架是Retrofit或OkHttpClient,那么只需要通過設(shè)置cache和Interceptor即可,cache的作用是指定緩存文件地址、大小,Interceptor稍微復(fù)雜一些,分為應(yīng)用攔截、網(wǎng)絡(luò)攔截兩種,主要控制緩存的時(shí)間、方式、過濾等。
具體通過代碼來講解:
if (retrofit == null) {
retrofit=new Retrofit.Builder().baseUrl("http://gank.io/api/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//偷個(gè)懶直接寫一起
.client(new OkHttpClient.Builder()
.cache(new Cache(new File(context.getExternalCacheDir(),"test_cache"),10 * 1024 * 1024))
.addInterceptor(new CaheInterceptor(context))
.addNetworkInterceptor(new CaheInterceptor(context))
.connectTimeout(5, TimeUnit.SECONDS)
.build())
.build();
}
上述代碼就為retrofit單例添加了緩存機(jī)制,最大緩存空間為10Mb,應(yīng)用攔截與網(wǎng)絡(luò)攔截也采用了同一個(gè)攔截器,簡單區(qū)別就是
addNetworkInterceptor添加的是網(wǎng)絡(luò)攔截器,他會(huì)在在request和resposne是分別被調(diào)用一次,
能夠操作中間過程的響應(yīng),如重定向和重試;
而addinterceptor添加的是aplication攔截器,他只會(huì)在response被調(diào)用一次,
且總是只調(diào)用一次,不需要擔(dān)心中間過程的響應(yīng)。
Interceptor的具體實(shí)現(xiàn)也很簡單,只需要重寫一個(gè)intercept方法,在其中處理多種緩存狀態(tài),例有網(wǎng)絡(luò),無網(wǎng)絡(luò),網(wǎng)絡(luò)狀態(tài)差等等。
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (NetworkUtils.isNetworkAvailable(context)) {
Response response = chain.proceed(request);
// read from cache for 0 s 有網(wǎng)絡(luò)不會(huì)使用緩存數(shù)據(jù)
int maxAge = 10;
String cacheControl = request.cacheControl().toString();
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
//無網(wǎng)絡(luò)時(shí)強(qiáng)制使用緩存數(shù)據(jù)
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
Response response = chain.proceed(request);
//set cahe times ; value is useless at all !
// int maxStale = 60;
int maxStale = 60 * 60 * 24 * 3;
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
上面的代碼僅根據(jù)當(dāng)前有無網(wǎng)絡(luò),對(duì)返回的數(shù)據(jù)response做了一個(gè)攔截處理,其中需要注意的是
- removeHeader();去除相關(guān)Cache-Control(緩存控制)的HTTP頭信息,不用去管,一般都是固定的格式;
- int maxAge = 10; 該值表示有網(wǎng)絡(luò)的時(shí)候,希望在10S內(nèi)不去重新獲取網(wǎng)絡(luò)數(shù)據(jù),而是直接使用緩存數(shù)據(jù);
- int maxStale = 60 * 60 * 24 * 3; 表示在無網(wǎng)絡(luò)的情況下,在3天內(nèi)使用緩存數(shù)據(jù)?但是在demo中實(shí)際調(diào)試發(fā)現(xiàn),該值并沒有什么軟用,即使你設(shè)置為0,無網(wǎng)絡(luò)時(shí)也會(huì)使用緩存數(shù)據(jù)。原因在這里:
//無網(wǎng)絡(luò)時(shí)強(qiáng)制使用緩存數(shù)據(jù)
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
追蹤C(jī)acheControl.FORCE_CACHE型的cacheControl源碼,發(fā)現(xiàn)其內(nèi)部,已經(jīng)將maxStale 設(shè)置為無限大了。
public static final CacheControl FORCE_CACHE = new Builder()
.onlyIfCached()
.maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS)
.build();
這樣,一個(gè)簡單的緩存方式就完成了,看下demo效果,當(dāng)我在10S內(nèi)去不停地獲取Gank.io中圖片時(shí),返回的一直是同一張,僅當(dāng)超過設(shè)置的maxAge時(shí)間后,picurl才更新了:
04-14 16:32:27.858 21905-21905/com.blink.dagger.democache D/luck: pic url :http://ww2.sinaimg.cn/large/7a8aed7bgw1ewees6m58qj20dw0kuadj.jpg
04-14 16:32:27.860 21905-21905/com.blink.dagger.democache D/luck: current time :2017-04-14 16:32:27
04-14 16:32:29.989 21905-21905/com.blink.dagger.democache D/luck: pic url :http://ww2.sinaimg.cn/large/7a8aed7bgw1ewees6m58qj20dw0kuadj.jpg
04-14 16:32:29.991 21905-21905/com.blink.dagger.democache D/luck: current time :2017-04-14 16:32:29
04-14 16:32:31.098 21905-21905/com.blink.dagger.democache D/luck: pic url :http://ww2.sinaimg.cn/large/7a8aed7bgw1ewees6m58qj20dw0kuadj.jpg
04-14 16:32:31.099 21905-21905/com.blink.dagger.democache D/luck: current time :2017-04-14 16:32:31
04-14 16:32:32.481 21905-21905/com.blink.dagger.democache D/luck: pic url :http://ww2.sinaimg.cn/large/7a8aed7bgw1ewees6m58qj20dw0kuadj.jpg
04-14 16:32:32.482 21905-21905/com.blink.dagger.democache D/luck: current time :2017-04-14 16:32:32
04-14 16:32:34.327 21905-21905/com.blink.dagger.democache D/luck: pic url :http://ww2.sinaimg.cn/large/7a8aed7bgw1ewees6m58qj20dw0kuadj.jpg
04-14 16:32:34.328 21905-21905/com.blink.dagger.democache D/luck: current time :2017-04-14 16:32:34
04-14 16:32:36.865 21905-21905/com.blink.dagger.democache D/luck: pic url :http://ww1.sinaimg.cn/large/7a8aed7bjw1ezf3wrxcx2j20p011i7b2.jpg
04-14 16:32:36.867 21905-21905/com.blink.dagger.democache D/luck: current time :2017-04-14 16:32:36
而我們的手機(jī)ExternalCacheDir路徑下,多了一些二進(jìn)制文件,所以如果需要做一個(gè)清除緩存的功能,在業(yè)務(wù)代碼中delete file即可。

Cookie緩存:
一般的場景應(yīng)該都用不到這種緩存方式,僅在每一次請(qǐng)求訪問網(wǎng)絡(luò)的時(shí)候,需要根據(jù)url將Cookie中的緩存數(shù)據(jù)提交給后臺(tái)時(shí)才用的著。
使用方法:
.cookieJar(new NovateCookieManger(context))
而且要實(shí)現(xiàn)CookieJar非常麻煩:
- 1.首選需要根據(jù)httpurl保存/發(fā)送Cookie(實(shí)現(xiàn)CookieJar接口);
- 2.將Map形式的cookies緩存至內(nèi)存中;
- 3.將cookies序列化后通過SP持久化至本地;
好在這種反人類的緩存方式一般不用。
Cookie難以被緩存,且大多情境下是沒有必要的。如果你非得使用Cookie,建議用在動(dòng)態(tài)頁面上。
具體的代碼太長了,這兒就不貼了,直接放在demo中了。