1. 概述
Retrofit和OkHttp都來自于Square公司,而且都是在用來處理HTTP請求的,先來看下用OkHttp處理HTTP請求的實現:
String url = "https://api.github.com/users/octocat/repos";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new okhttp3.Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
List<Repo> repos = JSON.parseArray(response.body().toString(), Repo.class);
}
});
可以看到在發起HTTP請求之前需要構造Request對象,請求完成后還需要將Response轉化成所需要的對象,如果每一個HTTP請求都要這么復雜,那對于需要成百上千個HTTP請求的應用來說無疑是多了很多的重復代碼,對于一個追求完美的程序員來說是無法容忍的;因此Square公司推出了Retrofit框架,Retrofit的中文意思是改造,顧名思義就是在OkHttp的基礎上的進行的一次升級和封裝,Retrofit通過定義接口的方式來構建Request對象,通過Converter將Response轉化為需要的對象,這就是Retrofit存在的意義,下面看一下通過Retrofit框架實現與上面一樣的功能:
// 構建Retrofit實例,一般都是通過單例模式創建的,所以一般會創建一個Manager類來創建和管理Retrofit對象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
// 添加一個用來創建Converter實例的工廠,該工廠是針對于json字符串的
.addConverterFactory(FastJsonConverterFactory.create())
.build();
// 在一個項目中,都是會對HTTP請求進行分類的,每一個分類都會創建一個與之對應的一個接口(比如下面的GitHubService接口)
// 每一個接口包含多個方法,每一個方法對應于一個HTTP請求(執行的時候會根據方法來構建Request對象)
// 每一個方法的返回值都是一個Call對象,默認是ExecutorCallbackCall對象,針對于rxjava2就是返回的就是Observable對象
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
// 下面就是發起HTTP的代碼,相比于OkHttp來說簡化了Request對象的構建和Response的解析
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, retrofit2.Response<List<Repo>> response) {
List<Repo> repoList = response.body();
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
上面代碼中提到的Call對象,其實是對OkHttp中RealCall的封裝,這樣的設計也體現了一種設計模式(門面模式):
門面模式(Facade Pattern)也叫做外觀模式,是一種比較常用的封裝模式,其定義如下:
Provide a unified interface to a set of interfaces in a subsystem.
Facade defines a higher-level interface that makes the subsystem easier to use.
(要求一個子系統的外部和內部的通信必須通過一個統一的對象進行。門面模式提供一個高層次的接口,
使得子系統更易于使用。)
所以Retrofit示例代碼中提到的Call對象就是門面模式中說到的統一的對象。
Retrofit源碼地址
2. 預備知識
2.1 Java編程語言中的Type
在Retrofit中會對Method實例(對應上面的例子,就是GitHubService的listRepos方法對應的實例)進行解析,因此會對Method實例的返回值類型和參數類型進行解析,所以這里帶大家了解一下Java編程語言中的Type:
Type是Java 編程語言中所有類型的公共高級接口,Java 編程語言中的類型包括(其中后面四種類型是泛型的三種表現形式):
1 基本類型:也就是我們所說的java中的8中基本類型。
2 原始類型(raw types):對應Class。
3 類型變量(TypeVariable):
該接口代表各種類型變量的公共接口,如Collection<T>中的T就是一個類型變量。
主要方法:
Type[] getBounds():獲取上邊界Type數組。
4 參數化類型(ParameterizedType):
該接口代表參數化類型,例如Collection<String>。
主要方法:
Type[] getActualTypeArguments():獲取參數化類型中的所有類型的數組。
Type getRawType():獲取參數化類型中<>前面的類型。
5 泛型數組類型(GenericArrayType):
該接口代表一種數組類型,其組件類型為參數化類型或類型變量
,例如參數化類型數組Map<String, String>[]map和類型變量數組T[] arr。
主要方法:
Type getGenericComponentType():返回其組件類型。
除了上面泛型的三種表現形式外還有一種并不屬于Java類型的表達形式:
通配符類型(WildcardType):
該接口代表通配符類型表達式,例如 如 ?、? extends Number 或 ? super Integer.
主要方法:
Type[] getUpperBounds():獲取上邊界Type數組。
Type[] getLowerBounds():獲取下邊界Type數組。
3. 源碼分析
我會根據上面的例子解析分析,因此在分析的過程中會依賴上面的代碼
首先看一下Retrofit處理http請求的時序圖:
3.1 構建Retrofit實例
上圖中的前8步通過建造者模式構建了一個Retrofit實例
建造者模式(Builder Pattern,也叫生成器模式)的定義:
Separate the construction of a complex object from its representation so that
the same construction process can create different representations.
(將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。)
構建的過程也是對Retrofit實例進行初始化的過程,初始化的結果:
1> callFactory : 顧名思義是用來創建Call對象的,默認為OkHttpClient類型對象,沒錯,這就就是OkHttp中的OkHttpClient,通常情況下不會修改該默認值。
2> baseUrl:默認值為HttpUrl.parse("https://api.github.com/"),通常情況下在同一個項目中所有的HTTP請求URL的 protocol :// hostname[:port] 部分是相同的,即在項目中baseUrl對應的值,如果一個項目中HTTP請求URL的 protocol :// hostname[:port] 部分多余一種的話,就需要多個Retrofit對象與之對應。
3> converterFactories:顧名思義是用來保存Converter.Factory對象的容器(Converter.Factory是用來創建Converter對象的,Converter有兩個常用的方法requestBodyConverter和responseBodyConverter,說到這里相信大家應該明白了Converter的作用了),默認只包含一個BuiltInConverters對象,通過第4步就可以在converterFactories集合的末尾添加一個FastJsonConverterFactory對象,這也是為什么接口的方法中@Body注解的參數是RequestBody類型時,就不會調用FastJsonRequestBodyConverter的convert方法的原因。
4> callAdapterFactories:顧名思義是用來保存CallAdapter.Factory對象的容器(CallAdapter.Factory是用來創建CallAdapter對象的,CallAdapter的adapt方法會得到Call<R>對象的代理,這里就用到了裝飾者模式),默認只包含一個ExecutorCallAdapterFactory對象,通過第5步就可以在ExecutorCallAdapterFactory對象的前面插入一個RxJava2CallAdapterFactory對象。
5> callbackExecutor:顧名思義就是用來控制Retrofit示例代碼中Callback執行的線程,默認值為MainThreadExecutor,即默認在主線程執行。
上面5條都是根據源碼得到的,不可能在該篇文章中完全分析所有細節,只有自己親自查閱源碼才會收獲更多,我只會點到為止,這樣你們可以更加快速的翻閱源。
3.2 創建GitHubService接口的實例
接下來看一下第9、10步的源碼:
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);
}
});
}
可以看到使用了動態代理模式為GitHubService接口創建實例。
代理模式(Proxy Pattern)是一個使用率非常高的模式,其定義如下:
Provide a surrogate or placeholder for another object to control access to it.
(為其他對象提供一種代理以控制對這個對象的訪問)
動態代理:
動態代理是在實現階段不用關心代理誰,而在運行階段才指定代理哪一個對象。
3.3 執行GitHubService接口中的方法
第11步調用GitHubService接口中的方法,此時InvocationHandler的invoke方法被執行(即第12步),對應于上面的例子listRepos方法對應的就是invoke方法中的參數method。
3.3.1 根據Method實例構建ServiceMethod實例
第13步loadServiceMethod方法被調用,loadServiceMethod方法會根據Method實例構建與之對應的ServiceMethod實例:
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;
}
為了提高運行時的效率,構建ServiceMethod實例的過程中使用了緩存機制,對于已經構建過ServiceMethod實例的Method實例,直接將緩存中與之對應的ServiceMethod實例返回,接下來的14到33步就是根據Method實例構建ServiceMethod實例的過程:
// 第14步對應的代碼
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 對應與上面例子,methodAnnotations保存的時GitHubService接口的listRepos方法的注解(即@GET("users/{user}/repos"))
this.methodAnnotations = method.getAnnotations();
// 對應與上面例子,parameterTypes保存的是GitHubService接口中listRepos方法的所以參數的類型
this.parameterTypes = method.getGenericParameterTypes();
// 對應與上面例子,parameterAnnotationsArray保存的是GitHubService接口中listRepos方法的所以參數的注解
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
// 第15對應的代碼
public ServiceMethod build() {
// 第16步到21步,完成CallAdapter實例的創建,默認為ExecutorCallAdapterFactory創建
// 的CallAdapter實例,對于rxjava2而言對應的是RxJava2CallAdapter實例
callAdapter = createCallAdapter();
// 對應于上面的例子,responseType代表的是List<Repo>
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?");
}
// 第22步到27步,完成 Converter<ResponseBody, T> responseConverter 實例的創建,
// 對于fastjson而言對應的是FastJsonResponseBodyConverter實例
// ,用于將ResponseBody中的json字符串轉化成指定類型的對象
responseConverter = createResponseConverter();
// 第28到第30步,用于解析方法上的注解,對應于上面的例子就是對@GET("users/{user}/repos")的解析
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 方法上的注解解析完成后,httpMethod為空代表方法上沒有@GET, @POST等類型的注解
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
// 對于沒有請求體的情況,方法上不應該有@Multipart和@FormUrlEncoded注解
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).");
}
}
// 第31、32步 完成方法參數上注解的解析,對應于上面的例子就是對@Path("user")的解析
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
// 對參數的類型進行檢查,不應該包含 類型變量 和 通配符類型,具體可以參考2.1
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);
}
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.3.2 發起http請求
// 第35步,創建OkHttpCall實例
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
// 第36步,默認情況下callAdapter代表ExecutorCallAdapterFactory創建的CallAdapter實例
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
// 第37步,返回ExecutorCallbackCall實例
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
// 第39步enqueue方法發起http請求
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
// delegate是OkHttpCall實例,enqueue方法中會創建Request對象
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(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);
}
});
}
});
}
4 細節分析
第3步中只是粗略的分析了Retrofit處理HTTP請求的大致流程,那么這一節就會詳細分析一些關鍵點
4.1 CallAdapter實例的創建
第16步到21步,完成CallAdapter實例的創建,下面是Google官方對CallAdapter的adapt方法的注解:
/**
* Returns an instance of {@code T} which delegates to {@code call}.
*/
T adapt(Call<R> call);
這句話也充分的說明CallAdapter是用來干嘛的了,同時也體現一種設計模式(裝飾者模式),接下來看一下16步createCallAdapter方法的源碼:
private CallAdapter<T, R> createCallAdapter() {
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.");
}
// 獲取方法上的注解,對應于上面的示例就是獲取listRepos方法的注解 @GET("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);
}
}
上面的蛛絲已經很清楚來,下面直接看第17、18步的源碼:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
// 因為skipPast為null,所以start為0,
int start = callAdapterFactories.indexOf(skipPast) + 1;
// 默認情況下callAdapterFactories包含一個ExecutorCallAdapterFactory對象,
// 對于RxJava2CallAdapterFactory對象,有興趣的同學可以自己研究一下,后面的分析過程中也只會基于ExecutorCallAdapterFactory對象進行分析。
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
// 如果沒有找到合適的CallAdapter實例,就會拋出IllegalArgumentException異常
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());
}
接下來看ExecutorCallAdapterFactory的get方法,即第19步:
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 如果返回值的類型不是Call類型,返回null,那么上面第18步中就會拋出IllegalArgumentException異常
if (getRawType(returnType) != Call.class) {
return null;
}
// returnType必須是參數化類型(對應于上面的例子,returnType代表的是Call<List<Repo>>),否者會拋出IllegalArgumentException異常
// responseType是參數化類型中的類型,對應于上面的例子,responseType代表的是List<Repo>
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);
}
};
}
到這里CallAdapter實例的創建完成了,總結一下關鍵點:
1> 方法的返回值類型:必須是參數化類型,并且rawtype為Call類型,并且不能包含類型變量和通配符表達式,否者會拋出異常;
2> CallAdapter是用來為Call<R>創建一個代理對象T,默認情況下T是ExecutorCallbackCall類型,對應于rxjava2情況下T通常是BodyObservable類型。
4.2 Converter<ResponseBody, T>實例的創建
第22步到27步,完成 Converter<ResponseBody, T>實例的創建,接下來看一下第22步的源碼:
// 該方法返回的Converter對象是用來將ResponseBody轉化成需要類型的對象,
// 對應于上面的示例就是轉化成<List<Repo>類型的對象。
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
// 第19步中提到過,對應于上面的例子,responseType代表的是List<Repo>
// 對應于上面的例子,annotations對應于listRepos方法的注解 @GET("users/{user}/repos")
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);
}
}
接下來看23、24步:
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
// 因為skipPast為null,所以start為0
int start = converterFactories.indexOf(skipPast) + 1;
// 默認情況下converterFactories包含一個BuiltInConverters對象,
// 在項目中一般都會配置一個針對于fastjson的FastJsonResponseBodyConverter對象。
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
// 如果沒有找到合適的Converter<ResponseBody, T>實例,就會拋出IllegalArgumentException異常
StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
.append(type)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = converterFactories.size(); i < count; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
接下來看一下25步:
// 如果方法的返回值為Call<ResponseBody>,那么BuiltInConverters的responseBodyConverter方法的返回值不會為null
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;
}
// 對應于上面的例子,listRepos方法的返回值不是Call<ResponseBody>類型,
// 那么FastJsonConverterFactory的responseBodyConverter方法的返回值會被使用
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return new FastJsonResponseBodyConverter<>(type, mParserConfig, featureValues, features);
}
到這里Converter<ResponseBody, T>實例的創建完成了,總結一下關鍵點:
1> Converter<ResponseBody, T>是用來將ResponseBody對象轉化成方法的返回值類型中的參數類型,對應于上面的例子,就是List<Repo>類型。
2> 如果方法的返回值為Call<ResponseBody>,那么BuiltInConverters的responseBodyConverter方法的返回值不會為null并且會被使用;否者FastJsonResponseBodyConverter對象會被使用。
4.3 OkHttpCall發起HTTP請求
OkHttpCall的enqueue方法如下:
@Override 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 {
// 創建OkHttp中的RealCall實例
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
// 調用RealCall的enqueue方法發起HTTP請求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 請求成功后,對響應體進行解析
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
// 執行callback的onResponse方法
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
// 執行callback的onFailure方法
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
接下來看一下createRawCall和parseResponse方法:
private okhttp3.Call createRawCall() throws IOException {
// 根據方法的參數構建Request實例,并且使用Request實例作為參數構建RealCall實例
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
// 對應與上面的例子,下面這句代碼會使用Converter<ResponseBody, T>實例將catchingBody轉化為List<Repo>類型對象。
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
到這里OkHttpCall發起HTTP請求的過程分析完了。
5 總結
到這里源碼已經分析完了,Retrofit處理HTTP請求主要流程為(為了便于說明,會用到上面的例子):
1> 首先創建Retrofit實例和GitHubService接口的實例。
2> 然后調用GitHubService接口中的listRepos方法(對listRepos進行解析,得到與之對應serviceMethod對象,然后調用serviceMethod對象的adapt方法得到listRepos方法的Call<List<Repo>>類型返回值)。
3> 調用Call的enqueue方法發起請求。