Android Retrofit源碼分析(一邊用一邊侃)

  這幾天空餘時間老是想着寫點什麼,因此緊跟着以前android盒子模型FlexBoxLayout以後有寫下了這篇Retrofit源碼分析使用篇。java

  前言:android

    Retrofit因爲簡單與出色的性能,使其安卓上最流行的HTTP Client庫之一。json

  Android Studio開發相關配置以下:api

compile "com.squareup.retrofit2:retrofit:2.0.2"
compile "com.squareup.retrofit2:converter-gson:2.0.2"

  這裏僅僅是簡單的說明下使用,不會過多的講解說明做用,緣由就是相似使用文章百度可謂是一堆堆(雜亂無章)緩存

        OkHttpClient client = new OkHttpClient();
        client.networkInterceptors().add(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response response = chain.proceed(chain.request());
                /*添加須要過濾的請求*/
                return response;
            }
        });

  上述代碼代碼只有在有須要過濾特殊的網絡請求時纔有必要,不然能夠不用理睬,往下看。網絡

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://api.nuuneoi.com/base/")
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

  這裏涉及Retrofit的創造和參數的構建,這裏回答下上邊說道的爲何在不須要進行相應的參數過濾的時候,能夠不用指定對應的Client,讓我看下源碼內部實現:app

 1 /**
 2      * Create the {@link Retrofit} instance using the configured values.
 3      * <p>
 4      * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
 5      * OkHttpClient} will be created and used.
 6      */
 7     public Retrofit build() {
 8       if (baseUrl == null) {
 9         throw new IllegalStateException("Base URL required.");
10       }
11 
12       okhttp3.Call.Factory callFactory = this.callFactory;
13       if (callFactory == null) {
14         callFactory = new OkHttpClient();
15       }
16 
17       Executor callbackExecutor = this.callbackExecutor;
18       if (callbackExecutor == null) {
19         callbackExecutor = platform.defaultCallbackExecutor();
20       }
21 
22       // Make a defensive copy of the adapters and add the default Call adapter.
23       List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
24       adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
25 
26       // Make a defensive copy of the converters.
27       List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
28 
29       return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
30           callbackExecutor, validateEagerly);
31     }

  這裏是Retrofit內部builder構建類進行build時候執行的方法,這裏稍稍關注下行12-15,判斷是否callFactory是否爲空,那麼callFactory對象來自哪裏哪?我們繼續深刻源碼。ide

/**
     * Specify a custom call factory for creating {@link Call} instances.
     * <p>
     * Note: Calling {@link #client} automatically sets this value.
     */
    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

  這裏是給callFactory對象賦值的地方,那我在看誰調用了這個方法。
oop

/**
     * The HTTP client used for requests.
     * <p>
     * This is a convenience method for calling {@link #callFactory}.
     * <p>
     * Note: This method <b>does not</b> make a defensive copy of {@code client}. Changes to its
     * settings will affect subsequent requests. Pass in a {@linkplain OkHttpClient#clone() cloned}
     * instance to prevent this if desired.
     */
    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }

  很顯然這裏就是咱們在初始化Retrofit的時候添加OkHttpClient的地方。這也就是剛纔說的爲何但我們不須要過濾網絡請求能夠不添加OkHttpClient源碼分析

  

  這裏須要你們稍微記下是ConverterFactory,他的做用是對返回的數據格式化。

  這裏之因此說道這塊以防你須要調整json裏面的一些格式,好比,Date Format。你能夠建立一個Gson 對象並把它傳遞給GsonConverterFactory.create(),遇到相似問題能夠參考以下處理方式

 

son gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
        .create();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  緊接着讓咱們跟着上邊的簡單使用來全面走進源碼,一窺內部實現方式。

    一、這裏須要優先記憶的幾個對象聲明以下:

    callFactory:這個參數表明是實現了Call.Factory接口的類的實例,其實也就是OkHttpClient

     converterFactories:返回數據格式化類,也就是GonsConverterFactory

    adapterFactories:這個集合對象內部是CallAdapter.Factory接口實現類的實例對象

  根據上述的簡單使用咱們瞭解到,Retrofit在建立的時候須要傳入一個字節碼文件,這裏姑且不說這個字節碼文件是類仍是接口,我們看下源碼內部設計。

 

 1 @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
 2   public <T> T create(final Class<T> service) {
 3     Utils.validateServiceInterface(service);
 4     if (validateEagerly) {
 5       eagerlyValidateMethods(service);
 6     }
 7     return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
 8         new InvocationHandler() {
 9           private final Platform platform = Platform.get();
10 
11           @Override public Object invoke(Object proxy, Method method, Object... args)
12               throws Throwable {
13             // If the method is a method from Object then defer to normal invocation.
14             if (method.getDeclaringClass() == Object.class) {
15               return method.invoke(this, args);
16             }
17             if (platform.isDefaultMethod(method)) {
18               return platform.invokeDefaultMethod(method, service, proxy, args);
19             }
20             ServiceMethod serviceMethod = loadServiceMethod(method);
21             OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
22             return serviceMethod.callAdapter.adapt(okHttpCall);
23           }
24         });
25   }

 

  你們注意下方法內部第3行,Utils.validateServiceInterface(service),這裏直接翻譯就是是不是有效的服務接口,看名字可能有些人會一下不是很明白,讓我看下改方法實現。

 1   static <T> void validateServiceInterface(Class<T> service) {
 2     if (!service.isInterface()) {
 3       throw new IllegalArgumentException("API declarations must be interfaces.");
 4     }
 5     // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
 6     // Android (http://b.android.com/58753) but it forces composition of API declarations which is
 7     // the recommended pattern.
 8     if (service.getInterfaces().length > 0) {
 9       throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
10     }
11   }

 

  直譯代碼行2,意思是傳入的字節碼文件是是不是接口,若是不是則拋出一個非法參數異常,這是其一。行8看到該接口是否繼承自其它接口,也就是說該接口不容許採用繼承的方式。到這裏我們總結了兩點  

  RetrofitCreate方法傳入的字節碼文件要求以下:

    必須是一個接口

    該接口不能繼承其餘接口

 二、這裏仍是create方法的使用,那麼接下來咱們來看看他們是如何使用接口,完成一系列的網絡請求的。

    這裏首先咱們在回到剛纔的Create方法中,看下Create方法對應的返回值

 

 1 ......
 2 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
 3         new InvocationHandler() {
 4           private final Platform platform = Platform.get();
 5 
 6           @Override public Object invoke(Object proxy, Method method, Object... args)
 7               throws Throwable {
 8             // If the method is a method from Object then defer to normal invocation.
 9             if (method.getDeclaringClass() == Object.class) {
10               return method.invoke(this, args);
11             }
12             if (platform.isDefaultMethod(method)) {
13               return platform.invokeDefaultMethod(method, service, proxy, args);
14             }
15             ServiceMethod serviceMethod = loadServiceMethod(method);
16             OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
17             return serviceMethod.callAdapter.adapt(okHttpCall);
18           }
19         });
20 ......

 

  這裏使用到java中高級部分篇章java的動態代理,簡單點來講也就是當你調用接口中對應的方法會優先調用InvocationHandler中的invoke方法,有不是很明白的童鞋可行百度瞭解這塊技術,這裏就不在深刻介紹。

  知道動態代理的基本流程,讓咱們看下invoke方法內部到底是如何工做的。

  2.一、行4,這裏根據不一樣的平臺返回不一樣的Platform platform = Platform.get()對象

  2.二、行9-11,這裏是判斷調用的方式是不是Object裏的方法,若是是則直接調用不作處理.

  2.三、行12-14,這裏僅僅是java8纔會使用

  2.四、行15,這裏仍是封裝method方法,而且處理對應的註解生成指定的請求頭和請求體.

  2.五、行16,okHttpCall真正的請求實現類

  2.六、行17,返回對應封裝了指定數據類型的Call

 

  2.一、精講說明

 1  private static final Platform PLATFORM = findPlatform();
 2 
 3   static Platform get() {
 4     return PLATFORM;
 5   }
 6 
 7   private static Platform findPlatform() {
 8     try {
 9       Class.forName("android.os.Build");
10       if (Build.VERSION.SDK_INT != 0) {
11         return new Android();
12       }
13     } catch (ClassNotFoundException ignored) {
14     }
15     try {
16       Class.forName("java.util.Optional");
17       return new Java8();
18     } catch (ClassNotFoundException ignored) {
19     }
20     try {
21       Class.forName("org.robovm.apple.foundation.NSObject");
22       return new IOS();
23     } catch (ClassNotFoundException ignored) {
24     }
25     return new Platform();
26   }

  2.1.一、這裏調用Platform的靜態方法get(),而後調用方法findPlatform()

  2.1.二、方法findPlatform()根據不一樣的平臺返回不一樣的對象,這裏我們使用的Android,因此返回的是Android對象

  Android類對象繼承Platform類,源碼以下:

 1  static class Android extends Platform {
 2     @Override public Executor defaultCallbackExecutor() {
 3       return new MainThreadExecutor();
 4     }
 5 
 6     @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
 7       return new ExecutorCallAdapterFactory(callbackExecutor);
 8     }
 9 
10     static class MainThreadExecutor implements Executor {
11       private final Handler handler = new Handler(Looper.getMainLooper());
12 
13       @Override public void execute(Runnable r) {
14         handler.post(r);
15       }
16     }
17   }

  如上代碼能夠知道,

    一、Android繼承自類Platform,重載了Platform方法defaultCallbackExecutordefaultCallAdapterFactory,方法defaultCallbackExecutor返回一個MainThreadExecutor對象,方法defaultCallAdapterFactory返回了一個對象ExecutorCallAdapterFactory

    二、聲明靜態內部類MainThreadExecutor實現了接口Executor,同時初始化了一個Handler對象。

  

  2.二、精講說明<判斷調用的方式是不是Object裏的方法,若是是則直接調用不作處理.>  

    因爲不涉及Retrofit的相關操做,這裏再也不進行說明。

  2.三、精講說明<這裏僅僅是java8纔會使用>  

     爲何這麼說那,關鍵在於代碼platform.isDefaultMethod(method),因此想說明白這個問題咱們仍是須要在進一步看下方法isDefaultMethod,固然前邊我說道platform返回的是Android,因此這裏先從類Android看。上邊說道Platform重載了Platform方法defaultCallbackExecutordefaultCallAdapterFactory,因此這裏僅僅須要看下platform類對該方法的處理便可。

  boolean isDefaultMethod(Method method) {
    return false;
  }

    默認返回是false,很顯然Android平臺並不會進入邏輯處理,那麼既然說道java8纔會使用那麼必然java類重載了該方法,深刻源碼咱們看下。

 static class Java8 extends Platform {
    @Override boolean isDefaultMethod(Method method) {
      return method.isDefault();
    }
  }

    正如咱們想象的那樣。

 

    2.四、精講說明<這裏仍是封裝method方法,而且處理對應的註解生成指定的請求頭和請求體.>  

      這裏咱們先跟着代碼一塊兒往下看loadServiceMethod(method)

 1 ServiceMethod loadServiceMethod(Method method) {
 2     ServiceMethod result;
 3     synchronized (serviceMethodCache) {
 4       result = serviceMethodCache.get(method);//Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>()
 5       if (result == null) {
 6         result = new ServiceMethod.Builder(this, method).build();
 7         serviceMethodCache.put(method, result);
 8       }
 9     }
10     return result;
11   }

     這裏對method和對應的ServiceMethod作了緩存,這裏優先判斷緩存,若是不存在則去new一個ServiceMethod對象。繼續看ServiceMethod對象建立的過程。

     類Builder構造器

1 public Builder(Retrofit retrofit, Method method) {
2       this.retrofit = retrofit;
3       this.method = method;
4       this.methodAnnotations = method.getAnnotations();
5       this.parameterTypes = method.getGenericParameterTypes();
6       this.parameterAnnotationsArray = method.getParameterAnnotations();
7     }

 

    待續

相關文章
相關標籤/搜索