目錄
前言
怎樣用Retrofit請(qǐng)求網(wǎng)絡(luò)
Retorfit是如何創(chuàng)建的
請(qǐng)求接口的實(shí)例是如何創(chuàng)建出來(lái)的
Call到底是什么
5.1 ServiceMethod的創(chuàng)建
5.2 Call的創(chuàng)建
5.3 總結(jié)
Call的enqueue方法到底干了什么
遺留
1.前言
近些天回想起工作這幾年阁最,感覺(jué)一事無(wú)成戒祠。俗話說(shuō),就算是咸魚(yú)速种,也要做一條有理想的咸魚(yú)姜盈。因此,訂了一個(gè)長(zhǎng)期的計(jì)劃:博客配阵。
為何選擇Retrofit作為人生中的第一篇博客馏颂?
- Retrofit太火了示血,在最新的2017Android框架中Retrofit排名第一
- Retrofit是對(duì)OkHttp的封裝。作為一個(gè)封裝庫(kù)救拉,它用了大量的設(shè)計(jì)模式难审,有很多值得借鑒的地方
- 代碼量少,相對(duì)簡(jiǎn)單
在讀這篇文章前亿絮,假設(shè)你已經(jīng)掌握了
- Retrofit如何使用
分析源碼一般都有一根主線告喊,本文打算從Retrofit最基本的用法開(kāi)始,一步一步深入了解Retrofit全貌派昧。
2.怎樣用Retrofit請(qǐng)求網(wǎng)絡(luò)
一般我們使用Retrofit需要以下五步:
- 定義請(qǐng)求接口
- 創(chuàng)建Retrofit實(shí)例
- 獲取請(qǐng)求接口的實(shí)例
- 獲取Call對(duì)象
- 同步或異步請(qǐng)求
//1.定義請(qǐng)求接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
//2.創(chuàng)建Retrofit實(shí)例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
//3.通過(guò)Retrofit實(shí)例獲取請(qǐng)求接口實(shí)例(動(dòng)態(tài)代理)
GitHubService service = retrofit.create(GitHubService.class);
//4.獲取Call對(duì)象
Call<List<Repo>> call = service.listRepos("octocat");
//5.異步請(qǐng)求
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
//doSometionSuccess
...
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
//doSometionError
...
}
});
我們將會(huì)以上述代碼為導(dǎo)火索來(lái)分析源碼黔姜。針對(duì)上述代碼我們先提出以下幾個(gè)問(wèn)題,分別對(duì)應(yīng)代碼注釋中的2 3 4 5對(duì)應(yīng)的代碼:
- Retrofit是如何創(chuàng)建的
- 請(qǐng)求接口的實(shí)例是如何創(chuàng)建出來(lái)的
- Call到底是什么
- Call的enqueue方法到底干了什么
我會(huì)在每節(jié)的開(kāi)始處附上每個(gè)問(wèn)題對(duì)應(yīng)的代碼
3.Retorfit是如何創(chuàng)建的
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
只要稍微了解Build模式的童鞋都能一眼看出來(lái)蒂萎,Retrofit是通過(guò)Build模式構(gòu)建的秆吵。關(guān)于Retrofit中的那些設(shè)計(jì)模式,我打算另起篇幅介紹五慈,這里就不敘述了纳寂。
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
private final Platform platform;
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);
}
這里我先簡(jiǎn)單介紹一下各個(gè)參數(shù)的作用:
- callFactory,前面介紹了Retrofit是對(duì)OkHttp的封裝豺撑,callFactory是Okhttp3提供的類烈疚,用來(lái)自定義OkHttpClient()。
- callbackExecutor聪轿,請(qǐng)求完成后爷肝,用來(lái)對(duì)回調(diào)過(guò)程進(jìn)行線程控制。默認(rèn)是在主線程中回調(diào)陆错。
- adapterFactories灯抛,它是CallAdapter.Factory的集合。CallAdapter.Factory是一個(gè)工廠音瓷,用來(lái)生產(chǎn)callAdapter对嚼,callAdapter是對(duì)OkHttpCall的適配。至于OkHttpCall是什么绳慎,我們會(huì)在下面的篇幅中會(huì)介紹纵竖。隨便提一句,Retrofit集成RxJava就是通過(guò)CallAdapter.Factory實(shí)現(xiàn)的杏愤。
- converterFactories靡砌,它與adapterFactories類似。不同的是珊楼,它生產(chǎn)的Converter可以控制請(qǐng)求結(jié)果的解析通殃。例如,進(jìn)行JSON還是XML解析厕宗。
- validateEagerly默認(rèn)為false画舌,validateEagerly參數(shù)如果我們?cè)谂渲玫臅r(shí)候設(shè)置為true的時(shí)候堕担,程序是在做一個(gè)預(yù)處理的操作,會(huì)提前解析請(qǐng)求接口中定義的方法曲聂,生產(chǎn)MethodHandler并緩存霹购。
- Platform,Retrofit希望是一個(gè)跨平臺(tái)的網(wǎng)絡(luò)請(qǐng)求庫(kù)朋腋,因此它定義了Platform接口厕鹃。每個(gè)平臺(tái)都提供了默認(rèn)的callbackExecutor與CallAdapter.Factory實(shí)現(xiàn)。
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);
}
}
4.請(qǐng)求接口的實(shí)例是如何創(chuàng)建出來(lái)的
GitHubService service = retrofit.create(GitHubService.class);
我們看一下Retrofit的create方法乍丈。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//動(dòng)態(tài)代理,返回的是T類型的對(duì)象把将。
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);
}
});
}
我們先暫時(shí)不去分析eagerlyValidateMethods(service)方法轻专,因?yàn)樗雌饋?lái)即使validateEagerly為false,我們的程序仍能正常運(yùn)行察蹲。
Proxy.newProxyInstance()生成了一個(gè)動(dòng)態(tài)代理對(duì)象请垛,而InvocationHandler可以攔截這個(gè)對(duì)象的所有方法。這么說(shuō)可能有些抽象洽议,你可以簡(jiǎn)單的認(rèn)為以下這兩段代碼等價(jià)宗收。
GitHubService service = retrofit.create(GitHubService.class)
GitHubService service = new GitHubService() {
//創(chuàng)建InvocationHandler對(duì)象
InvocationHandler invocationHandler = 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);
}
};
//調(diào)用listRepos方法其實(shí)是調(diào)用InvocationHandler的invoke方法,參數(shù)分別為:當(dāng)前GitHubService對(duì)象亚兄,listRepos()方法對(duì)象混稽,listRepos()傳入的參數(shù)
@Override
public Call<List<String>> listRepos(@Path("user") String user) {
return invocationHandler.invoke(this, GitHubService.class.getMethod("listRepos"), user);
}
}
5.Call到底是什么
Call<List<Repo>> call = service.listRepos("octocat");
service.listRepos()方法其實(shí)調(diào)用了invocationHandler的invoke()方法。其核心代碼僅有三行审胚。
//ServiceMethod的創(chuàng)建
ServiceMethod serviceMethod = loadServiceMethod(method);
//Call的創(chuàng)建
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
這部分將分為兩部分介紹匈勋,ServiceMethod的創(chuàng)建和Call的創(chuàng)建。
5.1 ServiceMethod的創(chuàng)建
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;
}
loadServiceMethod是為了創(chuàng)建ServiceMethod膳叨,然后將其放入的緩存中洽洁,緩存的Key為Method對(duì)象。ServiceMethod同樣是通過(guò)Builder模式創(chuàng)建的菲嘴。上述方法中的this指的是當(dāng)前Retrofit對(duì)象饿自。因此可以推測(cè)ServiceMethod.Builder持有了Retrofit對(duì)象和Method對(duì)象的引用。事實(shí)也的確如此龄坪,如下:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
這段代碼主要是保存了Retrofit的實(shí)例對(duì)象昭雌,method對(duì)象,method上的注解悉默,method參數(shù)注解城豁,method參數(shù)類型。
public ServiceMethod build () {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// ......
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
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.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
//...
return new ServiceMethod<>(this);
}
createCallAdapter主要是通過(guò)Builder中保存的retrofit對(duì)象抄课,找到CallAdapterFactory集合唱星,遍歷集合雳旅,根據(jù)Method的返回值類型和Method上的注解,找到合適的callAdapter间聊。callAdapter是一個(gè)接口攒盈,定義了兩個(gè)方法:Type responseType(),返回值類型哎榴;<R> T adapt(Call<R> call)型豁,用來(lái)返回代理對(duì)象。我們看一下Platform中默認(rèn)提供的CallAdapterFactory尚蝌。
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);
}
};
}
}
這樣ServiceMethod內(nèi)部就創(chuàng)建了一個(gè)匿名的CallAdapter對(duì)象迎变。
createResponseConverter與createCallAdapter過(guò)程類似,不再贅述飘言。build()方法中其余的代碼主要是通過(guò)解析注解和拼接參數(shù)來(lái)生成Http請(qǐng)求數(shù)據(jù)衣形,如:get、post姿鸿、delete等方法谆吴、請(qǐng)求Url、參數(shù)苛预。至此句狼,ServiceMethod中擁有了callAdapter、responseConverter以及和網(wǎng)絡(luò)請(qǐng)求有關(guān)的url热某、parameter腻菇、method等。loadServiceMethod介紹完畢苫拍。
5.2 Call的創(chuàng)建
我們看一下這兩段代碼的意思
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
OkHttpCall是Call的實(shí)現(xiàn)類芜繁,它有一個(gè)ServiceMethod對(duì)象和一個(gè)請(qǐng)求參數(shù)的數(shù)組。如下:
final class OkHttpCall<T> implements Call<T> {
//構(gòu)造方法
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
}
我們?cè)?ServiceMethod的創(chuàng)建 中介紹了serviceMethod.callAdapter是一個(gè)匿名類绒极。它的adapt方法返回了一個(gè)ExecutorCallbackCall對(duì)象骏令。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
這是典型的裝飾器模式,ExecutorCallbackCall是對(duì)OkHttpCall對(duì)象的裝飾垄提。它內(nèi)部的delegate對(duì)象就是上面分析的OkHttpCall對(duì)象榔袋。callbackExecutor是我們?cè)?* Retorfit是如何創(chuàng)建的 **中介紹的callbackExecutor對(duì)象。Platform提供了默認(rèn)實(shí)現(xiàn)MainThreadExecutor铡俐。MainThreadExecutor很簡(jiǎn)單凰兑,它將接收到的Runnable對(duì)象交給主線程的Handler去處理。
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
5.3 總結(jié)
我們返回的call對(duì)象其實(shí)是一個(gè)ExecutorCallbackCall對(duì)象审丘,它實(shí)現(xiàn)了Call接口吏够,是對(duì)OkHttpCall的裝飾,并且內(nèi)部持有了callbackExecutor對(duì)象。OkHttpCall也實(shí)現(xiàn)了Call接口锅知,它有持有了一個(gè)ServiceMethod對(duì)象和一個(gè)請(qǐng)求參數(shù)的數(shù)組的引用播急。ServiceMethod封裝了請(qǐng)求的細(xì)節(jié),如get售睹、post桩警、delete等方法、請(qǐng)求Url昌妹、參數(shù)等捶枢,同時(shí)callAdapter和responseConverter也是在ServiceMethod中創(chuàng)建的。
6.Call的enqueue方法到底干了什么
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
//doSometionSuccess
...
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
//doSometionError
...
}
});
在上節(jié)中飞崖,我們知道了返回的Call實(shí)例是ExecutorCallbackCall類型的對(duì)象烂叔。那我們看一下ExecutorCallbackCall的enqueue()方法。
public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, t);
}
});
}
});
}
我們先來(lái)介紹一下這段代碼中出現(xiàn)的變量固歪,然后再來(lái)分析整段代碼的含義长已。
- delegate是上一節(jié)介紹的OkHttpCall對(duì)象。
- callbackExecutor是上一節(jié)介紹的MainThreadExecutor對(duì)象昼牛。
這段代碼更能說(shuō)明ExecutorCallbackCall采用了裝飾模式,它生成了一個(gè)新的Callback對(duì)象康聂。這個(gè)新Callback有兩個(gè)作用贰健。一,將回調(diào)切換到callbackExecutor中執(zhí)行恬汁。二伶椿,增加了取消操作。最終氓侧,這個(gè)新的Callback對(duì)象交給OkHttpCall對(duì)象的enqueue方法去處理脊另。
public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
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();
}
}
});
}
OkHttpCall是對(duì)Okhttp3.Call的包裝,OkHttpCall內(nèi)部有一個(gè)類型為Okhttp3.Call的rawCall對(duì)象约巷。rawCall的創(chuàng)建偎痛,是通過(guò)Retrofit初始化時(shí),傳入的OkHttpClient創(chuàng)建的(若為空独郎,系統(tǒng)提供了默認(rèn)的)踩麦。在enqueue方法中利用rawCall對(duì)象發(fā)起請(qǐng)求。請(qǐng)求成功后氓癌,會(huì)通過(guò)parseResponse(rawResponse)方法對(duì)原始數(shù)據(jù)進(jìn)行解析谓谦。
而parseResponse()的核心代碼只有一句話。
T body = serviceMethod.toResponse(catchingBody);
不錯(cuò)贪婉,它調(diào)用了serviceMethod的toResponse方法反粥。而serviceMethod的toResponse方法也只有一句話。
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
還記得我們?cè)?ServiceMethod的創(chuàng)建 提到的,和callAdapter創(chuàng)建過(guò)程類似的responseConverter嗎才顿?沒(méi)錯(cuò)莫湘,就是它。
7.遺留
我們?cè)?* 請(qǐng)求接口的實(shí)例是如何創(chuàng)建出來(lái)的 ** 這節(jié)中遺留下一段代碼
if (validateEagerly) {
eagerlyValidateMethods(service);
}
我們現(xiàn)在回過(guò)頭來(lái)看一下這段代碼
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
loadServiceMethod是不是很熟悉娜膘。不要告訴我你已經(jīng)忘了!!! 好吧逊脯,那我來(lái)告訴你,ServiceMethod的創(chuàng)建 中我們最先介紹的就是這個(gè)方法竣贪。eagerlyValidateMethods是一個(gè)對(duì)service中的方法提前解析军洼,將其緩存的過(guò)程。所以我們可以通過(guò)設(shè)置validateEagerly=true來(lái)提高請(qǐng)求效率演怎。
哇匕争,終于完了,寫(xiě)博客是真的累啊
真的累啊
真累啊
累啊
累R8噬!!