前言不搭后語(yǔ):
自上次簡(jiǎn)書(shū)要求更新發(fā)布文章需要用戶(hù)綁定微信和手機(jī)號(hào)诉濒,著實(shí)被惡心了一下下,也說(shuō)過(guò)不再此處更新了。但現(xiàn)在想想攻冷,誰(shuí)不是已經(jīng)被扒的底褲都沒(méi)了,這點(diǎn)隱私的抗?fàn)師o(wú)非是給施暴者增加點(diǎn)情趣而已紧显,穿上褲子讲衫,生活還得繼續(xù),文章還得繼續(xù)寫(xiě)孵班,此刻真香涉兽。
正題
一般設(shè)置超時(shí)時(shí)間的方法:
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.readTimeout(20, TimeUnit.SECONDS);
builder.connectTimeout(10, TimeUnit.SECONDS).build();
Retrofit retrofit =new Retrofit.Builder().baseUrl("")
.client(client).build();
retrofit.create(ApiService.class);
但某些時(shí)候,我們需要針對(duì)單個(gè)的接口進(jìn)行動(dòng)態(tài)設(shè)置超時(shí)時(shí)間篙程。網(wǎng)上能找到的答案基本都是攔截器+反射實(shí)現(xiàn):
- 創(chuàng)建一個(gè)新的OkHttpClient枷畏,重新設(shè)置超時(shí)時(shí)間。
- 通過(guò)反射機(jī)制拿到對(duì)應(yīng)的屬性重新設(shè)置起時(shí)間值虱饿。
以上兩種方法拥诡,第一種沒(méi)試過(guò),因?yàn)橛X(jué)得不夠優(yōu)雅氮发。
第二種網(wǎng)上的做法如下渴肉,是我根據(jù)網(wǎng)上看到的實(shí)現(xiàn)的:
/**
* Created by ing on 2019/3/6
* 動(dòng)態(tài)設(shè)置接口請(qǐng)求超時(shí)時(shí)間
*/
public class DynamicTimeoutInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request oldRequest = chain.request();
setDynamicTimeout(oldRequest,okhttpclient);//這里是你當(dāng)前的okhttpclient對(duì)象
Request newRequest = oldRequest.newBuilder()
.method(oldRequest.method(), oldRequest.body())
.url(oldRequest.url())
.build();
return chain.proceed(newRequest);
}
/**
* 根據(jù)所需接口、進(jìn)行動(dòng)態(tài)設(shè)置網(wǎng)絡(luò)超時(shí)時(shí)間
*
* @param oldRequest
// * @param retrofit
*/
private void setDynamicTimeout(Request oldRequest,OkHttpClient client) {
final String questUrl = oldRequest.url().url().toString();
try {
//設(shè)置連接超時(shí),注意混淆規(guī)則爽冕,避免字段被混淆
boolean isCloseApi = questUrl.contains(PayApi.API_CLOSEORDER);
boolean isPollingApi = questUrl.contains(PayApi.API_POLLING);
if (isCloseApi||isPollingApi){
Field readTimeoutField = client.getClass().getDeclaredField("readTimeout");
readTimeoutField.setAccessible(true);
//設(shè)置讀寫(xiě)超時(shí)
Field connectTimeoutField = client.getClass().getDeclaredField("connectTimeout");
connectTimeoutField.setAccessible(true);
//過(guò)濾接口仇祭,重新設(shè)置超時(shí)時(shí)間
if (isCloseApi) {
connectTimeoutField.setInt(client, TimeOut.CLOSE_CONNECT);
readTimeoutField.setInt(client, TimeOut.CLOSE_READ);
} else if (isPollingApi) {
readTimeoutField.setInt(client, TimeOut.POLLING_READ );
}else {
readTimeoutField.setInt(client, TimeOut.DEFALT_READ );
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上方法測(cè)試無(wú)效,究其原因是因?yàn)榉瓷淠玫降膶傩允莊inal的颈畸,所以即便拿到也無(wú)法修改乌奇,這里感謝評(píng)論里epitomizelu
解惑。
后來(lái)查看chain 接口內(nèi)容眯娱,發(fā)現(xiàn)其內(nèi)就已提供了對(duì)應(yīng)的超時(shí)時(shí)間設(shè)置接口方法:
/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the request
* or response.
*/
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit); //重點(diǎn)在這
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);//重點(diǎn)在這
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);//重點(diǎn)在這
}
}
可以看到對(duì)應(yīng)的三種超時(shí)時(shí)間都有提供礁苗,哦了,那我們就通過(guò)這個(gè)來(lái)設(shè)置一下徙缴,最終代碼如下:
/**
* Created by ing on 2019/3/6
* 動(dòng)態(tài)設(shè)置接口請(qǐng)求超時(shí)時(shí)間
*/
public class DynamicTimeoutInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request reequest = chain.request();
String questUrl = reequest.url().toString();
boolean isCloseApi = questUrl.contains(PayApi.API_CLOSEORDER);
boolean isPollingApi = questUrl.contains(PayApi.API_POLLING);
if (isCloseApi){
return chain.withConnectTimeout(TimeOut.CLOSE_CONNECT,TimeUnit.SECONDS)
.withReadTimeout(TimeOut.CLOSE_READ,TimeUnit.SECONDS)
.proceed(reequest);
}else if (isPollingApi){
return chain.withReadTimeout(TimeOut.POLLING_READ,TimeUnit.SECONDS)
.proceed(reequest);
}
return chain.proceed(reequest);
}
}
最后別忘了试伙,將此攔截器添加上:
.addInterceptor(new DynamicTimeoutInterceptor())
然后測(cè)試 完美!!