十二、Retrofit2 原始碼解析(絕對詳細)
Retrofit2 原始碼解析
注意:本文是對原始碼的一個跟蹤,會對每一行程式碼有具體的闡述,但是不會介紹 Retrofit 的設計模式。
Retrofit:一個 Restful 設計風格的 HTTP 網路請求框架的封裝。基於 OkHttp
A type-safe HTTP client for Android and Java
0. 基本使用
1、Retrofit 將我們的 HTTP API 轉換成一個 介面形式。所以我們第一步定義一個 interface
public interface GitHubService { @GET("user/{user}/repos") Call<List<Integer>> listRepos(@Path("user") String user); }
2、然後構建一個 Retrofit,通過 create 方法生成 GitHubService 的一個實現。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class);
3、呼叫 listRepos 拿到 Call 例項,可以做同步或非同步請求。
Call<List<Integer>> repos = service.listRepos("octocat");
每個 Call 例項只能使用一次,但呼叫 clone() 將建立一個可以使用的新例項。
1. Retrofit 構建
1.1 Retrofit
首先看看 Retrofit 吧,這個類裡面有7個例項變數。我們根據型別和變數名先猜猜是幹什麼用的,留個大體印象即可。
// 一個執行緒安全的、支援高效併發的HashMap,Key 是 Method,Value 是 ServiceMethod。Method 我們能猜到應該就是上面介面中定義的 listRepos,而這個方法中有很多註解,@GET、@Path 啥的,那這個 ServiceMethod 很有可能是這個方法的封裝。而變數名帶個 Cache 說明,會把這個 Method 對應的 ServiceMethod 快取起來。 private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); // 想必你知道 Retrofit 就是基於 OkHttp 的封裝,那這個 Call.Factory,明顯就是 Call 的工廠類。至於 Call 是幹嘛的,負責建立 HTTP 請求,HTTP 請求被抽象為了 okhttp3.Call 類,它表示一個已經準備好,可以隨時執行的 HTTP 請求; final okhttp3.Call.Factory callFactory; // 這個很好理解了,就是上面 基本使用 中的 baseUrl,可是這是個 HttpUrl 型別的,我們傳的可是 String 型別的呀,那估計是通過 Builder 做了處理的。 final HttpUrl baseUrl; // Converter 根據字面意思可得 這應該是個轉換器,用於把我們的 響應 轉換成特定的格式 final List<Converter.Factory> converterFactories; // CallAdapter 根據字面意思,難道是對 Call 的一個適配? final List<CallAdapter.Factory> callAdapterFactories; // Executor 很熟悉了,這是個回撥 Executor,想必就是用來切換執行緒的了 final @Nullable Executor callbackExecutor; // 這個就猜不出了,只能暫時理解為一個標誌位 final boolean validateEagerly;
再來看看 Retrofit 的建構函式
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = converterFactories; // Copy+unmodifiable at call site. this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; }
並沒做什麼特殊的處理,就是簡單的賦值,那想必所有初始化的操作都在 Builder 裡了。
那麼成功建立一個 Retrofit 物件的標準就是:配置好Retrofit 裡的成員變數。
- callFactory : 網路請求 工廠
- baseUrl :網路請求的基本 Url 地址
- converterFactories :資料轉換器 工廠集合
- callAdapterFactories :網路請求介面卡 工廠集合
- callbackExecutor :回撥方法執行器
1.2 Retrofit.Builder
public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private HttpUrl baseUrl; private final List<Converter.Factory> converterFactories = new ArrayList<>(); private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; Builder(Platform platform) { this.platform = platform; } public Builder() { this(Platform.get()); } // ... ... }
我們可以看到 Builder 與 Retrofit 的引數幾乎一樣,只是少了 serviceMethodCache,多了個 Platform。這個 Platform 很重要。我們通過 Builder 的建構函式可以知道,呼叫了 Platform.get()方法,然後賦值給自己的 platform 變數。 我們看看這個 Platform 類。
class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM; } private static Platform findPlatform() { try { Class.forName("android.os.Build"); if (Build.VERSION.SDK_INT != 0) { return new Android(); } } catch (ClassNotFoundException ignored) { } try { Class.forName("java.util.Optional"); return new Java8(); } catch (ClassNotFoundException ignored) { } return new Platform(); } // ... ... }
get 方法會去呼叫 findPlatform 方法,這個裡面很明顯跟平臺相關,Class.forName 要求 JVM 根據 className 查詢並載入指定的類,如果未找到則丟擲 ClassNotFoundException 。這裡很明顯我們分析 Android 平臺,所以會 return 一個 Android()物件。
//Platform 內部 static class Android extends Platform { @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError(); return new ExecutorCallAdapterFactory(callbackExecutor); } static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }
我們在這裡面可以看到兩個重要的方法
- defaultCallbackExecutor :這個方法返回的是個 Executor ,我們想到 Retrofit 正好有個 Executor 型別的變數,那麼想必就是它了,它是 MainThreadExecutor 型別的,內部採用 handler 執行任務。
- defaultCallAdapterFactory :這個方法返回的是個 CallAdapter.Factory,Retrofit 成員變數中也正好有個 CallAdapter.Factory 型別的變數,所以說這個 Platform 很重要嘛,跟我們 Retrofit 類中的兩個成員變數都有重大的關係。這裡最終返回的是個 ExecutorCallAdapterFactory ,話說我們一開始就不知道這個 CallAdapter 是什麼,更不用說這個 Factory 了,那我們先看看這個 ExecutorCallAdapterFactory 吧。
final class ExecutorCallAdapterFactory extends CallAdapter.Factory { final Executor callbackExecutor; ExecutorCallAdapterFactory(Executor callbackExecutor) { this.callbackExecutor = callbackExecutor; } @Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Object, Call<?>>() { @Override public Type responseType() { return responseType; } @Override public Call<Object> adapt(Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; } //... ... 省略 }
這裡我們可以看到,把我們傳進來的 Executor 儲存起來了,這個 Executor 想必就是 MainThreadExecutor 了。至於 get 方法,我們暫時還不知道哪裡用到了,所以後面的暫時不看了,到了這裡還是不知道 CallAdapter.Factory 幹嘛用的。
看來 Builder 方法很複雜呀,寫了這麼多隻是講了個 Platform,不過幸好這裡面也包括了 Executor 和 CallAdapter.Factory ,那麼現在我們正式看看 Builder.build()方法。
public Retrofit build() { // 這一句告訴我們,baseUrl 是必不可少的。 if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } // 這裡如果你沒配置 callFactory , 會預設配置為 OkHttpClient okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } // 同樣的,沒配置的話,會預設配置為 Platform 的 defaultCallbackExecutor,這裡我們之前分析過,它所返回的就是 MainThreadExecutor Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } //這裡會把你所配置的 CallAdapter.Factory 加到 List 裡去,最後把 Platform 預設的 defaultCallAdapterFactory 即 ExecutorCallAdapterFactory 加到 List 的最後邊, // Make a defensive copy of the adapters and add the default Call adapter. List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); //這裡一樣會把你配置的 Converter.Factory 加到 List 裡去,但是會把一個 BuiltInConverters 加到第一個,而不是最後一個,請注意這點。 // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size()); // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); //最後返回一個 Retrofit 物件 return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
到這裡,我們的 Retrofit 就構建完成了。如果按照我們 基本使用 中的例子,那麼此刻,Retrofit 成員變數的值如下:
- serviceMethodCache :暫時為空的 HashMap 集合
- callFactory : OkHttpClient 物件
- baseUrl : 根據配置的baseUrl "ofollow,noindex">https://api.github.com/ " 字串, 構建出了一個 HttpUrl 物件
- converterFactories :一個 ArrayList 物件,裡面存放著一個BuiltInConverters 物件
- callAdapterFactories :一個 ArrayList 物件,裡面存放著一個 ExecutorCallAdapterFactory 物件
- callbackExecutor :MainThreadExecutor 物件
- validateEagerly :預設值 false
2. 建立網路請求介面例項,即GitHubService service = retrofit.create(GitHubService.class);
接下來我們看看是怎樣獲得 GitHubService 例項的。
同樣上原始碼,注意 這裡的 create 是非常重要的一個方法,這裡使用了 外觀模式 和 代理模式。
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall); } }); }
這裡我們看到了 validateEagerly 變數,讓我們看看它到底控制了什麼。進 eagerlyValidateMethods 方法。
private void eagerlyValidateMethods(Class<?> service) { Platform platform = Platform.get(); for (Method method : service.getDeclaredMethods()) { if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); } } } ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
這裡又見到了 Platform ,在 Retrofit.Builder 我們知道它返回的是 Android() 物件。 接著是個 迴圈 ,迴圈取出介面中的 Method ,接著呼叫 loadServiceMethod 。 loadServiceMethod 裡面會根據 Method 生成一個 ServiceMethod,然後存入 serviceMethodCache , 那麼我們大概知道,這是屬於提前驗證 ,會提前把介面中每個方法進行解析 得到一個ServiceMethod 物件,然後存入快取中。 在 loadServiceMethod 中會取快取中的值,如果有就直接返回 ServiceMethod。
由此可以知道validateEagerly 變數是用於 判斷是否需要提前驗證解析的。
create 方法中 繼續往下走,會看到 return 一個 代理物件 Proxy ,並轉成了 T 型別,即 GitHubService 。
此時我們這句程式碼GitHubService service = retrofit.create(GitHubService.class);
中的 service 有值了,它指向一個 實現了 GitHubService 介面的 代理物件 Proxy 。
3. 拿到 Call 物件 , 即Call<List<Repo>> repos = service.listRepos("octocat");
這裡我們的 service 是個代理物件,所以執行 listRepos 方法時, 會先走 InvocationHandler 中的 invoke 方法。
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. // 如果這個方法是宣告在 Object 類中,那麼不攔截,直接執行 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } // 這個總是返回的false,所以不用關心 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } // 下面三行程式碼非常重要,重點分析,分別對應 3.1 3.2 3.3 三個小節 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall); } }); }
3.1ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
首先 ServiceMethod 我們之前猜測過,應該是對 Method 的一個封裝, 而這個 loadServiceMethod ,如果你還記得的話,我們在 create 的時候就碰到過,eagerlyValidateMethods 這個方法內部呼叫過 loadServiceMethod ,是為了載入這個 ServiceMethod 。現在我們來深入分析這個 loadServiceMethod 方法。
ServiceMethod<?, ?> loadServiceMethod(Method method) { // 首先從 快取 serviceMethodCache 中取 ServiceMethod ,如果存在就返回,不存在繼續往下走。 // 也就是說 我們的 ServiceMethod 只會建立一次。 ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { //這裡又從快取取了一遍,看到這裡有沒有一種熟悉的感覺,是不是跟 DCL 單例模式特別像,雙重校驗。 result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
到這裡其實 loadServiceMethod 已經分析完了,很簡單,就是個 DCL 單例模式,然後獲得 ServiceMethod 。
那其實我們現在的分析任務就很明確了,弄清楚這個 ServiceMethod 究竟是什麼 。
3.1.1 ServiceMethod 分析
final class ServiceMethod<R, T> { // ... 省略部分程式碼 private final okhttp3.Call.Factory callFactory; private final CallAdapter<R, T> callAdapter; private final HttpUrl baseUrl; private final Converter<ResponseBody, R> responseConverter; // 同樣先猜猜什麼意思吧 // 應該是網路請求的 Http 方法,比如 GET、POST 啥的 private final String httpMethod; // 相對地址 ,應該就是 "user/{user}/repos" 這一段 private final String relativeUrl; // http 請求頭 private final Headers headers; // 網路請求的 http 報文的 body 的型別 private final MediaType contentType; // 是否有 body private final boolean hasBody; // post 提交資料時,是否使用 表單提交 方式 private final boolean isFormEncoded; // post 提交資料時,是否使用 Mutipart 方式,一般用來檔案上傳 private final boolean isMultipart; // 方法引數處理器,應該是解析方法中的 引數 的吧,這個估計也得詳細分析下。 private final ParameterHandler<?>[] parameterHandlers; ServiceMethod(Builder<R, T> builder) { this.callFactory = builder.retrofit.callFactory(); this.callAdapter = builder.callAdapter; this.baseUrl = builder.retrofit.baseUrl(); this.responseConverter = builder.responseConverter; this.httpMethod = builder.httpMethod; this.relativeUrl = builder.relativeUrl; this.headers = builder.headers; this.contentType = builder.contentType; this.hasBody = builder.hasBody; this.isFormEncoded = builder.isFormEncoded; this.isMultipart = builder.isMultipart; this.parameterHandlers = builder.parameterHandlers; } // ... 省略部分程式碼
首先看看 ServiceMethod 的構造方法。 也是通過建造者模式構建的。其中很多變數其實都很熟悉了,比如 callFactory 、 baseUrl 。 對於 callAdapter、responseConverter 我們別弄混了,我們在 Retrofit 類中的變數是 callAdapterFactories 和 converterFactories , 是它們的工廠,是生產它們的地方。
接下來看 Builder 吧,畢竟這是真正做事的。
public ServiceMethod build() { // 拿到具體的 CallAdapter 即 網路請求介面卡,具體看 3.1.1.1 callAdapter = createCallAdapter(); // 根據上面拿到的 callAdapter 獲取 響應型別,在 3.1.1.1 小節分析完後可知道 // 在我們的例子中 responseType = java.util.List<java.lang.Integer> responseType = callAdapter.responseType(); if (responseType == Response.class || responseType == okhttp3.Response.class) { throw methodError("'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } // 獲取 響應轉換器 ,具體看 3.1.1.2 小節 responseConverter = createResponseConverter(); // 解析網路請求介面中方法的註解,這裡我們就只有一個 @GET 註解,具體看 3.1.1.3 小節 // 這裡解析完可以拿到 Http 請求方法、請求體、相對 url、相對 url 中的引數 for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } //解析完方法上的註解後,做校驗 if (httpMethod == null) { throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.)."); } if (!hasBody) { if (isMultipart) { throw methodError( "Multipart can only be specified on HTTP methods with request body (e.g., @POST)."); } if (isFormEncoded) { throw methodError("FormUrlEncoded can only be specified on HTTP methods with " + "request body (e.g., @POST)."); } } // 解析當前方法的引數,這裡就我們的例子而言 // parameterAnnotationsArray 就是 @Path ,所以這裡的 length 就是 1 int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { // parameterTypes 是引數型別,就本例而言是 String Type parameterType = parameterTypes[p]; if (Utils.hasUnresolvableType(parameterType)) { throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType); } // 拿到第一個引數的 註解陣列 Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; if (parameterAnnotations == null) { throw parameterError(p, "No Retrofit annotation found."); } // 解析引數 // p : 0 // parameterType : String // parameterAnnotations : 雖然是陣列,但是就一個元素 @Path // 這個 parseParameter 就不分析了,大家自己看看原始碼就清楚了,無非就是構建 ParameterHandler 陣列,而這個 ParameterHandler 其實就是負責解析 API 定義時每個方法的引數,並在構造 HTTP 請求時設定引數 parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } // 解析完方法中引數的註解後,做校驗 if (relativeUrl == null && !gotUrl) { throw methodError("Missing either @%s URL or @Url parameter.", httpMethod); } if (!isFormEncoded && !isMultipart && !hasBody && gotBody) { throw methodError("Non-body HTTP method cannot contain @Body."); } if (isFormEncoded && !gotField) { throw methodError("Form-encoded method must contain at least one @Field."); } if (isMultipart && !gotPart) { throw methodError("Multipart method must contain at least one @Part."); } return new ServiceMethod<>(this); }
3.1.1.1 createCallAdapter ()
private CallAdapter<T, R> createCallAdapter() { // 拿到網路請求接口裡方法的返回值型別,在我們的例子中會返回如下型別 // retrofit2.Call<java.util.List<java.lang.Integer>> Type returnType = method.getGenericReturnType(); if (Utils.hasUnresolvableType(returnType)) { throw methodError( "Method return type must not include a type variable or wildcard: %s", returnType); } // 如果返回型別是 void ,丟擲異常 if (returnType == void.class) { throw methodError("Service methods cannot return void."); } // 拿到方法的 註解 ,在我們的例子中就是如下所示,大家可以自己實驗下 // @retrofit2.http.GET(value=users/{user}/repos) Annotation[] annotations = method.getAnnotations(); try { // 拿到註解後,返回個 CallAdapter ,跟進去看看究竟是做了什麼 return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create call adapter for %s", returnType); } } public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { // 這裡會去呼叫 nextCallAdapter return nextCallAdapter(null, returnType, annotations); } // 這裡的引數大家注意 // skipPast 上面傳的是 null // returnType 就是retrofit2.Call<java.util.List<java.lang.Integer>> // annotations 在我們的例子中就是 @retrofit2.http.GET(value=users/{user}/repos) public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null"); checkNotNull(annotations, "annotations == null"); // callAdapterFactories 是一個 ArrayList 物件,裡面存放著一個 ExecutorCallAdapterFactory 物件 ,這個是在 Retrofit Builder 的時候建立的,也就是我們上面所說的生產 CallAdapter 的地方,大家可以回過頭去看看。 這裡的 skipPast 是null, 所以 indexOf 肯定返回的 -1, 所以這裡 start = 0 int start = callAdapterFactories.indexOf(skipPast) + 1; // 迴圈, 這裡由於我們的 callAdapterFactories 只有一個 元素, 所以直接看 ExecutorCallAdapterFactory 的 get方法 for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } // 錯誤資訊 builder StringBuilder builder = new StringBuilder("Could not locate call adapter for ") .append(returnType) .append(".\n"); if (skipPast != null) { builder.append("Skipped:"); for (int i = 0; i < start; i++) { builder.append("\n* ").append(callAdapterFactories.get(i).getClass().getName()); } builder.append('\n'); } builder.append("Tried:"); for (int i = start, count = callAdapterFactories.size(); i < count; i++) { builder.append("\n* ").append(callAdapterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }
到這裡,我們別忘了我們是在幹嘛,我們是在獲取CallAdapter<T, R>
,好了,繼續看 **ExecutorCallAdapterFactory 的 get方法 **。 解釋都在程式碼註釋裡喲,一定要看看才知道現在到底是在幹啥。話說原始碼分析,還是得靠自己認認真真讀一次原始碼才行。
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { // getRawType 會返回該型別的原始類型別 , 比如傳進去的是 List<? extends Runnable> 會返回 List.class // 那麼在我們的例子中,我們的 returnType 是 retrofit2.Call<java.util.List<java.lang.Integer>> // 那麼 getRawType 後,返回的是 retrofit2.Call ,所以這裡是相等的 if (getRawType(returnType) != Call.class) { return null; } // 根據 returnType 拿到 responseType ,這裡就不跟進了,可以自己去看看 // 在我們的例子中, responseType = java.util.List<java.lang.Integer> final Type responseType = Utils.getCallResponseType(returnType); // 最後返回一個 CallAdapter return new CallAdapter<Object, Call<?>>() { @Override public Type responseType() { return responseType; } @Override public Call<Object> adapt(Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; }
到這裡,其實我們大概知道這個 CallAdapter 有什麼用了,就是提供兩個東西
- 網路請求響應要返回的型別 responseType
- retrofit2.Call< T >,注意這裡不是 okhttp3 下的 Call ,這裡暫不深究。
因為我們不要忘了現在在做什麼,我們現在是在獲取 ServiceMethod 中的 callAdapter 變數值。所以看到這裡返回了一個 CallAdapter 物件即可。
3.1.1.2 createResponseConverter ()
這裡個方法是獲取 響應轉換器, 就是把網路請求得到的響應資料轉換成相應的格式。
private Converter<ResponseBody, T> createResponseConverter() { // 拿到方法上所有的註解,在我們的例子中就只有 @GET 註解 Annotation[] annotations = method.getAnnotations(); // 這裡的 responseType 就是上面我們得到的 List<Integer> try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create converter for %s", responseType); } }
這裡想必大家也知道套路了,跟獲取 CallAdapter 是一樣的,程式碼就不貼了,程式碼裡同樣是迴圈遍歷 Retrofit 裡的 converterFactories 變數。而這個 converterFactories 在我們的例子中是沒有設定轉換器的,所以它也只有一個預設的元素,即 BuiltInConverters 。 那麼我們直接檢視 它的 responseBodyConverter 方法。
final class BuiltInConverters extends Converter.Factory { // 注意這裡的引數,別忘了到底是什麼 // type : 就是我們的 responseType ,即 List<Integer> // annotations : 這裡我們方法的註解只有一個,所以就是 @GET @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { if (type == ResponseBody.class) { return Utils.isAnnotationPresent(annotations, Streaming.class) ? StreamingResponseBodyConverter.INSTANCE : BufferingResponseBodyConverter.INSTANCE; } if (type == Void.class) { return VoidResponseBodyConverter.INSTANCE; } return null; }
通過這裡我們可以知道,其實它會返回 null 。 所以我們ServiceMethod 中的 Builder 中的 responseConverter 變數就等於 null 。
3.1.1.3 parseMethodAnnotation ()
我們來看看 解析方法註解 ,注意我們例子中這個方法裡傳的引數是 @GET 註解
private void parseMethodAnnotation(Annotation annotation) { if (annotation instanceof DELETE) { parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false); } else if (annotation instanceof GET) { //我們這裡是 GET 註解,所以進這個方法 parseHttpMethodAndPath("GET", ((GET) annotation).value(), false); } else if (annotation instanceof HEAD) { parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false); if (!Void.class.equals(responseType)) { throw methodError("HEAD method must use Void as response type."); } } // 省略後續程式碼,後續還有很多其他型別的判斷 } // 這裡的三個引數的值 // httpMethod : GET // value : users/{user}/repos // hasBody : false private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { // 此處判斷 httpMethod 的值是否存在,說明只允許一個 HTTP 方法存在 if (this.httpMethod != null) { throw methodError("Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod); } this.httpMethod = httpMethod; this.hasBody = hasBody; if (value.isEmpty()) { return; } // 下面是解析 value 中的 相對 url // Get the relative URL path and existing query string, if present. int question = value.indexOf('?'); if (question != -1 && question < value.length() - 1) { // Ensure the query string does not have any named parameters. String queryParams = value.substring(question + 1); Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams); if (queryParamMatcher.find()) { throw methodError("URL query string \"%s\" must not have replace block. " + "For dynamic query parameters use @Query.", queryParams); } } this.relativeUrl = value; // 相對地址中的引數名字,這裡不具體分析了,可以把結果告訴你 // 在我們的例子中 value = “users/{user}/repos” // 這裡的 relativeUrlParamNames 是個 Set<String> 集合 ,裡面只有一個元素 user 。 this.relativeUrlParamNames = parsePathParameters(value); }
至此,我們的 Builder 把 Http 的方法以及它的 Url 給分析完了,現在只剩引數解析了 。引數解析在 ServiceMethod 的 build 方法裡已經講過了 ,記得看註釋。
呼~ 終於講完了 ServiceMethod 的構造。這麼大篇幅,由此可以看出 ServiceMethod 這個類非常重要。現在來總結一下,我們究竟擁有了些什麼。
- callFactory : ExecutorCallAdapterFactory 例項
- callAdapter : ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 例項
- baseUrl : HttpUrl 例項
- responseConverter : 由於我們沒設定,所以為 null
- httpMethod : 字串 GET
- relativeUrl :字串 users/{user}/repos
- headers : 沒有設定 Headers ,所以為 null
- contentType : null
- hasBody : false
- isFormEncoded : false
- isMultipart : false
- parameterHandlers : 就我們例子而已,該陣列有一個元素,Path 物件,它是 ParameterHandler 抽象類裡的一個靜態內部類。
由此可以看出,ServiceMethod 物件包含了訪問網路的所有基本資訊。
好吧,接下來還是得繼續前行,別忘了,我們構建 ServiceMethod 只是在 invoke 方法內,並且這還只是第一步。接下來看第二步。
3.2OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
這裡是 new 一個 OkHttpCall 物件,這個 OkHttpCall 是 Retrofit 的 Call,它裡面就是做請求的地方,會有 request、enqueue 等同步、非同步請求方法,但是在這裡面真正執行請求的是 okhttp3.Call ,即把請求委託給 okHttp 去執行。下面簡要看看它的構造方法和一些成員變數吧,因為這裡只是 new 操作,所以暫時不分析其餘方法,用到的時候再看。
final class OkHttpCall<T> implements Call<T> { // 含有所有網路請求引數資訊的 ServiceMethod private final ServiceMethod<T, ?> serviceMethod; private final @Nullable Object[] args; private volatile boolean canceled; // 實際進行網路請求的 Call private @Nullable okhttp3.Call rawCall; @GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException. private @Nullable Throwable creationFailure; @GuardedBy("this") private boolean executed; // 傳入配置好的 ServiceMethod 和 請求引數 OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) { this.serviceMethod = serviceMethod; this.args = args; }
這樣就把 OkHttpCall 給構建好了,接下來看第三步。
3.3return serviceMethod.adapt(okHttpCall);
直接上程式碼
T adapt(Call<R> call) { return callAdapter.adapt(call); }
這是 前面構建好的 ServiceMethod 中的 adapt 方法,會去呼叫 callAdapter 的 adapt 方法,我們知道 ServiceMethod 中的 callAdapter 是 ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 例項。而這個例項的 adapt 方法會返回一個 ExecutorCallbackCall 物件。
<!-- ExecutorCallAdapterFactory 內部類 --> static final class ExecutorCallbackCall<T> implements Call<T> { // 這裡在之前建立ExecutorCallAdapterFactory時,就知道它的值了,就是 MainThreadExecutor ,用來切換執行緒的 final Executor callbackExecutor; // 這就是剛剛傳進來的 OkHttpCall final Call<T> delegate; ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; }
到這裡為止,我們已經成功的返回了一個Call<List<Integer>>
4. 呼叫 Call 的 enqueue
趁熱打鐵,我們執行非同步請求,看看怎樣切換執行緒的。
<!-- ExecutorCallbackCall 內部 --> @Override public void enqueue(final Callback<T> callback) { checkNotNull(callback, "callback == null"); // 真正的 Call 去執行請求 delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { // 回撥後 利用 MainThreadExecutor 中的 Handler 切換到主執行緒中去。 callbackExecutor.execute(new Runnable() { @Override public void run() { if (delegate.isCanceled()) { // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation. callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled")); } else { callback.onResponse(ExecutorCallbackCall.this, response); } } }); } @Override public void onFailure(Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); }
可以看到是 delegate 執行了 enqueue 操作,而 delegate 就是我們的 OkHttpCall ,在 OkHttpCall 裡的 enqueue 方法是這樣工作的。
通過okhttp3.Call call = serviceMethod.toCall(args);
構建一個真正執行請求的 Call ,即把請求交給 okhttp 去完成。而構建一個 Call 利用到了 ServiceMethod 中的 ParameterHandler 物件,這個物件是用來處理引數的。 它會把具體引數的值與 RequestBuilder 繫結起來。當然也用到了 ServiceMethod 自己,ServiceMethod 類似請求響應的大管家。
別忘了拿到響應後,在 okhttp3.Callback 中會去呼叫response = parseResponse(rawResponse);
將響應轉換成自己想要的格式,即定義的 Converter 。
到這裡終於結束了,當然在響應解析這裡還有許多沒講,但是 Retrofit 一個主體的流程已經走完了。真累。。。
沒啥總結的了,這篇文章只是用來跟蹤具體的原始碼,具體到每一句程式碼都有解釋。至於 Retrofit 的設計思路,別的文章都有講。
總之,在自己跟著分析完這麼一大段後,已經對 Retrofit 相當熟悉了,遇到問題,相信也可以定位到原始碼中去找到問題的根源,然後解決,至此,目標已達成。