這篇部落客要和大家說說okhttp的緩存。之前踩了好多坑,反正看了很多文章做了很多試驗,發現網上的很多都不怎麼麼正确,我的疑問也一直沒有解決。今天這個這個是真實的自己寫的接口實作過的。是真的正确的也解決了我們需要的2種緩存的需求
我先說說我們為啥要緩存。1.處理高并發的問題:當我們的使用者量比較大的時候我們的伺服器 有時候可能受不了是以我們要把那些并不是經常更新和不是很重要的資訊緩存下來。我們隻需要去請求那些主要的資訊。還有就是有時候我們很無聊就是在app界面重新整理重新整理重新整理,這樣的話我們就可以不用把這個看成有效的請求。這時候我們就可以将緩存到本地的資料展示出來,這樣的話我們就不用給伺服器壓力了。
2。這個就是我麼沒有網絡的情況下要顯示的緩存。我們有的需求就是我們沒有網絡的時候我們要展示我們上次顯示的資訊。這樣的話我麼就要用到我們的緩存了。
這裡就說到了我們的兩種緩存:
一、無論有無網絡我們都去擷取緩存的資料(我們會設定一個緩存時間,在某一段時間内(例如60S)去擷取緩存資料。超過60S我們就去網絡重新請求資料)
二、有網絡的時候我們就去直接擷取網絡上面的資料。當沒有網絡的時候我們就去緩存擷取資料。
現在說一下基本的知識把,為我們的後面講的2種緩存打下最簡單的基礎。如果了解Retrofit,okhtt的朋友可以忽略這裡的資訊。
一、環境的搭建和內建
1.先內建okhttp和retrofit我就直接貼出來我的項目裡面的了。
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.okio:okio:1.6.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
這樣配置就可以了。
2.最簡單的使用我就不說了。直接調用了。
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)//連接配接失敗後是否重新連接配接
.connectTimeout(15, TimeUnit.SECONDS)//逾時時間15S
.build();
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(AppConstants.RequestPath.HOST)
.client(client)//設定okhttp
.addConverterFactory(GsonConverterFactory.create(new Gson()))//解析資料
.build();
server = retrofit.create(ApiServer.class);
那麼這裡就是我們最簡單的調用了有了server就很簡單了啦。直接調用Api裡面的自己編寫的接口。
對于okhtt+retrofit不會使用的大家可以去看看文章啊。這裡就過多講了啊。主要講緩存政策的問題。
說說緩存吧。
在trofit自己是不支援緩存的。要做緩存用的是okhttp的功能,主要利用的是攔截器。這裡一定要看清楚okhtt添加攔截器有兩種。看清楚啊,很多時候這樣的小的設定可能然我們浪費一天的時間的。有1.addInterceptor ,和2.addNetworkInterceptor這兩種。他們的差別簡單的說下,不知道也沒關系,addNetworkInterceptor添加的是網絡攔截器,他會在在request和resposne是分别被調用一次,addinterceptor添加的是aplication攔截器,他隻會在response被調用一次。這個如果不知道也沒有太多關系,不影響我們的這次操作,如果真的想要知道這些的話就去網上找找這個相關的一些東西看看,個人感覺還是比較重要的,但是如果這裡過多的将的話感覺沒有什麼意義。
一、無論有無網絡我們都先擷取緩存的資料。
1.先要建立攔截器。
/**
* 一、無論有無網路都添加緩存。
* 目前的情況是我們這個要addNetworkInterceptor
* 這樣才有效。經過本人測試(chan)測試有效.
* 60S後如果沒有網絡将擷取不到資料,顯示連接配接失敗
*/
static Interceptor netInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
/*String cacheControl = request.header("Cache-Control");
if (TextUtils.isEmpty(cacheControl)) {
cacheControl = "public, max-age=60";
}*/
int maxAge = 60;
return response.newBuilder()
.removeHeader("Pragma")// 清除頭資訊,因為伺服器如果不支援,會傳回一些幹擾資訊,不清除下面無法生效
.removeHeader("Cache-Control")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
}
};
2.這樣的話就寫好了攔截器,然後哦就是把攔截器設定到okhttp裡面
File cacheFile = new File(BaseApp.getInstance().getCacheDir(), "caheData");
//設定緩存大小
Cache cache = new Cache(cacheFile, DEFAULT_DIR_CACHE);//google建議放到這裡
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)//連接配接失敗後是否重新連接配接
.connectTimeout(15, TimeUnit.SECONDS)//逾時時間15S
.addNetworkInterceptor(cacheInterceptor)//這裡大家一定要注意了是addNetworkOnterceptor别搞錯了啊。
.cache(cache)
.build();
3.良心圖好了這樣的話第一種緩存政策就寫好了我測試下截圖發來,别說我吹逼的。
絕對良心截圖
我的操作了4次伺服器之列印了一次也就是我們在60S隻能無論我怎麼點選隻通路了一次資料。第一次是有網絡的時候我擷取了資料緩存了。第二次也是有網絡的時候我擷取的還是緩存的資料。第三次是我段網絡後的資料還是有擷取的緩存。第四次是我沒有網絡了,但是超過了設定的60S是以顯示連接配接伺服器失敗。這樣良心的截圖說明我想夠了吧。還有一點就算是有網絡超過了60S我們擷取的資料不就是緩存裡面的資料了。第一種緩存比較簡單也很好配置。
二、有網絡的時候我們擷取網絡的資料或者自己設定一定的緩存,沒有網絡的時候我們擷取緩存的資料。
1.所有的配置基本上一緻,唯一不同的就是我們的攔截器的設定,那麼我們的這種緩存的攔截器該怎麼寫呢。下面貼出來代碼。大家要是有不懂的可以留言我可以一句句給大家解答,我也寫了點注釋在上面
<pre name="code" class="java"> public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();//擷取請求
//這裡就是說判讀我們的網絡條件,要是有網絡的話我麼就直接擷取網絡上面的資料,要是沒有網絡的話我麼就去緩存裡面取資料
if(!NetworkUtils.isNetworkAvailable(BaseApp.getInstance().getApplicationContext())){
request = request.newBuilder()
//這個的話内容有點多啊,大家記住這麼寫就是隻從緩存取,想要了解這個東西我等下在
// 給大家寫連接配接吧。大家可以去看下,擷取大家去找攔截器資料的時候就可以看到這個方面的東西反正也就是緩存政策。
.cacheControl(CacheControl.FORCE_CACHE)
.build();
Log.d("CacheInterceptor","no network");
}
Response originalResponse = chain.proceed(request);
if(NetworkUtils.isNetworkAvailable(BaseApp.getInstance().getApplicationContext())){
//這裡大家看點開源碼看看.header .removeHeader做了什麼操作很簡答,就是的加字段和減字段的。
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
//這裡設定的為0就是說不進行緩存,我們也可以設定緩存時間
.header("Cache-Control", "public, max-age=" + 0)
.removeHeader("Pragma")
.build();
}else{
int maxTime = 4*24*60*60;
return originalResponse.newBuilder()
//這裡的設定的是我們的沒有網絡的緩存時間,想設定多少就是多少。
.header("Cache-Control", "public, only-if-cached, max-stale="+maxTime)
.removeHeader("Pragma")
.build();
}
}
}
</pre><pre>
</pre><p><span style="font-size:14px; color:rgb(51,51,51)"><span style="line-height:27.2px">2.設定Interceptor</span></span></p><p><span style="font-size:14px; color:rgb(51,51,51)"><span style="line-height:27.2px">這個大家注意了和之前設定的不同。也就一點點不同而已。我給出我的良心代碼吧,等下還有良心截圖。</span></span></p><p><span style="font-size:14px; color:#333333"><span style="line-height:27.2px"></span></span></p><pre name="code" class="java"> OkHttpClient.Builder builder = new OkHttpClient.Builder();
//設定緩存路徑
File cacheFile = new File(BaseApp.getInstance().getCacheDir(), "caheData");
//設定緩存大小
Cache cache = new Cache(cacheFile, DEFAULT_DIR_CACHE);
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)//連接配接失敗後是否重新連接配接
.connectTimeout(15, TimeUnit.SECONDS)//逾時時間15S
.addInterceptor(new CacheInterceptor())//也就這裡不同
.addNetworkInterceptor(new CacheInterceptor())//也就這裡不同
.cache(cache)
.build();
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(AppConstants.RequestPath.HOST)//baseURL提倡以“/”結尾
.client(client)//設定okhttp
.addConverterFactory(GsonConverterFactory.create(new Gson()))//解析資料
.build();
server = retrofit.create(ApiServer.class);
大家看看也就是添加攔截器的一點點地方不同。我良心截圖了。
我第一次操作是有網絡的時候很明顯是最新資料,第二次也是有網絡的時候我沒有設定緩存資料,這樣的話我伺服器又收到了相應,後面幾次都是沒有網絡的時候我的資料就是擷取的緩存的資料。
總結:好了良心之作寫完了。緩存的原理啥的網上一大堆我就不在這裡講了。有不知道的地方大家可以順藤摸瓜一步步找出來然後學習
http://www.oschina.net/news/41397/web-cache-knowledge 這個是緩存的。1.緩存原理2.攔截器3retrofit+okhttp+Rxjava這樣的教學一大堆。大家可以去看看。
ok就這樣吧,不懂的留言。
我的微信公衆号,更多幹活歡迎關注