編輯:關於Android編程
關於Retrofit+OkHttp的強大這裡就不多說了,還沒了解的同學可以自行去百度。這篇文章主要講如何利用Retrofit+OkHttp來實現一個較為簡單的緩存策略:
即有網環境下我們請求數據時,如果沒有緩存或者緩存過期了,就去服務器拿數據,並且將新緩存保存下來,如果有緩存而且沒有過期,則直接使用緩存。無網環境下我們請求數據時,緩存沒過期則直接使用緩存,緩存過期了則無法使用,需要重新聯網獲取服務器數據。
緩存處理還是很有必要的,它有效的減少服務器負荷,降低延遲提升用戶體驗,同時也方便用戶即使在沒網絡的情況下也能使用APP。
之前一直有一個疑惑,既然Retrofit已經是對OkHttp的一個封裝了,為什麼還一直說Retrofit+OkHttp要一起搭配使用,後來才知道其實OKHttp很重要的一個作用,就是對一些網絡請求的配置,例如連接超時,讀取超時,以及一些緩存配置等。
一、添加依賴
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(設置緩存路徑和緩存文件大小)
File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");//這裡為了方便直接把文件放在了SD卡根目錄的HttpCache中,一般放在context.getCacheDir()中
int cacheSize = 10 * 1024 * 1024;//設置緩存文件大小為10M
Cache cache = new Cache(httpCacheDirectory, cacheSize);
httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)//設置連接超時
.readTimeout(10, TimeUnit.SECONDS)//讀取超時
.writeTimeout(10, TimeUnit.SECONDS)//寫入超時
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加自定義緩存攔截器(後面講解),注意這裡需要使用.addNetworkInterceptor
.cache(cache)//把緩存添加進來
.build();
三、配置Retrofit
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(httpClient)//把OkHttpClient添加進來
.addConverterFactory(GsonConverterFactory.create())
.build();
四、編寫攔截器
我們知道其實Retrofit+OkHttp的緩存主要通過攔截器實現,所以主要做的功夫也在攔截器裡面。
static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//網上很多示例代碼都對在request請求前對其進行無網的判斷,其實無需判斷,無網自動訪問緩存
// if(!NetworkUtil.getInstance().isConnected()){
// request = request.newBuilder()
// .cacheControl(CacheControl.FORCE_CACHE)//只訪問緩存
// .build();
// }
Response response = chain.proceed(request);
if (NetworkUtil.getInstance().isConnected()) {
int maxAge = 60;//緩存失效時間,單位為秒
return response.newBuilder()
.removeHeader("Pragma")//清除頭信息,因為服務器如果不支持,會返回一些干擾信息,不清除下面無法生效
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
} else {
//這段代碼設置無效
// int maxStale = 60 * 60 * 24 * 28; // 無網絡時,設置超時為4周
// return response.newBuilder()
// .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
// .removeHeader("Pragma")
// .build();
}
return response;
}
};
到這裡,其實已經可以實現了我們開頭所說的緩存效果了。
但是,上面設置的每個接口緩存時間都一樣,例如我現在想讓不同接口的緩存數據失效時間都不一樣,甚至有些接口不緩存數據,應該怎麼做呢?其實也很簡單
首先我們只需要在接口前面添加@Headers參數(max-age代表緩存時間,單位為秒,示例中表示緩存失效時間為60s,想要多少時間可以自行設置),不設置@Headers參數則不進行緩存。
@Headers("Cache-Control:public ,max-age=60")
@GET("getBusiness.action")//商店信息
Call<RestaurantInfoModel> getRestaurantInfo(@Query("userId") String userId,@Query("businessId") String businessId);
同時,我們的緩存攔截器也要做下簡單的修改(去掉了之前的注釋代碼)
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")//清除頭信息,因為服務器如果不支持,會返回一些干擾信息,不清除下面無法生效
.header("Cache-Control", cacheControl)
.build();
}
return response;
}
};
*注意:
1.只能緩存Get請求的接口,不能緩存Post請求的接口
2.OkHttpClient需要用.addNetworkInterceptor添加緩存攔截器,不能使用.addInterceptor,也無需兩者同時使用。
3.此方法無需服務器端任何操作,適用於服務器端沒有其他緩存策略,如果服務器端有自己的緩存策略代碼應該做相應的修改,以適應服務器端。
附上所有代碼:
/**
* 簡單封裝的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)//設置連接超時
.readTimeout(10, TimeUnit.SECONDS)//讀取超時
.writeTimeout(10, TimeUnit.SECONDS)//寫入超時
.addInterceptor(interceptor)//添加日志攔截器
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加緩存攔截器
.cache(cache)//把緩存添加進來
.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")//清除頭信息,因為服務器如果不支持,會返回一些干擾信息,不清除下面無法生效
// .header("Cache-Control", cacheControl)
// .build();
// }
// return response;
// }
// };
//緩存攔截器,統一緩存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;//緩存失效時間,單位為秒
return response.newBuilder()
.removeHeader("Pragma")//清除頭信息,因為服務器如果不支持,會返回一些干擾信息,不清除下面無法生效
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
}
return response;
}
};
}
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
Android基礎知識(1)——UI編程
我學習android一段時間了,看著大牛們的各種神博客,心裡也癢癢的,希望有一天也能成為他們一樣。我知道,這些都是一滴一滴的積累,所有我也需要找到我的學習方法,打好基礎,
Android注解-編譯時生成代碼 (APT)
Android注解越來越引領潮流,比如 Dagger2, ButterKnife, EventBus3 等,他們都是注解類型,而且他們都有個共同點就是編譯時生成代碼,而不
Android基礎入門教程——10.2 SmsManager(短信管理器)
本節引言: 本節帶來的是Android中的SmsManager(短息管理器),見名知意,就是用來管理手機短信的, 而該類的應用場景並不多,一般是我
簡單實現Android驗證碼
安卓驗證碼的簡單實現我們經常在登錄或者注冊的時候要求輸入驗證碼,這裡簡單介紹一下一種方法 效果如下首先是要獲取 隨機的四個字母組合,我這裡是將26個字母存儲到一個數組中,