1. 程式人生 > >retrfoit+okhttp動態改變連線超時時間

retrfoit+okhttp動態改變連線超時時間

設定連線超時時間的基本用法

OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
            builder.readTimeout(25, TimeUnit.SECONDS);
            builder.connectTimeout(25, TimeUnit.SECONDS).build();

Retrofit retrofit =
                    new Retrofit.Builder().baseUrl(IotApiService.ENDPOINT)
                            .client(client).build();
retrofit.create(IotApiService.class);

一般重新修改超時的方法

1. 重新建立一個OkHttpClient,修改裡面的超時時間
2. retrofit替換這個新的client
3. 最後,在create的一個新的網路介面物件例項

這種修改方法是生成一個新的網路介面訪問例項,替換掉舊的,從而達到了修改超時時間條件
但是,如果retrofit.create建立的IotApiService例項不能變呢?例如使用dagger框架的情況下,一開始就將IotApiService依賴注入到每個需要它的物件中,這種情況上訴的修改方法就行不通了

so what should i do ?

先說怎麼做,在分析原因:
我們儲存好OkHttpClient這個例項,通過反射獲取這個例項內部關於超時的引數,在設定回去即可:

/**
         * 修改client超時時間
         * @param ConnectTime
         */
        public  static void modify(int ConnectTime){
            if(client == null){
                return;
            }

            try {
                Field connectTimeoutField = client.getClass().getDeclaredField("connectTimeout"
); connectTimeoutField.setAccessible(true); connectTimeoutField.setInt(client, ConnectTime); Field readTimeout = client.getClass().getDeclaredField("readTimeout"); readTimeout.setAccessible(true); readTimeout.setInt(client, ConnectTime); Field writeTimeout = client.getClass().getDeclaredField("writeTimeout"); writeTimeout.setAccessible(true); writeTimeout.setInt(client, ConnectTime); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }

問題來了,為什麼了修改了client,我們的網路介面IotApiService就變了呢?

這就得分析原始碼,檢視client、Retrofit以及建立的網路介面之間的關係了

OkHttpClient的超時時間

OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
            builder.readTimeout(25, TimeUnit.SECONDS);
            builder.connectTimeout(25, TimeUnit.SECONDS).build();

檢視原始碼,上訴這種建造中模式構建client,最終都是改變了OkHttpClient的這幾個成員:


  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
/**
     * Sets the default connect timeout for new connections. A value of 0 means no timeout,
     * otherwise values must be between 1 and {@link Integer#MAX_VALUE} when converted to
     * milliseconds.
     */
    public Builder connectTimeout(long timeout, TimeUnit unit) {
      if (timeout < 0) throw new IllegalArgumentException("timeout < 0");
      if (unit == null) throw new NullPointerException("unit == null");
      long millis = unit.toMillis(timeout);
      if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large.");
      if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small.");
      connectTimeout = (int) millis;     //這裡設定的,注意時間單位是ms
      return this;
    }

Retrofit和OKHttpClient關係?

原始碼new Retrofit.Builder()..client(client)…

//1
public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }

//2
static <T> T checkNotNull(T object, String message) {
    if (object == null) {
      throw new NullPointerException(message);
    }
    return object;
  }
//3
public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

上訴的程式碼實質就是獲取okhttpclient的一個引用,並沒有重新建立新的值,而最後retrofit.create是一個動態代理行為,起最終超時都是來自一開始的okhttpclient的那個例項物件,並沒有建立新物件,所以修改最初的okhttpclient就可以了。

有一個問題:我試著反射去修改Retrfit->okhttpclient成員–>獲取超時屬性,這種修改卻不行,不知道為啥?知道原因的還請在評論裡告知