這幾天空餘時間老是想着寫點什麼,因此緊跟着以前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看到該接口是否繼承自其它接口,也就是說該接口不容許採用繼承的方式。到這裏我們總結了兩點
Retrofit的Create方法傳入的字節碼文件要求以下:
必須是一個接口
該接口不能繼承其餘接口
二、這裏仍是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方法defaultCallbackExecutor和defaultCallAdapterFactory,方法defaultCallbackExecutor返回一個MainThreadExecutor對象,方法defaultCallAdapterFactory返回了一個對象ExecutorCallAdapterFactory
二、聲明靜態內部類MainThreadExecutor實現了接口Executor,同時初始化了一個Handler對象。
2.二、精講說明<判斷調用的方式是不是Object裏的方法,若是是則直接調用不作處理.>
因爲不涉及Retrofit的相關操做,這裏再也不進行說明。
2.三、精講說明<這裏僅僅是java8纔會使用>
爲何這麼說那,關鍵在於代碼platform.isDefaultMethod(method),因此想說明白這個問題咱們仍是須要在進一步看下方法isDefaultMethod,固然前邊我說道platform返回的是Android,因此這裏先從類Android看。上邊說道類Platform重載了Platform方法defaultCallbackExecutor和defaultCallAdapterFactory,因此這裏僅僅須要看下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 }
待續