【快取策略】Retrofit+OkHttp實現快取處理
阿新 • • 發佈:2019-02-07
早先對於伺服器資料快取處理一般是本地SP或者Sqlite;現在網路請求改為Retrofit+OkHttp,OkHttp是有快取策略的,
今天我們就來說怎麼實現Retrofit與OkHttp的快取實現。
使用快取的目的
減少伺服器負荷,降低延遲提升使用者體驗。複雜的快取策略會根據使用者當前的網路情況採取不同的快取策略,比如在2g網路很差的情況下,提高快取使用的時間;不用的應用、業務需求、介面所需要的快取策略也會不一樣,需要資料的實時性,採用快取就是無意義!根據實際應用情況,制定自己的快取策略。Retrofit+OkHttp的快取機制
在響應請求之後在 data/data/<包名>/cache 下建立一個response 資料夾,保持快取資料。這樣我們就可以在請求的時候,如果判斷到沒有網路,自動讀取快取的資料。
同樣這也可以實現,在我們沒有網路的情況下,重新開啟App可以瀏覽的之前顯示過的內容。
也就是:判斷網路,有網路,則從網路獲取,並儲存到快取中,無網路,則從快取中獲取。
實現快取
1、開啟快取 這一步是設定快取路徑,以及快取大小<span style="font-size:14px;">File httpCacheDirectory = new File(context.getExternalCacheDir(), "responses");
//設定快取 10M
Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
client = new OkHttpClient.Builder().cache(cache).build();</span>
2、設定
OkHttp 攔截器兩個操作都是在 Interceptor 中進行的
- 通過 CacheControl 控制快取資料
CacheControl.Builder cacheBuilder = new CacheControl.Builder(); cacheBuilder.maxAge(0, TimeUnit.SECONDS);//多次訪問一個介面,<span style="white-space:pre"> </span>設定請求快取時間,超過時間重新請求,否則去快取 cacheBuilder.maxStale(365,TimeUnit.DAYS);//這個是控制快取的過時時間 CacheControl cacheControl = cacheBuilder.build();
- 設定攔截器
Request request = chain.request();
if(!StateUtils.isNetworkAvailable(MyApp.mContext)){
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
Response originalResponse = chain.proceed(request);
if (StateUtils.isNetworkAvailable(MyApp.mContext)) {
int maxAge = 60; // read from cache
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
.maxAge(0,TimeUnit.SECONDS)設定的時間比攔截器長是不起效果
設定比攔截器設定的時間短就會以這個時間為主,我覺得是為了方便控制。
maxStale(365, TimeUnit.DAYS)設定的是過時時間,okthhp快取分成了兩個來考慮,一個是為了請求時直接拿快取省流量,一個是為了下次進入應用時可以直接拿快取。
直接上程式碼
private HttpControl(final Context context) {
cookieStore = new PersistentCookieStore(context);
CookieHandler cookieHandler = new CookieManager(cookieStore,
CookiePolicy.ACCEPT_ALL);
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
/**
* 未聯網獲取快取資料
*/
if (!CheckHasNet.isNetWorkOk(context)) {
//在20秒快取有效,此處測試用,實際根據需求設定具體快取有效時間
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(30, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.d("MyTAG", "OkHttp: " + message);
}
});
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
File httpCacheDirectory = new File(context.getExternalCacheDir(), "responses");
//設定快取 10M
Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
//1.建立Retrofit物件
client = new OkHttpClient.Builder().addInterceptor(logging)
.addInterceptor(interceptor)//離線
.addNetworkInterceptor(provideCacheInterceptor())//線上
.cache(cache)
.readTimeout(30000, TimeUnit.MILLISECONDS)
.connectTimeout(30000, TimeUnit.MILLISECONDS)
.cookieJar(new JavaNetCookieJar(cookieHandler))
.build();
retrofit = new Retrofit.Builder().client(client).baseUrl(Constant.BASEURL)// 定義訪問的主機地址
.validateEagerly(true)
// .addConverterFactory(GsonConverterFactory.create())//解析方法 Gson
.addConverterFactory(JsonConverterFactory.create())//解析方法
// .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
public static Interceptor provideCacheInterceptor ()
{
return new Interceptor()
{
@Override
public Response intercept (Chain chain) throws IOException
{
Response response = chain.proceed( chain.request() );
// re-write response header to force use of cache
// 正常訪問同一請求介面(多次訪問同一介面),給30秒快取,超過時間重新發送請求,否則取快取資料
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(3, TimeUnit.SECONDS )
.build();
return response.newBuilder()
.header("Cache-Control", cacheControl.toString() )
.build();
}
};
}
public PersistentCookieStore getCookieStore() {
return cookieStore;
}
/**
* 單例模式
*
* @return
*/
public static HttpControl getInstance(Context context) {
if (instance == null) {
synchronized (HttpControl.class) {
if (instance == null) {
instance = new HttpControl(context);
}
}
}
return instance;
}
public OkHttpClient getClient() {
return client;
}
public void setClient(OkHttpClient client) {
this.client = client;
}
public <T> T create(final Class<T> service) {
return retrofit.create(service);
}
注意
1、快取是在每一次網路請求之後,重新儲存的,所以在超過快取過期時間後,Retrofit會在檢查到沒快取之後自動請求網路伺服器資料
2、快取資料也是需要網路下載的,所以在網路不好的情況下,可能不能立即快取
3、根據自身實際情況,制定快取策略