Retrofit2,okhttp3 通過攔截器進行快取
本文出自:http://blog.csdn.net/u010286855/article/details/52608485;
這篇部落格主要和大家說說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);
對於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();
- }
- };
- 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"> publicclass 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這樣的教學一大堆。大家可以去看看。