okhttp3.4.1+retrofit2.1.0實(shí)現(xiàn)離線緩存的示例
關(guān)于Retrofit+OkHttp的強(qiáng)大這里就不多說了,還沒了解的同學(xué)可以自行去百度。這篇文章主要講如何利用Retrofit+OkHttp來實(shí)現(xiàn)一個(gè)較為簡單的緩存策略:
即有網(wǎng)環(huán)境下我們請求數(shù)據(jù)時(shí),如果沒有緩存或者緩存過期了,就去服務(wù)器拿數(shù)據(jù),并且將新緩存保存下來,如果有緩存而且沒有過期,則直接使用緩存。無網(wǎng)環(huán)境下我們請求數(shù)據(jù)時(shí),緩存沒過期則直接使用緩存,緩存過期了則無法使用,需要重新聯(lián)網(wǎng)獲取服務(wù)器數(shù)據(jù)。
緩存處理還是很有必要的,它有效的減少服務(wù)器負(fù)荷,降低延遲提升用戶體驗(yàn),同時(shí)也方便用戶即使在沒網(wǎng)絡(luò)的情況下也能使用APP。
之前一直有一個(gè)疑惑,既然Retrofit已經(jīng)是對OkHttp的一個(gè)封裝了,為什么還一直說Retrofit+OkHttp要一起搭配使用,后來才知道其實(shí)OKHttp很重要的一個(gè)作用,就是對一些網(wǎng)絡(luò)請求的配置,例如連接超時(shí),讀取超時(shí),以及一些緩存配置等。
一、添加依賴
compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.okhttp3:okhttp:3.4.1' compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
二、配置OkHttpClient(設(shè)置緩存路徑和緩存文件大?。?/strong>
File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");//這里為了方便直接把文件放在了SD卡根目錄的HttpCache中,一般放在context.getCacheDir()中
int cacheSize = 10 * 1024 * 1024;//設(shè)置緩存文件大小為10M
Cache cache = new Cache(httpCacheDirectory, cacheSize);
httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)//設(shè)置連接超時(shí)
.readTimeout(10, TimeUnit.SECONDS)//讀取超時(shí)
.writeTimeout(10, TimeUnit.SECONDS)//寫入超時(shí)
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加自定義緩存攔截器(后面講解),注意這里需要使用.addNetworkInterceptor
.cache(cache)//把緩存添加進(jìn)來
.build();
三、配置Retrofit
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(httpClient)//把OkHttpClient添加進(jìn)來
.addConverterFactory(GsonConverterFactory.create())
.build();
四、編寫攔截器
我們知道其實(shí)Retrofit+OkHttp的緩存主要通過攔截器實(shí)現(xiàn),所以主要做的功夫也在攔截器里面。
static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//網(wǎng)上很多示例代碼都對在request請求前對其進(jìn)行無網(wǎng)的判斷,其實(shí)無需判斷,無網(wǎng)自動(dòng)訪問緩存
// if(!NetworkUtil.getInstance().isConnected()){
// request = request.newBuilder()
// .cacheControl(CacheControl.FORCE_CACHE)//只訪問緩存
// .build();
// }
Response response = chain.proceed(request);
if (NetworkUtil.getInstance().isConnected()) {
int maxAge = 60;//緩存失效時(shí)間,單位為秒
return response.newBuilder()
.removeHeader("Pragma")//清除頭信息,因?yàn)榉?wù)器如果不支持,會(huì)返回一些干擾信息,不清除下面無法生效
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
} else {
//這段代碼設(shè)置無效
// int maxStale = 60 * 60 * 24 * 28; // 無網(wǎng)絡(luò)時(shí),設(shè)置超時(shí)為4周
// return response.newBuilder()
// .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
// .removeHeader("Pragma")
// .build();
}
return response;
}
};
到這里,其實(shí)已經(jīng)可以實(shí)現(xiàn)了我們開頭所說的緩存效果了。
但是,上面設(shè)置的每個(gè)接口緩存時(shí)間都一樣,例如我現(xiàn)在想讓不同接口的緩存數(shù)據(jù)失效時(shí)間都不一樣,甚至有些接口不緩存數(shù)據(jù),應(yīng)該怎么做呢?其實(shí)也很簡單
首先我們只需要在接口前面添加@Headers參數(shù)(max-age代表緩存時(shí)間,單位為秒,示例中表示緩存失效時(shí)間為60s,想要多少時(shí)間可以自行設(shè)置),不設(shè)置@Headers參數(shù)則不進(jìn)行緩存。
@Headers("Cache-Control:public ,max-age=60")
@GET("getBusiness.action")//商店信息
Call<RestaurantInfoModel> getRestaurantInfo(@Query("userId") String userId,@Query("businessId") String businessId);
同時(shí),我們的緩存攔截器也要做下簡單的修改(去掉了之前的注釋代碼)
static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if (NetworkUtil.getInstance().isConnected()) {
//獲取頭部信息
String cacheControl =request.cacheControl().toString();
return response.newBuilder()
.removeHeader("Pragma")//清除頭信息,因?yàn)榉?wù)器如果不支持,會(huì)返回一些干擾信息,不清除下面無法生效
.header("Cache-Control", cacheControl)
.build();
}
return response;
}
};
*注意:
1.只能緩存Get請求的接口,不能緩存Post請求的接口
2.OkHttpClient需要用.addNetworkInterceptor添加緩存攔截器,不能使用.addInterceptor,也無需兩者同時(shí)使用。
3.此方法無需服務(wù)器端任何操作,適用于服務(wù)器端沒有其他緩存策略,如果服務(wù)器端有自己的緩存策略代碼應(yīng)該做相應(yīng)的修改,以適應(yīng)服務(wù)器端。
附上所有代碼:
/**
* 簡單封裝的Retroit初始化類
*/
public class initRetrofit {
private static String baseUrl = "http://202.171.212.154:8080/hh/";
private static OkHttpClient httpClient;
private static Retrofit retrofit;
public static Retrofit initRetrofit() {
//緩存路徑和大小
File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(httpCacheDirectory, cacheSize);
//日志攔截器
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)//設(shè)置連接超時(shí)
.readTimeout(10, TimeUnit.SECONDS)//讀取超時(shí)
.writeTimeout(10, TimeUnit.SECONDS)//寫入超時(shí)
.addInterceptor(interceptor)//添加日志攔截器
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加緩存攔截器
.cache(cache)//把緩存添加進(jìn)來
.build();
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
public static RetrofitAPI getService() {
return initRetrofit().create(RetrofitAPI.class);
}
// //緩存攔截器,不同接口不同緩存
// static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
// @Override
// public Response intercept(Chain chain) throws IOException {
//
// Request request = chain.request();
// Response response = chain.proceed(request);
//
// if (NetworkUtil.getInstance().isConnected()) {
// String cacheControl =request.cacheControl().toString();
// return response.newBuilder()
// .removeHeader("Pragma")//清除頭信息,因?yàn)榉?wù)器如果不支持,會(huì)返回一些干擾信息,不清除下面無法生效
// .header("Cache-Control", cacheControl)
// .build();
// }
// return response;
// }
// };
//緩存攔截器,統(tǒng)一緩存60s
static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if (NetworkUtil.getInstance().isConnected()) {
int maxAge = 60*60*24*2;//緩存失效時(shí)間,單位為秒
return response.newBuilder()
.removeHeader("Pragma")//清除頭信息,因?yàn)榉?wù)器如果不支持,會(huì)返回一些干擾信息,不清除下面無法生效
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
}
return response;
}
};
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Retrofit之OKHttpCall源碼分析
- Okhttp、Retrofit進(jìn)度獲取的方法(一行代碼搞定)
- Android 封裝Okhttp+Retrofit+RxJava,外加攔截器實(shí)例
- OKHttp3(支持Retrofit)的網(wǎng)絡(luò)數(shù)據(jù)緩存Interceptor攔截器的實(shí)現(xiàn)
- RxJava+Retrofit+OkHttp實(shí)現(xiàn)多文件下載之?dāng)帱c(diǎn)續(xù)傳
- RxJava+Retrofit+OkHttp實(shí)現(xiàn)文件上傳
- 深入淺出RxJava+Retrofit+OkHttp網(wǎng)絡(luò)請求
- 淺談RxJava+Retrofit+OkHttp 封裝使用
- Android中Retrofit+OkHttp進(jìn)行HTTP網(wǎng)絡(luò)編程的使用指南
- Retrofit和OkHttp如何實(shí)現(xiàn)Android網(wǎng)絡(luò)緩存
相關(guān)文章
Android App中使用Gallery制作幻燈片播放效果
這篇文章主要介紹了Android App中使用Gallery制作幻燈片播放效果,相冊應(yīng)用中的輪播功能也與本文中例子的原理類似,需要的朋友可以參考下2016-04-04
使用ViewPager實(shí)現(xiàn)android軟件使用向?qū)Чδ軐?shí)現(xiàn)步驟
現(xiàn)在的大部分android軟件,都是使用說明,就是第一次使用該軟件時(shí),會(huì)出現(xiàn)向?qū)В梢宰笥一瑒?dòng),然后就進(jìn)入應(yīng)用的主界面了,下面我們就實(shí)現(xiàn)這個(gè)功能2013-11-11
Android中實(shí)現(xiàn)ping功能的多種方法詳解
這篇文章主要介紹了Android中實(shí)現(xiàn)ping功能的多種方法詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Android開發(fā)實(shí)現(xiàn)拍照功能的方法實(shí)例解析
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)拍照功能的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android拍照功能的具體實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Android自定義View onDraw()方法會(huì)調(diào)用兩次的問題解決
這篇文章主要介紹了Android自定義View onDraw()方法會(huì)調(diào)用兩次的問題解決,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
Android客制化adb shell進(jìn)去后顯示shell@xxx的標(biāo)識
今天小編就為大家分享一篇關(guān)于Android客制化adb shell進(jìn)去后顯示shell@xxx的標(biāo)識,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
Android控件WebView實(shí)現(xiàn)完整截圖
這篇文章主要為大家詳細(xì)介紹了Android控件WebView實(shí)現(xiàn)完整截圖,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05

