Android OKHttp3攔截器的使用方法
本文介紹了Android OKHttp3攔截器的使用方法,分享給大家,具體如下:
添加Interceptor
在上一篇中我們已經(jīng)知道了okhttp的基本使用,其中在介紹OkHttpClient初始化的時候,介紹了兩種方式,第二種方式就可以對這個OkHttpClient對象設(shè)置攔截器,如下所示:
// 配置一些信息進入OkHttpClient mOkHttpClient = new OkHttpClient().newBuilder() .connectTimeout(REQUEST_TIME, TimeUnit.SECONDS) .readTimeout(REQUEST_TIME, TimeUnit.SECONDS) .writeTimeout(REQUEST_TIME, TimeUnit.SECONDS) .addInterceptor(new LoggerInterceptor()) .build();
如上代碼,很簡單,只要利用addInterceptor方法就可以添加攔截器,而自定義的攔截器只需要實現(xiàn) Interceptor 接口就行了,如下所示:
public class LoggerInterceptor implements Interceptor { ... }
應(yīng)用場景
日志打印
可以使用攔截器方便的打印網(wǎng)絡(luò)請求時,需要查看的日志。如下所示:
public class LoggerInterceptor implements Interceptor { @Override public Response intercept(@NonNull Chain chain) throws IOException { // 攔截請求,獲取到該次請求的request Request request = chain.request(); // 執(zhí)行本次網(wǎng)絡(luò)請求操作,返回response信息 Response response = chain.proceed(request); if (Configuration.DEBUG) { for (String key : request.headers().toMultimap().keySet()) { LogUtil.e("zp_test", "header: {" + key + " : " + request.headers().toMultimap().get(key) + "}"); } LogUtil.e("zp_test", "url: " + request.url().uri().toString()); ResponseBody responseBody = response.body(); if (HttpHeaders.hasBody(response) && responseBody != null) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseBody.byteStream(), "utf-8")); String result; while ((result = bufferedReader.readLine()) != null) { LogUtil.e("zp_test", "response: " + result); } // 測試代碼 responseBody.string(); } } // 注意,這樣寫,等于重新創(chuàng)建Request,獲取新的Response,避免在執(zhí)行以上代碼時, // 調(diào)用了responseBody.string()而不能在返回體中再次調(diào)用。 return response.newBuilder().build(); } }
做了一個打印驗證:通過分別打印攔截器與返回體的時間和線程名字,可以知道這兩者處于同一線程中,增加攔截器,請求執(zhí)行的時間也會增加,所以猜測,其實就是線性的在執(zhí)行不同攔截器中的代碼,根據(jù)需求返回一個相同的或者新的response。
緩存
想要實現(xiàn)緩存,先在創(chuàng)建okhttpclint的時候多加一行代碼 .cache() ,通過它來設(shè)置緩存目錄,當然需要服務(wù)器支持緩存功能。
mOkHttpClient = new OkHttpClient().newBuilder() .cache(new Cache(FileUtils.getCacheDirectory(AppApplication .getApplication(), ""), 1024 * 1024)) .connectTimeout(REQUEST_TIME, TimeUnit.SECONDS) .readTimeout(REQUEST_TIME, TimeUnit.SECONDS) .writeTimeout(REQUEST_TIME, TimeUnit.SECONDS) .addNetworkInterceptor(new LoggerInterceptor()) .build();
如果服務(wù)器端支持緩存的話,則請求所返回的Response會帶有這樣的頭信息header:cache-control, max-age=xxx,這樣設(shè)置。這時可以直接使用緩存功能。其中,max-age設(shè)置的緩存時間,過了這個時間,就算有緩存也不會進行使用。
像我公司服務(wù)器返回的頭信息中與緩存相關(guān)的字段如下:
header: {cache-control : [no-store, private]}
header: {pragma : [no-cache]}
這就說明,服務(wù)器默認是不支持緩存的,okhttp就不會對此次請求進行緩存。
接下來再看攔截器中如何設(shè)置緩存
public class LoggerInterceptor implements Interceptor { @Override public Response intercept(@NonNull Chain chain) throws IOException { // 攔截請求,獲取到該次請求的request Request request = chain.request(); // 執(zhí)行本次網(wǎng)絡(luò)請求操作,返回response信息 Response response = chain.proceed(request); if (Configuration.DEBUG) { for (String key : request.headers().toMultimap().keySet()) { LogUtil.e("zp_test", "header: {" + key + " : " + request.headers().toMultimap().get(key) + "}"); } LogUtil.e("zp_test", "url: " + request.url().uri().toString()); ResponseBody responseBody = response.body(); } return response.newBuilder() // 增加一個緩存頭信息,緩存時間為60s .header("cache-control", "public, max-age=60") // 移除pragma頭信息 .removeHeader("pragma") .build(); } }
這樣設(shè)置,就等于是在60s內(nèi)強制設(shè)置使用緩存。
注意點:
切記,最開始,我一直在犯一個錯誤,okhttp3不能緩存post接口
攔截器可以理解為,給請求的request和response重新一次封裝的機會,使得你可以在特定條件下,給一些特定的接口或者滿足特定條件的接口一些特殊的操作。
比如有一種場景,有網(wǎng)絡(luò)時,進行請求,無網(wǎng)絡(luò)時,拿緩存數(shù)據(jù)。
if (NetUtils.isNetAvailable(AppApplication.getApplication())) { response.newBuilder() .header("Cache-Control", "public, max-age=" + 0) .removeHeader("Pragma") .build(); } else { int maxStale = 60 * 60 * 24; // 無網(wǎng)絡(luò)時,設(shè)置超時為1天 response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) .removeHeader("Pragma") .build(); } return response;
max-stale:在max-age指定的失效時間外,額外增加一段指定的時間可以使用失效的response。
網(wǎng)上有很多是上面這種做法,但是,我在攔截器中試了一下,當沒有網(wǎng)絡(luò)時,壓根就不會走入攔截器。(我使用的是網(wǎng)絡(luò)攔截器,如果有是別的什么原因,歡迎指出錯誤)
最終解決方案是在初始化request(如果初始化不熟悉可以參考我的上一篇文章OKHttp3的基本使用)的時候進行的判斷操作,當有網(wǎng)絡(luò)時初始化正常的request,當沒有網(wǎng)絡(luò)時初始化強制使用緩存的request:
Request request; if (NetUtils.isNetAvailable(AppApplication.getApplication())) { request = addHeaderInfo().url(requestUrl).build(); } else { request = addHeaderInfo().url(requestUrl).cacheControl(CacheControl.FORCE_CACHE).build(); }
攔截器還是使用上面的那種形式,只是將有效時間變成了0
response.newBuilder() .header("Cache-Control", "public, max-age=" + 0) .removeHeader("Pragma") .build();
這樣就可以在有網(wǎng)絡(luò)的情況下使用最新的數(shù)據(jù),在無網(wǎng)絡(luò)的情況下使用緩存數(shù)據(jù)。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 中動態(tài)加載.jar的實現(xiàn)步驟
本文介紹動態(tài)加載 .jar的實現(xiàn)步驟,這將對你的android開發(fā)很有幫助,剛興趣的朋友可以了解下哦2013-01-01Android組件DrawerLayout仿網(wǎng)易新聞v4.4側(cè)滑菜單
這篇文章主要為大家詳細介紹了Android組件DrawerLayout仿網(wǎng)易新聞v4.4側(cè)滑菜單,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01Android 集成 google 登錄并獲取性別等隱私信息的實現(xiàn)代碼
這篇文章主要介紹了Android 集成 google 登錄并獲取 性別等隱私信息,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06Android使用GridView實現(xiàn)日歷的簡單功能
這篇文章主要為大家詳細介紹了Android使用GridView實現(xiàn)日歷的簡單功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12Android開發(fā)實現(xiàn)廣告無限循環(huán)功能示例
這篇文章主要介紹了Android開發(fā)實現(xiàn)廣告無限循環(huán)功能,結(jié)合完整實例形式分析了Android廣告圖片輪播功能的具體實現(xiàn)步驟與相關(guān)功能、布局等操作技巧,需要的朋友可以參考下2017-11-11Android ImageButton自定義按鈕的按下效果的代碼實現(xiàn)方法分享
這篇文章主要介紹了Android ImageButton自定義按鈕的按下效果的代碼實現(xiàn)方法,需要的朋友可以參考下2014-02-02Android 使用Gallery實現(xiàn)3D相冊(附效果圖+Demo源碼)
今天主要是說說如何實現(xiàn)Gallery的3D顯示切換,Demo的代碼很多是基于網(wǎng)上一些現(xiàn)成效果,感謝這些分享成果的開發(fā)者2013-07-07Android編程實現(xiàn)3D旋轉(zhuǎn)效果實例
這篇文章主要介紹了Android編程實現(xiàn)3D旋轉(zhuǎn)效果的方法,基于Android的Camera類實現(xiàn)坐標變換達到圖片3D旋轉(zhuǎn)效果,需要的朋友可以參考下2016-01-01