分析源碼之前先介紹幾個Retrofit中的概念模庐。
Call,Request,Response昂勉,因為Retrofit中也是使用OkHttp來進行網絡請求的,這幾個概念和OkHttp中的基本類似扫腺,可以看下我在OkHttp源碼分析一篇中開頭對這幾個概念的介紹岗照。
CallAdapter<R, T>
Adapts a {@link Call} with response type {@code R} into the type of {@code T}.
將一個返回類型為R的Call適配為一個T。
Retrofit默認的為Call類型笆环,比方說如果我們將Retrofit和RxJava結合使用谴返,需要返回RxJava的Observable類型,那么我們就要提供相應的CallAdapter來將Call轉化為Observable咧织。
Converter<F, T>
Convert objects to and from their representation in HTTP.
將F類型轉換為T類型嗓袱。
主要用途是將原始請求參數(shù)的類型轉換為okhttp3.RequestBody,以及將okhttp3.ResponseBody轉換為你想要的返回類型习绢。
本篇使用的Retrofit版本是2.4.0渠抹,上代碼,一個Retrofit請求闪萄。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestApi request = retrofit.create(RequestApi.class);
retrofit2.Call<JSONObject> call = request.getCall(word);
call.enqueue(new retrofit2.Callback<JSONObject>() {
@Override
public void onResponse(retrofit2.Call<JSONObject> call, retrofit2.Response<JSONObject> response) {
if (200 == response.code()) {
JSONObject result = response.body();
}
}
@Override
public void onFailure(@NonNull retrofit2.Call<JSONObject> call, Throwable t) {
System.out.println("請求失敗");
System.out.println(t.getMessage());
}
});
RequestApi類
public interface RequestApi {
@POST("translate?doctype=json&jsonversion=&type=&keyfrom=&model=&mid=&imei=&vendor=&screen=&ssid=&network=&abtest=")
@FormUrlEncoded
Call<JSONObject> getCall(@Field("i") String targetSentence);
}
首先梧却,使用建造者模式完成Retrofit的構建。
然后調用Retrofit的create方法構建了RequestApi對象败去,我們看一下create方法放航。
public <T> T create(final Class<T> 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 {
...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
這是一個動態(tài)代理。
接著圆裕,使用代理生成的RequestApi對象調用getCall方法構建Call<JSONObject>對象广鳍。我們來分析一下這個動態(tài)代理內部是如何生成Call<JSONObject>對象的。
第一步調用loadServiceMethod方法來構建了一個ServiceMethod對象吓妆。下圖截取了ServiceMethod類中的域和主要方法赊时。
它的主要作用是將一個接口方法的調用適配為一個http請求。
它的創(chuàng)建使用的也是建造者模式行拢。靜態(tài)類Builder的build方法里面會把我們寫在接口的請求方法里面的各種注解進行解析并且轉化ServiceMethod對象相應的域祖秒。
然后是一個toCall方法,使用ServiceMethod對象的域來創(chuàng)建一個okhttp3.Call舟奠,最終會使用該Call來進行網絡請求竭缝。
我們來看下他的Builder的build方法。方法比較長沼瘫,我省略了好多不重要的代碼抬纸,并且對每一段是干啥的加了注釋。
public ServiceMethod build() {
//創(chuàng)建CallAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
//創(chuàng)建返回結果轉換的Converter
responseConverter = createResponseConverter();
//解析方法上的注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
//解析參數(shù)上的注解
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);
}
看看創(chuàng)建CallAdapter的createCallAdapter()方法晕鹊。
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
...
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
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);
}
}
這里的method就是我們調用的接口中的相關請求方法松却,在我們上面的代碼中就是getCall方法。將它的類型和方法注解傳入retrofit的callAdapter方法來獲取合適的CallAdapter溅话。
跟進retrofit的callAdapter方法晓锻,發(fā)現(xiàn)它調用了nextCallAdapter方法。
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
這里的callAdapterFactories是一個CallAdapter的工廠列表飞几,代碼里面的邏輯是砚哆,在callAdapterFactories中依次進行遍歷,第一個符合條件的將被返回屑墨。
我們在創(chuàng)建Retrofit對象的時候可以向callAdapterFactories添加工廠躁锁,比如如果我們將RxJava和Retrofit聯(lián)合使用,想在interface方法中定義Observable作為返回類型卵史,就需要添加第三方庫中的RxJava2CallAdapterFactory战转。
Retrofit的build代碼中添加了一個默認的DefaultCallAdapterFactory,它響應的類型是Retrofit的Call接口以躯,所以如果我們不添加任何額外的CallAdapterFactory槐秧,那么interface方法中定義的返回類型只能為Call類型。
下面再來看創(chuàng)建返回結果轉換Converter的createResponseConverter方法忧设。
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
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);
}
}
調用了Retrofit的responseBodyConverter方法刁标,跟進去,發(fā)現(xiàn)調用了nextResponseBodyConverter方法址晕。
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
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;
}
}
...
}
這個和獲取CallAdapter的邏輯簡直一模一樣膀懈。converterFactories是一個Converter.Factory列表,一次遍歷選取第一個符合條件的進行返回谨垃。
再看解析方法注解的方法parseMethodAnnotation
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
...
}
調用了parseHttpMethodAndPath方法启搂,根據(jù)不同的注解類型傳入不同的參數(shù)。
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
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;
}
// 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;
this.relativeUrlParamNames = parsePathParameters(value);
}
在這里解析出來httpMethod刘陶,hasBody狐血,relativeUrl,relativeUrlParamNames等參數(shù)易核。
解析參數(shù)注解的部分匈织,和解析類注解的部分相似,會根據(jù)參數(shù)上的注解的不同牡直,生成不同的參數(shù)處理器保存到了parameterHandlers域中缀匕。
ServiceMethod的Builder的build方法主要做的事情就是這么多了,build方法結束之后碰逸,其構建的ServiceMethod對象中的域就都被賦值完成了乡小。
我們再回到之前的動態(tài)代理的方法,看看ServiceMethod構建完成之后饵史,構建的OkHttpCall是個啥满钟。
final class OkHttpCall<T> implements Call<T> {
...
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
...
}
嗯胜榔,OkHttpCall實現(xiàn)了Retrofit的Call接口,但是其內部持有一個okhttp3.Call
湃番,調用網絡請求方法夭织,實際是調用的okhttp3.Call的網絡請求方法。
構建完OkHttpCall之后吠撮,調用了serviceMethod.adapt(okHttpCall)來返回指定的返回類型尊惰,也就是我們代碼里面的retrofit2.Call<JSONObject>對象。
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
這個callAdapter的來歷我們在ServiceMethod的build方法里面已經分析過了泥兰。由于我們的返回類型是retrofit2.Call<JSONObject>弄屡,所以這里的callAdapter會是默認的DefaultCallAdapterFactory返回的CallAdapter
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@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 call;
}
};
}
}
如上所示,DefaultCallAdapterFactory中返回的CallAdapter的adapt方法鞋诗,只是簡單地把傳入的Call返回了膀捷,什么都沒做。
所以我們在動態(tài)代理中返回的retrofit2.Call<JSONObject>的實際類型就是傳入的OkHttpCall削彬。
到這里担孔,動態(tài)代理的代碼就分析完了。
再來看看下一步吃警,執(zhí)行網絡請求call.enqueue糕篇。
由于這里的call就是OkHttpCall,我們再來OkHttpCall的enqueue方法酌心。
@Override
public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
...
call = rawCall = createRawCall();
...
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
...
response = parseResponse(rawResponse);
...
callback.onResponse(OkHttpCall.this, response);
...
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
...
});
調用了createRawCall方法來創(chuàng)建一個okhttp3.Call拌消,然后調用該okhttp3.Call的enqueue方法。
繼續(xù)跟進createRawCall方法
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
調用了serviceMethod.toCall方法
/** Builds an HTTP request from method arguments. */
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
使用了ServiceMethod之前解析出來的參數(shù)安券,比如httpMethod, baseUrl, relativeUrl, headers等等墩崩,構建了一個RequestBuilder對象,又使用RequestBuilder對象build出了一個okhttp3.Request對象侯勉,進而又構建出一個okhttp3.Call對象鹦筹。這樣,最終就是調用創(chuàng)建的這個okhttp3.Call來進行網絡請求的址貌。
可以看到铐拐,Retrofit對我們寫在接口中的各種注解進行解析,得出請求參數(shù)练对,然后用這些參數(shù)構造出okhttp請求來請求網絡遍蟋。同時,它通過CallAdapter可以實現(xiàn)和RxJava的配合使用螟凭,通過Converter可以靈活地返回你需要的數(shù)據(jù)類型虚青。