Retrofit 2.5.0 Invocation最佳動態配置請求timeout處理

Retrofit最佳動態配置請求timeout辦法–Invocation

最近重構項目需要調整,
需要區分普通上傳和輔助功能校驗的超時.
爲了提高用戶體驗,需要動態去進行配置.

傳統方式

1.OkHttpClient設置

最傳統的設置 請求超時時間的方法無疑是

 OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(connTimeout, TimeUnit.SECONDS)
                .readTimeout(connTimeout, TimeUnit.SECONDS)
                .writeTimeout(connTimeout, TimeUnit.SECONDS));

在創建OkhttpClient的時候,傳入指定的timeout,
還可以在這裏加上各種自定義攔截器(比如日誌輸出,user_agent,加簽)
這個當然可以.
但是如果是一個大型項目,一個host的service內有着大量的請求接口.
在請求的時候,無疑是需要對OkHttpClient進行單例複用的,
這個時候需要對這種同一個host的其中的幾個請求接口的超時時間進行獨立控制,就不好處理了.

當然還有一種辦法,

2.自定義攔截器請求地址比對

在創建OkHttpClient的時候,新增一個自定義攔截器,繼承Interceptor,然後維護一個需要獨立處理請求超時的地址集合.

@Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        String questUrl = request.url().toString();
     	//在這裏進行請求地址判斷.
        if ( isContains(questUrl)){
            Response proceed = chain.withConnectTimeout(timeout, TimeUnit.SECONDS)
                    .withReadTimeout(timeout, TimeUnit.SECONDS)
                    .withWriteTimeout(timeout, TimeUnit.SECONDS)
                    .proceed(request);
            return proceed;
        }
        return chain.proceed(request);
    }

通過維護一個地址集合,然後判斷地址,再設置對應的超時時間.
這種方法也可以,
但是如果某些地址需要超時1秒,某些需要超時2秒,某些需要超時6秒,
那麼可以預期得到,這樣寫起來會很蛋疼,
那麼有沒有什麼更好的辦法?
當然是有的!


最佳&最優雅的方式–Invocation

3.自定義攔截器與Invocation

經過上面的鋪墊,
前面的2種方法,多多少少都有着一點缺陷和遺憾.
那麼現在隆重介紹第3種方法,也是我個人認爲最佳也是最優雅的辦法.
首先請將Retrofit升級至 2.5.0
首先請將Retrofit升級至 2.5.0
首先請將Retrofit升級至 2.5.0
重要的事情說3遍.

  • 自定義註解.

先創建一個自定義註解,

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DynamicTimeout {
    int timeout();
}

註解名稱可以按照自己的習慣起,代碼內容也通俗易懂,當然也可以再加一個參數,比如說 Unit,也就是時間單位,指定設置超時時間是 毫秒或者 秒,這看具體的個人需求.

  • 添加註解

添加註解
使用起來也很簡單,直接在指定方法上面添加註解,設置指定的超時時間即可,
簡單易用!

  • 創建自定義攔截器

還是創建一個攔截器

 @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
		//核心代碼!!!
        final Invocation tag = request.tag(Invocation.class);
        final Method method = tag != null ? tag.method() : null;
        final DynamicTimeout timeout = method != null ? method.getAnnotation(DynamicTimeout.class) : null;

        XLog.d("invocation",tag!= null ? tag.toString() : "");

        if(timeout !=null && timeout.timeout() > 0){

            Response proceed = chain.withConnectTimeout(timeout.timeout(), TimeUnit.SECONDS)
                    .withReadTimeout(timeout.timeout(), TimeUnit.SECONDS)
                    .withWriteTimeout(timeout.timeout(), TimeUnit.SECONDS)
                    .proceed(request);
            return proceed;
        }

        return chain.proceed(request);
    }

注意看註釋,標註的那3行核心代碼.
在Request內,通過tag,獲取到Invocation,
然後再獲取Invocaion對象的method,最後獲取method的註解信息,
判斷註解對象存不存在,
如果存在直接讀取對應註解對象的設置參數值,動態設置進去.
Wow~
Awesome !!!


拓展

作爲一個有追求的程序員,當然會很好奇,
這玩意是怎麼實現的 以及 舉一反三.
能不能用這個再去做一點其他騷操作,來改善一下我們現有的代碼呢?
Invocation
Invocation這個類點進去一看,
平平無奇…
還是去看看他的method屬性是怎麼設置進去的吧.
RequestFactory
我們在RequestFactory內看到了是如何設置tag,
以及設置進去的tag也就是Invocation對象內如何保存 method和args的.
那麼這2個屬性的來源呢
Retrofit
當然是來自於Retrofit的核心,這個動態代理方法.
具體的源碼分析也不講了,
網上實在是太多了,我自己在2018年底也寫了一篇.

看了一圈,Invocation這個對象是有2個屬性的,我們只用到了method,
另外一個args呢,

我們其實也可以拿來利用一下.
比如 一些定義要在header內添加的 sign,user-agent,
可以通過invocation.arguments()獲取到,然後進行處理.
這些拓展用法就不細說了.

最後說一句:
JakeWharton牛逼!
JakeWharton


總結

OK,我們回顧完所有的代碼,最後的總結就是

通過Invocation動態設置請求超時時間,其原理就是通過在接口請求方法上面添加自定義註解,然後在自定義攔截器內,通過Request的tag,也就是Invocation對象,獲取到每一個接口請求方法,判斷方法是否存在我們自定義的註解,如果存在那就將註解設置的超時時間動態的設置到chain內.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章