
前言
使用Retrofit已經(jīng)一段時(shí)間了,這貨挺好用的,還很特別,特別是使用接口來定義請求方式,這用法讓我對它的源碼很是好奇。今天就來看看源碼吧...
參靠源碼retrofit:2.0.2
基本的用法
首先來簡單得實(shí)現(xiàn)一次GET請求
- 定義接口
interface Service {
@GET("News")
Call<ResponseBody> getNews(
@Query("limit") String limit);
}
- 完成一次請求
Retrofit retrofit =new Retrofit.Builder()
.baseUrl("http://hcy.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Service service = retrofit.create(Service.class);
Call<ResponseBody> call = service.getNews("10");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.i(TAG, "onResponse");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i(TAG, "onFailure");
}
});
根據(jù)這個(gè)請求一步步進(jìn)行解析,接下來就是這篇的重點(diǎn),Retrfit內(nèi)部的實(shí)現(xiàn)。
還不會(huì)用Retrofit?少年去看看Retrofit 2.0 的使用吧?。?!
源碼解析
這里分別說明了都調(diào)用了哪些源碼,都是怎么實(shí)現(xiàn)的。(里面涉及到一些設(shè)計(jì)模式,什么?你還不知道有什么設(shè)計(jì)模式?下面會(huì)涉及到Builder模式(外觀模式)、工廠模式、動(dòng)態(tài)代理。stay 的 Retrofit分析-經(jīng)典設(shè)計(jì)模式)
-
1.Retrofit的創(chuàng)建
首先看下Retrofit對象的創(chuàng)建
Retrofit retrofit =new Retrofit.Builder()
.baseUrl("http://hcy.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.build();
這里使用了Builder設(shè)計(jì)模式(外觀模式),Retrofit.Builder是Retrofit的一個(gè)內(nèi)部類,用來配置一些成員變量,這里配置了baseUrl和ConverterFactory(對象的序列號/反序列化組件),然后創(chuàng)建一個(gè)Retrofit對象。這些代碼都做了什么,下面一一說明。
-
Retrofit.Builder()
看看new Retrofit.Builder()調(diào)用的代碼
public Builder() {
this(Platform.get());
}
Platform.get()又是什么?抱著一貫的好奇,點(diǎn)進(jìn)去看看。主要代碼如下
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) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
機(jī)智的你一定能看出來,主要就是這個(gè)findPlatform()方法。這里面的代碼,就是判斷當(dāng)前運(yùn)行的平臺。可以看到里面有Android、Java8、IOS。等下,怎會(huì)有IOS,什么鬼(為什么會(huì)有IOS就交給你去研究了)。
我們在Android上運(yùn)行的話,就調(diào)用了return new Android()。進(jìn)一步往下看,Android()是什么
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
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);
}
}
}
他繼承了Platform重寫了defaultCallbackExecutor和defaultCallAdapterFactory方法。
defaultCallbackExecutor:返回的是用于執(zhí)行 Callback 的 線程池??梢钥吹?strong>MainThreadExecutor 獲取了主線程的 Looper 并構(gòu)造了一個(gè)主線程的 Handler,調(diào)用 Callback 時(shí)會(huì)將該請求 post 到主線程上去執(zhí)行。這就解釋了為什么請求后完成的回調(diào)都是在主線中。
defaultCallAdapterFactory:將返回的適配類型默認(rèn)為Call類型(如果使用RxJava的話,就可以通過配置.addCallAdapterFactory(RxJavaCallAdapterFactory.create())將配置類型改成Observable。)
- .baseUrl("http://hcy.com/api/")
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
這里有兩個(gè)重載的方法,創(chuàng)建了okhttp3 的 HttpUrl 實(shí)例。
- .addConverterFactory(GsonConverterFactory.create())
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
往轉(zhuǎn)換工廠集合中添加了我們指定的轉(zhuǎn)換工廠,最后將返回的數(shù)據(jù)類型轉(zhuǎn)換成對應(yīng)的實(shí)體類對象的Converter類型。在我們的例子里面 GsonConverterFactory 將選用 GsonConverter 來轉(zhuǎn)換。
- .build();
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
看最后一句
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
這里才是創(chuàng)建Retrofit對象的地方,之前的只是一些配置。里面的參數(shù):
callFactory(Call工廠):看到了吧callFactory = new OkHttpClient();,這里用的是okhttp3;
baseUrl(服務(wù)器基本地址):這個(gè)我們上面配置過;
converterFactories(對象的序列號/反序列化組件):我們上面配置過。
adapterFactories(適配類型)、callbackExecutor(執(zhí)行 Callback 的線程池):從我們上面提到的platform中獲取默認(rèn)值。
validateEagerly(標(biāo)識):先不說,后面會(huì)用到
- 總:完成基本的配置,創(chuàng)建一個(gè)Retrofit對象
2.Service的創(chuàng)建以及接口的調(diào)用
我們創(chuàng)建了一個(gè)接口的實(shí)例,用于調(diào)用接口。看下代碼吧
Service service = retrofit.create(Service.class);
Call<ResponseBody> call = service.getNews("10");
Service是之前定義的接口,這里代碼通過retrofit.create(Service.class)就得到了Service的實(shí)例,他是怎么做到的?進(jìn)入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, 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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
看到這里的代碼,相信有些同學(xué)開始懵逼了,Proxy.newProxyInstance...這是什么鬼?這代碼鬼認(rèn)識...

哈哈,這叫動(dòng)態(tài)代理,可以生成接口對應(yīng)的對象,之后使用這個(gè)對象調(diào)用方法時(shí)都會(huì)調(diào)用InvocationHandler中的invoke方法。(我不會(huì)告訴你們我一開始也是懵逼的~~)
對動(dòng)態(tài)代理還不熟悉的看看這里: 公共技術(shù)點(diǎn)之 Java 動(dòng)態(tài)代理
下面我們來一步步分析這個(gè)create方法:
-
Utils.validateServiceInterface(service);
源碼我就不貼出來了,這個(gè)方法主要就是判斷了參數(shù)service是否為Interface,是否包含了其他接口; -
eagerlyValidateMethods(service);:
這里根據(jù)validateEagerly判斷是否需要提前創(chuàng)建ServiceMethod,調(diào)用loadServiceMethod()方法,這個(gè)方法我們自后面會(huì)講到。 -
invoke
接下來看Proxy.newProxyInstance中重寫的方法invoke,這才是這次解析的重點(diǎn)??纯蠢锩娑甲隽耸裁?- 代碼
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
第一個(gè)if用來判斷的是否為Object方法,如果是就直調(diào)用;
第二個(gè)if則是判斷平臺,不過進(jìn)入.isDefaultMethod(method)源碼可以看到,直接返回false,應(yīng)該是為了之后的擴(kuò)展用的。
-
ServiceMethod serviceMethod = loadServiceMethod(method);
創(chuàng)建了一個(gè)ServiceMethod對象,看下loadServiceMethod的源碼
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMethod做了三件事:
1.先去serviceMethodCache中查找否存在method(看來這貨是有緩存的,這里采用了LinkedHashMap來緩存這些Method的解析結(jié)果),存在的話跳過第二步;
2.method不存在的話就創(chuàng)建一個(gè),然后添加到緩存中;
3.返回ServiceMethod 對像。
可以看到ServiceMethod也使用了Bulider設(shè)計(jì)模式,繼續(xù)往里面看?看看new ServiceMethod.Builder(this, method).build();都干嘛了?
這里就簡單說說ServiceMethod的功能,再講下去這層次結(jié)果有點(diǎn)深...
ServiceMethod的定義:把對接口中的方法的調(diào)用轉(zhuǎn)化成一次HTTP調(diào)用。
(說人話...)
呃...,就是解析了接口中@GET("News")、@Query("limit") String limit等一些列有關(guān)請求的信息,然后還保存了Retrofit中的一些重要信息,如:
1、callFactory:Call工廠,負(fù)責(zé)創(chuàng)建 HTTP 請求
2、callAdapter:確定返回的retrofit2.Call<T>類型(接口定義時(shí)的返回類型,例子中的Call<ResponseBody>);
3、responseConverter:數(shù)據(jù)轉(zhuǎn)換類型,負(fù)責(zé)將服務(wù)器返回的數(shù)據(jù)(Json、xml等各式)轉(zhuǎn)換成我們需要用到的T類型的對象;
4、parameterHandlers:則負(fù)責(zé)解析 API 定義時(shí)每個(gè)方法的參數(shù),并在構(gòu)造 HTTP 請求時(shí)設(shè)置參數(shù)。(如例子中的@Query("limit")中的limit)
總之就是基本包含了這次請求的全部內(nèi)容
-
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
創(chuàng)建了一個(gè)OkHttpCall 對象,用來發(fā)起請求。OkHttpCall 中有個(gè)我們常用的方法enqueue()
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
okhttp3.Call call;
....
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call,
okhttp3.Response rawResponse) throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
...
});
}
都說Retrofit內(nèi)部是用okhttp實(shí)現(xiàn)請求的,原來在這里,哈哈...
拿著這個(gè)對象我們就可以發(fā)起請求了,不過Retrofit還要適配返回類型,所以還要下面這句代碼。
-
return serviceMethod.callAdapter.adapt(okHttpCall);
這里將我們創(chuàng)建的OkHttpCall 對象適配成對應(yīng)的類型(例子中得到的是Call,如果用RxJava得到的就是Observable)。
3.發(fā)起請求
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.i(TAG, "onResponse");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i(TAG, "onFailure");
}
});
最后就是使用得到的call對象來發(fā)起請求(這個(gè)call是retrofit2.Call)。
通過上面的解析可以知道,這里其實(shí)就是調(diào)用了okhttp3里面的okhttp3.Call來完成這次請求。
還不滿足?想知道okhttp3是怎么完成請求的?
自己去研究吧,少年~~

以上有錯(cuò)之處,還望不吝賜教。謝謝??!
參考
拆輪子系列:拆 Retrofit
Retrofit源碼1: 為什么寫一個(gè)interface就可以實(shí)現(xiàn)http請求
Retrofit2 源碼解析
Retrofit 源碼分析之 Retrofit 對象
Retrofit分析-漂亮的解耦套路
Retrofit分析與實(shí)現(xiàn)