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() 將創(chuàng)建一個可以使用的新實例沃疮。
1. Retrofit 構建
1.1 Retrofit
首先看看 Retrofit 吧盒让,這個類里面有7個實例變量。我們根據類型和變量名先猜猜是干什么用的司蔬,留個大體印象即可邑茄。
// 一個線程安全的、支持高效并發(fā)的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 是干嘛的坞嘀,負責創(chuàng)建 HTTP 請求躯护,HTTP 請求被抽象為了 okhttp3.Call 類,它表示一個已經準備好丽涩,可以隨時執(zhí)行的 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 :回調方法執(zhí)行器
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 執(zhí)行任務疆柔。
- 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 " https://api.github.com/ " 字符串, 構建出了一個 HttpUrl 對象
- converterFactories :一個 ArrayList 對象勺阐,里面存放著一個BuiltInConverters 對象
- callAdapterFactories :一個 ArrayList 對象卷中,里面存放著一個 ExecutorCallAdapterFactory 對象
- callbackExecutor :MainThreadExecutor 對象
- validateEagerly :默認值 false
2. 創(chuàng)建網絡請求接口實例,即 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() 對象。 接著是個 循環(huán) 玩焰,循環(huán)取出接口中的 Method 由驹,接著調用 loadServiceMethod 。 loadServiceMethod 里面會根據 Method 生成一個 ServiceMethod震捣,然后存入 serviceMethodCache 荔棉, 那么我們大概知道,這是屬于提前驗證蒿赢,會提前把接口中每個方法進行解析得到一個 ServiceMethod 對象润樱,然后存入緩存中。 在 loadServiceMethod 中會取緩存中的值羡棵,如果有就直接返回 ServiceMethod壹若。
由此可以知道 validateEagerly 變量是用于 判斷是否需要提前驗證解析的。
create 方法中 繼續(xù)往下走皂冰,會看到 return 一個 代理對象 Proxy 店展,并轉成了 T 類型,即 GitHubService 秃流。
此時我們這句代碼 GitHubService service = retrofit.create(GitHubService.class);
中的 service 有值了赂蕴,它指向一個 實現了 GitHubService 接口的 代理對象 Proxy 。
3. 拿到 Call 對象 舶胀, 即 Call<List<Repo>> repos = service.listRepos("octocat");
這里我們的 service 是個代理對象概说,所以執(zhí)行 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 類中糖赔,那么不攔截萍丐,直接執(zhí)行
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 三個小節(jié)
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
3.1 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
首先 ServiceMethod 我們之前猜測過,應該是對 Method 的一個封裝奋构, 而這個 loadServiceMethod 壳影,如果你還記得的話,我們在 create 的時候就碰到過声怔,eagerlyValidateMethods 這個方法內部調用過 loadServiceMethod 态贤,是為了加載這個 ServiceMethod 。現在我們來深入分析這個 loadServiceMethod 方法醋火。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
// 首先從 緩存 serviceMethodCache 中取 ServiceMethod 悠汽,如果存在就返回,不存在繼續(xù)往下走芥驳。
// 也就是說 我們的 ServiceMethod 只會創(chuàng)建一次柿冲。
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 小節(jié)分析完后可知道
// 在我們的例子中 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 小節(jié)
responseConverter = createResponseConverter();
// 解析網絡請求接口中方法的注解编丘,這里我們就只有一個 @GET 注解与学,具體看 3.1.1.3 小節(jié)
// 這里解析完可以拿到 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 上面?zhèn)鞯氖?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 的時候創(chuàng)建的,也就是我們上面所說的生產 CallAdapter 的地方很泊,大家可以回過頭去看看角虫。 這里的 skipPast 是null沾谓, 所以 indexOf 肯定返回的 -1, 所以這里 start = 0
int start = callAdapterFactories.indexOf(skipPast) + 1;
// 循環(huán)戳鹅, 這里由于我們的 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>
妇穴,好了,繼續(xù)看 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 是一樣的,代碼就不貼了赐俗,代碼里同樣是循環(huán)遍歷 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.");
}
}
// 省略后續(xù)代碼澎现,后續(xù)還有很多其他類型的判斷
}
// 這里的三個參數的值
// 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 抽象類里的一個靜態(tài)內部類。
由此可以看出庙睡,ServiceMethod 對象包含了訪問網絡的所有基本信息事富。
好吧,接下來還是得繼續(xù)前行乘陪,別忘了统台,我們構建 ServiceMethod 只是在 invoke 方法內,并且這還只是第一步暂刘。接下來看第二步饺谬。
3.2 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
這里是 new 一個 OkHttpCall 對象,這個 OkHttpCall 是 Retrofit 的 Call,它里面就是做請求的地方募寨,會有 request族展、enqueue 等同步、異步請求方法拔鹰,但是在這里面真正執(zhí)行請求的是 okhttp3.Call 仪缸,即把請求委托給 okHttp 去執(zhí)行。下面簡要看看它的構造方法和一些成員變量吧列肢,因為這里只是 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.3 return 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> {
// 這里在之前創(chuàng)建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
趁熱打鐵,我們執(zhí)行異步請求痕届,看看怎樣切換線程的韧献。
<!-- ExecutorCallbackCall 內部 -->
@Override
public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
// 真正的 Call 去執(zhí)行請求
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 執(zhí)行了 enqueue 操作研叫,而 delegate 就是我們的 OkHttpCall 势决,在 OkHttpCall 里的 enqueue 方法是這樣工作的。
通過 okhttp3.Call call = serviceMethod.toCall(args);
構建一個真正執(zhí)行請求的 Call 蓝撇,即把請求交給 okhttp 去完成果复。而構建一個 Call 利用到了 ServiceMethod 中的 ParameterHandler 對象,這個對象是用來處理參數的渤昌。 它會把具體參數的值與 RequestBuilder 綁定起來虽抄。當然也用到了 ServiceMethod 自己,ServiceMethod 類似請求響應的大管家独柑。
別忘了拿到響應后迈窟,在 okhttp3.Callback 中會去調用 response = parseResponse(rawResponse);
將響應轉換成自己想要的格式,即定義的 Converter 忌栅。
到這里終于結束了车酣,當然在響應解析這里還有許多沒講曲稼,但是 Retrofit 一個主體的流程已經走完了。真累湖员。贫悄。。
沒啥總結的了娘摔,這篇文章只是用來跟蹤具體的源碼窄坦,具體到每一句代碼都有解釋。至于 Retrofit 的設計思路凳寺,別的文章都有講鸭津。
總之,在自己跟著分析完這么一大段后肠缨,已經對 Retrofit 相當熟悉了逆趋,遇到問題,相信也可以定位到源碼中去找到問題的根源晒奕,然后解決父泳,至此,目標已達成吴汪。
參考
https://blog.csdn.net/carson_ho/article/details/73732115
http://www.reibang.com/p/fb8d21978e38
https://blog.csdn.net/justloveyou_/article/details/72783008
https://imququ.com/post/four-ways-to-post-data-in-http.html