版權聲明:本文爲博主原創文章,未經博主容許不得轉載
文章分類:Android知識體系 - 網絡編程
複製代碼
Retrofit是一個基於OkHttp、遵循RESTful API設計風格的網絡請求封裝框架,本文將按照其工做流程逐步分析對應的源碼(本文使用的Retrofit版本爲2.5.0)java
如下是一次簡單的請求示例,首先咱們須要定義一個接口API,並使用註解描述其中的API方法android
public interface ExpressService {
@GET("query")
Call<ResponseBody> get(@Query("type") String type, @Query("postid") String postid);
}
複製代碼
而後是Retrofit的工做流,能夠分爲三步:express
public void asyncGet() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.kuaidi100.com/")
.build();
ExpressService expressService = retrofit.create(ExpressService.class);
Call<ResponseBody> call = expressService.get("ems", "11111111");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
複製代碼
下面咱們將按照上述過程,分析對應的源碼編程
本章咱們將分析Retrofit對象構建的過程,如下是對應的示例代碼緩存
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.kuaidi100.com/")
.build();
複製代碼
首先來看Retrofit類聲明瞭哪些成員變量安全
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
...
}
複製代碼
serviceMethodCache:serviceMethodCache是一個ConcurrentHashMap類型的Map集合,所以它支持併發操做且線程安全,其存儲對象是ServiceMethod。ServiceMethod咱們能夠理解是API方法的配置器以及代理中轉站,具體內容會在後文進行分析bash
callFactory:callFactory就是生產請求執行器的工廠(Call.Factory),Retrofit中默認的請求執行器工廠是OkHttpClient。若是咱們沒有設置自定義的請求執行器工廠,那麼就會在構建Retrofit對象的過程當中爲咱們建立一個OkHttpClient實例網絡
baseUrl:API接口基地址的封裝對象,類型爲HttpUrl併發
converterFactories:數據轉換器工廠(Converter.Factory)的集合,該工廠的產品數據轉換器(Converter)做用是對請求與響應數據進行序列化和反序列化app
callAdapterFactories:請求適配器工廠(CallAdapter.Factory)的集合,該工廠的產品請求適配器(CallAdapter)用於改變執行請求的方式,例如咱們能夠經過添加支持RxJava的請求適配器,將默認執行請求的方式改成RxJava調用鏈的方式
callbackExecutor:回調執行器,主要做用是處理請求回調,例如將回調所在線程從子線程切換至主線程
validateEagerly:是否提早加載API方法配置的標誌位
Retrofit對象經過建造者模式進行構建,咱們來看下Builder是如何初始化的
public static final class Builder {
private final Platform platform;
...
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
...
}
複製代碼
咱們看見Builder的構造方法須要傳入Platform對象,它的主要做用是根據運行平臺爲Retrofit提供默認的配置方法、工廠類或者工廠類的集合。Platform能夠經過Platform.get()
方法獲取實例,咱們來看下方法相關源碼
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();
}
...
}
複製代碼
調用Platform.get()
方法獲取的是靜態成員變量PLATFORM,PLATFORM則經過findPlatform()
方法生成
findPlatform()
主要經過是否能查找到指定的類來判斷當前Retrofit運行的平臺,若是是運行在Android平臺,則返回Platform.Android的實例;若是是Java平臺,則返回Platform.Java8的實例;若是二者皆非,則返回Platform自身的實例
如今咱們是在Android平臺下運行Retrofit,因此繼續往下看Platform.Android的代碼
// Platform
static class Android extends Platform {
@IgnoreJRERequirement // Guarded by API check.
@Override
boolean isDefaultMethod(Method method) {
if (Build.VERSION.SDK_INT < 24) {
return false;
}
return method.isDefault();
}
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
@Override
int defaultCallAdapterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
}
@Override
List<? extends Converter.Factory> defaultConverterFactories() {
return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.<Converter.Factory>emptyList();
}
@Override
int defaultConverterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
複製代碼
Platform.Android中主要定義瞭如下內容:
以上平臺默認的內容都會在Builder調用build()
完成構建時用到,具體的咱們待會再細說,如今先來看下Builder主要提供了哪些方法
// Retrofit.Builder
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder callbackExecutor(Executor executor) {
this.callbackExecutor = checkNotNull(executor, "executor == null");
return this;
}
public Builder validateEagerly(boolean validateEagerly) {
this.validateEagerly = validateEagerly;
return this;
}
複製代碼
簡單介紹一下這些方法的做用
client()
:添加自定義配置的OkHttpClientcallFactory()
:添加自定義的請求執行器工廠baseUrl()
:添加API接口的基地址addConverterFactory()
:添加自定義的數據轉換器addCallAdapterFactory()
:添加自定義的請求適配器callbackExecutor()
:添加自定義的回調執行器validateEagerly()
:設置是否預加載API方法的標誌位完成Retrofit的構建最終須要調用Builder.build()
方法,來看下源碼
// Retrofit.Builder
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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// 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);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
複製代碼
build()
方法完成了如下工做:
Platform.defaultCallbackExecutor()
,即MainThreadExecutor完成上述工做後將相關參數傳入Retrofit的構造方法中即完成構建Retrofit對象的工做。其中須要注意的是converterFactories和callAdapterFactories都變成了不可修改的List集合,這意味着後續咱們不能夠再更改這兩個集合中的內容了
至此Retrofit對象構建的過程就分析完了,下一章咱們將分析API接口方法加載配置以及轉換爲請求執行器的過程
這一章咱們分析了構建Retrofit對象的過程,過程當中主要完成了如下工做:
本章咱們將分析API方法加載配置的過程,如下是對應的示例代碼
// 請求示例
ExpressService expressService = retrofit.create(ExpressService.class);
Call<ResponseBody> call = expressService.get("ems", "11111111");
複製代碼
Retrofit對象構建完畢後,下一步是經過Retrofit.create(Class<T> service)
方法實現API接口,該方法的代碼以下
// Retrofit
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();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable
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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
複製代碼
該方法主要是經過運用動態代理的方式爲請求接口生成一個代理對象,咱們對接口全部方法的調用都會轉發到代理對象中。如今咱們一步步分析是如何完成整個動態代理的過程的
首先是調用Utils.validateServiceInterface(Class<T> service)
對接口類進行校驗
// Utils
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
// Prevent API interfaces from extending other interfaces. This not only avoids a bug in
// Android (http://b.android.com/58753) but it forces composition of API declarations which is
// the recommended pattern.
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
複製代碼
這裏規定咱們傳入的參數必須是一個接口類,而且該接口不能繼承其餘的接口
回到create方法中,接下來會經過標誌位validateEagerly來決定是否提早爲API方法加載相應的配置
// Retrofit.create
if (validateEagerly) {
eagerlyValidateMethods(service);
}
複製代碼
咱們知道動態代理是在接口方法被調用時纔會生效的,這相似於懶加載策略,Retrofit默認採用的就是這種方式,而咱們能夠經過Retrofit.Builder.validateEagerly()
方法將validateEagerly標誌設置爲true,Retrofit就會調用eagerlyValidateMethods()
提早爲接口方法加載配置
eagerlyValidateMethods()
源碼以下
// Retrofit
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
複製代碼
具體邏輯爲遍歷接口中的方法(method),而後判斷方法是否爲默認方法或靜態方法(接口的默認方法和靜態方法都是Java8新增的特性),若不是則調用loadServiceMethod()
爲接口方法加載相應的配置。loadServiceMethod()
方法的邏輯咱們待會再細說,如今繼續分析Retrofit.create()
方法
通過預加載的邏輯後,下一步就是執行動態代理相關的邏輯
// Retrofit.create
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable
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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
複製代碼
首先依然是對接口方法的校驗,會判斷這次調用的方法是否爲Object對象的方法(非接口方法),如果則正常調用,不進行任何代理操做。而後判斷該方法是否爲默認方法,如果則調用Platform對象提供的配置方法invokeDefaultMethod()
並返回。invokeDefaultMethod()
在Android平臺下會拋出UnsupportedOperationException異常,具體代碼以下
// Platform
@Nullable
Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, @Nullable Object... args) throws Throwable {
throw new UnsupportedOperationException();
}
複製代碼
執行完全部的校驗工序以後,最終依然是調用loadServiceMethod()
開始加載API方法的配置,咱們來看下源碼
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
複製代碼
方法的邏輯很是簡單,功能能夠分爲兩部分來看
繼續往下看ServiceMethod的代碼
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
複製代碼
ServiceMethod是一個抽象類,它只有兩個方法,一個是invoke()
,這是一個抽象方法,具體的邏輯由ServiceMethod的子類實現,當調用接口方法時會被動態代理到這個方法中
另外一個方法是parseAnnotations()
,這是一個靜態方法,它的功能以下
RequestFactory.parseAnnotations()
方法HttpServiceMethod.parseAnnotations()
完成接口方法後續的配置加載工做這一部分最主要的關注點是RequestFactory。RequestFactory是請求體對象(okhttp3.Request)的工廠類,咱們能夠調用RequestFactory.create()
建立一個請求體的實例,下面咱們就來詳細分析生成RequestFactory的過程
如下是與RequestFactory.parseAnnotations()
方法相關的代碼
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
...
RequestFactory(Builder builder) {
method = builder.method;
baseUrl = builder.retrofit.baseUrl;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
headers = builder.headers;
contentType = builder.contentType;
hasBody = builder.hasBody;
isFormEncoded = builder.isFormEncoded;
isMultipart = builder.isMultipart;
parameterHandlers = builder.parameterHandlers;
isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
}
...
static final class Builder {
...
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(method,
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
if (relativeUrl == null && !gotUrl) {
throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(method, "Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError(method, "Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError(method, "Multipart method must contain at least one @Part.");
}
return new RequestFactory(this);
}
...
}
}
複製代碼
RequestFactory一樣經過建造者模式來構建實例,咱們能夠看到Builder.build()
方法中有許多狀態位的校驗邏輯,主要做用是當用戶在建立請求接口中錯誤地使用註解或配置參數時,能夠拋出相應的異常告知用戶。這部分的細節就不一一查看了,感興趣的同窗能夠自行研究
這裏咱們最主要關注的地方有兩點:一是遍歷接口方法的註解,而後經過Builder.parseMethodAnnotation()
方法解析註解的過程;二是遍歷方法的參數,而後經過Builder.parseParameter()
方法解析參數的過程
首先來看第一點,parseMethodAnnotation()
的代碼以下
// RequestFactory.Builder
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("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
複製代碼
這裏有大量的判斷分支語句,咱們能夠按照註解的功能分紅三類來看。第一類註解主要是描述HTTP方法的,例如@DELETE
、@GET
、@POST
等,解析方法爲parseHttpMethodAndPath()
,來看下源碼
// RequestFactory.Builder
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError(method, "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(method, "URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
複製代碼
這個方法有三個參數
@GET("query?type=ems&postid=11111111")
中括號裏的內容實際上就是指服務端接口Url的資源路徑和查詢參數部分。這些內容能夠經過調用這一系列註解的value()
方法獲取,這是在定義註解時設置的知道了每一個參數的含義,後面的代碼就好理解了,流程是這樣的:首先會對一個接口方法是否同時設置了多個HTTP方法註解進行了校驗;而後校驗value是否爲空,爲空就不須要繼續解析了,由於這部份內容不是在方法註解裏設置就是在方法參數中設置,這裏沒有,那就直接交給後面解析參數時再去處理;若value不爲空,則校驗查詢參數部分是否符合要求,符合要求則繼續解析查詢參數字符串獲得參數集合,不符合則拋出異常,這些操做主要經過Java正則解析相關的Matcher類完成的,就不細說了
回到RequestFactory.Builder.parseMethodAnnotation()
,咱們來看第二類註解。第二類註解只有@Headers
一個,負責設置請求頭信息,解析的方法爲Builder.parseHeaders()
,這部份內容比較簡單,就不展開了
第三類註解主要負責描述請求報文數據的類型,有@Multipart
和@FormUrlEncoded
兩種,但由於這兩種類型都須要配合方法參數的註解使用,因此這裏的處理過程只是簡單地校驗二者不重複設置就行
實際上方法註解中還有第四類,那就是@Streaming
,這是用於描述響應正文數據的,所以Retrofit將它的處理過程放到了後面配置響應內容相關的部分再進行
至此解析方法註解的部分咱們就分析完了,接下來看解析參數的部分
解析方法參數對應的方法是Builder.parseParameter()
,代碼以下
// RequestFactory.Builder
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(method, p,
"Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
...
return result;
}
複製代碼
這裏的核心邏輯是經過parseParameterAnnotation()
方法解析參數註解生成ParameterHandler對象,同時規定一個參數只能設置一個Retrofit定義的註解
ParameterHandler是一個抽象類,它的子類封裝了參數的數據和數據的處理過程,而且和不一樣註解類型的參數一一對應,例如子類ParameterHandler.Query封裝了@Query
註解的參數,ParameterHandler.Field則封裝了@Field
註解的參數
做爲參數的處理器,ParameterHandler能夠在構建請求體對象時利用專屬的參數數據轉換器將數據轉換成請求須要的格式,這裏咱們以ParameterHandler.Query爲例進行分析
// ParameterHandler
static final class Query<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Query(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String queryValue = valueConverter.convert(value);
if (queryValue == null) return; // Skip converted but null values
builder.addQueryParam(name, queryValue, encoded);
}
}
複製代碼
ParameterHandler.Query有三個成員屬性,其中name和encoded對應了@Query
定義的屬性
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {
/** The query parameter name. */
String value();
/** * Specifies whether the parameter {@linkplain #value() name} and value are already URL encoded. */
boolean encoded() default false;
}
複製代碼
而valueConverter指的就是參數數據轉換器,它能夠經過調用convert()
方法進行數據轉換。參數處理的過程都放在Query.apply()
方法中,當構建請求體須要此參數的數據時,就會調用apply()
方法,而後經過傳入的RequestBuilder引用設置數據
ParameterHandler的分析就到這,其餘參數處理器就不一一分析了,由於套路基本上都是同樣的,如今咱們繼續分析parseParameterAnnotation()
方法是如何生成ParameterHandler的
// RequestFactory.Builder
@Nullable
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
...
return new ParameterHandler.RelativeUrl(method, p);
} else if (annotation instanceof Path) {
...
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
} else if (annotation instanceof Query) {
...
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
...
Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryName) {
...
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
...
Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).array();
} else {
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.QueryName<>(converter, encoded);
}
} else if (annotation instanceof QueryMap) {
...
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.QueryMap<>(method, p,
valueConverter, ((QueryMap) annotation).encoded());
} else if (annotation instanceof Header) {
...
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Header<>(name, converter).iterable();
} else if (rawParameterType.isArray()) {
...
Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Header<>(name, converter).array();
} else {
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Header<>(name, converter);
}
} else if (annotation instanceof HeaderMap) {
...
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.HeaderMap<>(method, p, valueConverter);
} else if (annotation instanceof Field) {
...
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
...
Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Field<>(name, converter, encoded);
}
} else if (annotation instanceof FieldMap) {
...
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.FieldMap<>(method, p, valueConverter, ((FieldMap) annotation).encoded());
} else if (annotation instanceof Part) {
...
String partName = part.value();
if (partName.isEmpty()) {
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
...
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
return ParameterHandler.RawPart.INSTANCE;
} else {
...
}
} else {
Headers headers =
Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
"Content-Transfer-Encoding", part.encoding());
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(method, p, headers, converter).iterable();
} else if (rawParameterType.isArray()) {
...
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(method, p, headers, converter).array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
...
} else {
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Part<>(method, p, headers, converter);
}
}
} else if (annotation instanceof PartMap) {
...
Converter<?, RequestBody> valueConverter =
retrofit.requestBodyConverter(valueType, annotations, methodAnnotations);
return new ParameterHandler.PartMap<>(method, p, valueConverter, partMap.encoding());
} else if (annotation instanceof Body) {
...
Converter<?, RequestBody> converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Body<>(method, p, converter);
} else if (annotation instanceof Tag) {
...
return new ParameterHandler.Tag<>(tagType);
}
return null; // Not a Retrofit annotation.
}
複製代碼
因爲方法註解不少,parseParameterAnnotation()
代碼很是的多,所以這裏我只把核心的內容展現給你們。parseParameterAnnotation()
解析每一個參數的過程大體能夠總結爲三步
校驗過程就不細說了,感興趣的同窗能夠自行查閱源碼,咱們重點關注參數數據轉換器是如何生成的。從上面的源碼能夠看出生成轉換器的方式主要有兩種,一種是經過Retrofit.stringConverter()
方法生成,這類轉換器轉換出來的數據類型爲String;另外一種則經過Retrofit.requestBodyConverter()
方法生成,對應的轉換結果就是請求實體類型RequestBody
先來看Retrofit.stringConverter()
// Retrofit
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<?, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, String>) converter;
}
}
// Nothing matched. Resort to default converter which just calls toString().
//noinspection unchecked
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
複製代碼
這裏的代碼主要完成了如下工做:按順序遍歷數據轉換器工廠集合converterFactories,到符合要求的轉換器工廠,即在實現接口方法Converter.Factory.stringConverter()
時不能返回null。這裏有一點細節須要注意,在遍歷過程當中只要發現符合的轉換器工廠就會返回,所以轉換器工廠添加的順序決定了它們的優先級,越早添加的優先級越高,就能夠優先被徵調。還記得咱們在構建Retrofit對象時添加的轉換器嗎?如今咱們從新來回顧一下加深記憶
// Retrofit.Builder.build()
converterFactories.add(new BuiltInConverters());// 添加Retrofit內置的數據轉換器,優先級最高
converterFactories.addAll(this.converterFactories);// 按順序添加全部自定義的數據轉換器
converterFactories.addAll(platform.defaultConverterFactories());// 添加針對對應運行平臺設置的數據轉換器工廠
複製代碼
當內置轉換器工廠BuiltInConverters以及集合中其餘轉換器工廠都不符合要求時,則返回特定的轉換器BuiltInConverters.ToStringConverter,其代碼以下
// BuiltInConverters
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override
public String convert(Object value) {
return value.toString();
}
}
複製代碼
代碼很簡單就不細說了,接下來是Retrofit.requestBodyConverter()
public <T> Converter<T, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
}
public <T> Converter<T, RequestBody> nextRequestBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
checkNotNull(type, "type == null");
checkNotNull(parameterAnnotations, "parameterAnnotations == null");
checkNotNull(methodAnnotations, "methodAnnotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter.Factory factory = converterFactories.get(i);
Converter<?, RequestBody> converter =
factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, RequestBody>) converter;
}
}
// 沒有找到符合要求的請求數據轉換器,拋出IllegalArgumentException異常
...
}
複製代碼
和以前的處理邏輯差異不大,不過此次調用的方法爲Converter.Factory.requestBodyConverter()
,並且咱們發現BuiltInConverters實現了該接口方法,代碼以下
// BuiltInConverters
@Override
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
複製代碼
這裏返回了針對RequestBody類型參數的轉換器BuiltInConverters.RequestBodyConverter
// BuiltInConverters
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override
public RequestBody convert(RequestBody value) {
return value;
}
}
複製代碼
能夠看見RequestBodyConverter並無對參數數據進行任何處理,所以該轉換器最主要的做用是攔截類型爲RequestBody的參數
至此咱們就完了解析方法參數的所有工做,也成功生成了請求體對象工廠RequestFactory。
HttpServiceMethod是ServiceMethod的子類,它的代碼有點多,咱們直接挑重點看。首先是parseAnnotations()
方法
// HttpServiceMethod
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
...
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
複製代碼
這裏主要作了下面這些工做
createCallAdapter()
方法生成請求適配器callAdaptercallAdapter.responseType()
方法獲取響應數據的類型responseTypecreateResponseConverter()
方法生成響應體(Response)的數據轉換器responseConverter首先咱們分析生成請求適配器CallAdapter的過程,如下是createCallAdapter()
方法的代碼
// HttpServiceMethod
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method) {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
複製代碼
// Retrofit
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
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;
}
}
// 當全部適配器都不符合要求時拋出IllegalArgumentException異常
...
}
複製代碼
能夠發現套路基本上是同樣的,具體方式爲遍歷callAdapterFactories找到符合要求的請求適配器後返回,驗證的方法爲CallAdapter.Factory.get()
。經過上一章的分析咱們知道,除了用戶添加的自定義的請求適配器工廠之外,Retrofit還內置了兩種默認的適配器工廠:CompletableFutureCallAdapterFactory(系統版本大於等於24時生效)和ExecutorCallAdapterFactory。這裏咱們只以ExecutorCallAdapterFactory爲例進行分析,來看下源碼
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public @Nullable
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);
}
};
}
...
}
複製代碼
經過上述代碼咱們知道,get()
方法指定ExecutorCallAdapterFactory的適配目標是返回類型爲retrofit2.Call的API方法,其最終返回值是一個新的CallAdapter實例。此外,該CallAdapter實例的adapt()
方法生成了retrofit2.Call的子類ExecutorCallbackCall,這其實是請求執行器的裝飾器,具體內容咱們在後面用到時再細說,如今繼續下一步
接下來是調用HttpServiceMethod.createResponseConverter()
方法生成響應數據轉換器(ResponseConverter),咱們來看下相關代碼
// HttpServiceMethod
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
複製代碼
// Retrofit
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");
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;
}
}
// 沒法找到符合要求的ResponseBodyConverter時拋出IllegalArgumentException異常
...
}
複製代碼
一樣這裏也是經過遍歷轉換器工廠集合converterFactories找到符合要求的轉換器工廠,驗證方法爲Converter.Factory.responseBodyConverter()
。以前講過轉換器工廠優先級最高的是內置的BuiltInConverters,來看下它的responseBodyConverter()
方法
final class BuiltInConverters extends Converter.Factory {
...
@Override
public @Nullable 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;
}
...
}
複製代碼
這裏指定BuiltInConverters只能處理類型爲okhttp3.ResponseBody以及void的響應體數據。當類型爲ResponseBody時,還會判斷接口方法是否含有@Streaming
註解,而後提供不一樣的轉換器實例。下面咱們就看下這三個數據轉換器有什麼區別吧
// BuiltInConverters
static final class StreamingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
@Override
public ResponseBody convert(ResponseBody value) {
return value;
}
}
static final class BufferingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override
public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
@Override
public Void convert(ResponseBody value) {
value.close();
return null;
}
}
複製代碼
能夠看到這三個轉換器都實現了Converter接口的convert()
方法,這個方法會在後續處理響應數據時調用,如今咱們先看下這三個轉換器的convert()
方法是如何實現的
@Streaming
註解適合在執行大文件下載任務的時候使用如今回到一開始的請求示例中,咱們定義的接口方法是這樣的
public interface ExpressService {
@GET("query?type=ems&postid=11111111")
Call<ResponseBody> get();
}
複製代碼
這裏設置的響應數據類型是ResponseBody,即BuiltInConverters能夠處理這個API方法,所以遍歷查找轉換器工廠的過程到了BuiltInConverters處就被攔截了下來,且因爲該接口方法並無添加@Streaming
註解,因此最終HttpServiceMethod.createResponseConverter()
構建的響應數據轉換器就是BufferingResponseBodyConverter
完成全部前置工做後,咱們回到Retrofit.create()
方法,由以前的分析可知API方法會被動態代理到
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
複製代碼
而loadServiceMethod()
最終返回的是HttpServiceMethod的實例,所以咱們來看下HttpServiceMethod.invoke()
方法的代碼
// HttpServiceMethod
@Override
ReturnT invoke(Object[] args) {
return callAdapter.adapt(new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
複製代碼
adapt()
方法的傳參是OkHttpCall的實例,這是Retrofit層的請求執行器,其內部持有真實的請求執行器okhttp3.Call。OkHttpCall做爲代理類主要負責Retrofit層與OkHttp層之間交互數據的轉換
此外,從以前的講解中咱們知道adapt()
方法的返回結果是ExecutorCallbackCall的實例,所以動態代理API方法最終獲得的就是這個實例,其做爲OkHttpCall的裝飾器,主要負責協同回調執行器爲OkHttpCall動態加強回調方面的功能
至此API方法的動態代理和加載配置的過程就分析完了,下一章咱們將分析Retrofit是如何發起請求以及處理響應數據的
這一章分析了加載API方法配置的過程,原理是利用動態代理機制,主要完成了如下工做:
本章咱們將分析請求與響應的過程,如下是對應的示例代碼
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
複製代碼
由上一章咱們知道,這裏的call其實是裝飾器ExecutorCallbackCall,咱們來看下ExecutorCallbackCall.enqueue()
方法的代碼
// ExecutorCallAdapterFactory
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;
}
@Override
public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
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);
}
});
}
});
}
...
}
複製代碼
ExecutorCallbackCall有兩個成員變量,callbackExecutor與delegate,經過以前的分析咱們知道它們分別對應了MainThreadExecutor和OkHttpCall。那麼先來分析MainThreadExecutor.execute()
方法,該方法在OkHttpCall的請求回調中被調用
// Platform.Android
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
複製代碼
這裏的功能很是好理解,綜合以前的代碼來看就是將OkHttpCall的請求回調結果發送至主線程。再來看OkHttpCall.enqueue()
方法
// OkHttpCall
@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 = parseResponse(rawResponse);
callback.onResponse(OkHttpCall.this, response);
...
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
...
});
}
複製代碼
這裏我把核心的代碼摘抄出來進行分析,首先是經過createRawCall()
方法獲取真實的請求執行器
// OkHttpCall
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
複製代碼
這裏有兩個須要關注的點,一是調用callFactory.newCall()
方法獲取真實的請求執行器,callFactory實際上就是OkHttpClient對象的引用,這和咱們在OkHttp中生成請求執行器的方法一致;二是經過requestFactory.create()
方法獲取請求體okhttp3.Request的實例,其中args是經過動態代理API方法拿到的傳參。如今咱們開始分析生成Request對象的過程
// RequestFactory
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
...
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
複製代碼
handlers是參數封裝類ParameterHandler的集合,經過apply()
方法能夠處理參數數據,轉換成RequestBuilder須要的格式,而後經過RequestBuilder的引用設置數據,這些數據將在生成Request時用到。先來看下RequestBuilder的構造方法
// RequestBuilder
RequestBuilder(String method, HttpUrl baseUrl,
@Nullable String relativeUrl, @Nullable Headers headers, @Nullable MediaType contentType,
boolean hasBody, boolean isFormEncoded, boolean isMultipart) {
this.method = method;
this.baseUrl = baseUrl;
this.relativeUrl = relativeUrl;
this.requestBuilder = new Request.Builder();
this.contentType = contentType;
this.hasBody = hasBody;
if (headers != null) {
requestBuilder.headers(headers);
}
if (isFormEncoded) {
// Will be set to 'body' in 'build'.
formBuilder = new FormBody.Builder();
} else if (isMultipart) {
// Will be set to 'body' in 'build'.
multipartBuilder = new MultipartBody.Builder();
multipartBuilder.setType(MultipartBody.FORM);
}
}
複製代碼
能夠看到咱們以前在解析註解、加載API方法配置的過程當中生成的屬性在這都獲得了應用。再來看ParameterHandler.apply()
的過程,咱們以請求示例中定義的API方法爲例,方法參數中使用了@Query
註解,對應的參數封裝類是Query
// ParameterHandler
static final class Query<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Query(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String queryValue = valueConverter.convert(value);
if (queryValue == null) return; // Skip converted but null values
builder.addQueryParam(name, queryValue, encoded);
}
}
複製代碼
參數數據轉換器在這裏開始發揮做用了,能夠經過調用Converter.convert()
方法將參數數據轉換成RequestBuilder實際須要的數據,經過3.3.2一節的分析咱們知道處理String類型數據的轉換器是ToStringConverter,所以這裏valueConverter就是ToStringConverter實例的引用,從新回顧一下ToStringConverter.convert()
方法
// BuiltInConverters.ToStringConverter
@Override
public String convert(Object value) {
return value.toString();
}
複製代碼
數據轉換完畢後,繼續調用RequestBuilder.addQueryParam()
方法設置Query參數的數據
// RequestBuilder
void addQueryParam(String name, @Nullable String value, boolean encoded) {
if (relativeUrl != null) {
// Do a one-time combination of the built relative URL and the base URL.
urlBuilder = baseUrl.newBuilder(relativeUrl);
...
relativeUrl = null;
}
if (encoded) {
//noinspection ConstantConditions Checked to be non-null by above 'if' block.
urlBuilder.addEncodedQueryParameter(name, value);
} else {
//noinspection ConstantConditions Checked to be non-null by above 'if' block.
urlBuilder.addQueryParameter(name, value);
}
}
複製代碼
到這裏就都是OkHttp構建Request的方法了,再也不展開細說。回到RequestFactory.create()
,繼續往下看Request的構建過程
// RequestFactory.create
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
複製代碼
首先調用了RequestBuilder.get()
方法,看下源碼
Request.Builder get() {
HttpUrl url;
HttpUrl.Builder urlBuilder = this.urlBuilder;
if (urlBuilder != null) {
url = urlBuilder.build();
} else {
// No query parameters triggered builder creation, just combine the relative URL and base URL.
//noinspection ConstantConditions Non-null if urlBuilder is null.
url = baseUrl.resolve(relativeUrl);
...
}
RequestBody body = this.body;
if (body == null) {
// Try to pull from one of the builders.
if (formBuilder != null) {
body = formBuilder.build();
} else if (multipartBuilder != null) {
body = multipartBuilder.build();
} else if (hasBody) {
// Body is absent, make an empty body.
body = RequestBody.create(null, new byte[0]);
}
}
MediaType contentType = this.contentType;
if (contentType != null) {
if (body != null) {
body = new ContentTypeOverridingRequestBody(body, contentType);
} else {
requestBuilder.addHeader("Content-Type", contentType.toString());
}
}
return requestBuilder
.url(url)
.method(method, body);
}
複製代碼
一樣這裏也都是OkHttp層的調用,成員變量requestBuilder對應的類型就是okhttp3.Request.Builder,調用build()
方法就能夠生成Request對象了
至此OkHttpCall.createRawCall()
成功建立了一個okhttp3.Call的實例,如今咱們回到OkHttpCall.enqueue()
方法繼續往下看
獲得okhttp3.Call實例後,下一步就是調用Call.enqueue()
發起異步請求,並在回調中獲得響應體對象okhttp3.Response,因爲這是OkHttp層的,所以還須要解析轉換成Retrofit層的響應體對象,解析轉換的方法是OkHttpCall.parseResponse()
// OkHttpCall
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);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(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;
}
}
複製代碼
這裏的重點是調用ResponseConverter.convert()
轉換響應數據,以前分析過的內置和自定義的響應數據轉換器在這發揮了做用,ResponseBody成功轉換成用戶須要的類型
至此咱們完成了okhttp3.Response的處理過程,下一步再將生成的retrofit2.Response對象經過回調方法返回給用戶,請求與響應的過程以及整個Retrofit工做流程的源碼分析就完成了
這一章分析了請求與響應的過程,主要完成了如下工做:
enqueue()
方法發起真實的異步請求最後以一張Retrofit的工做流程圖總結以前的分析(ps:爲了和流程進行區分,這裏我將一些重要成員抽象成了數據源)