最近非常流行 Retrofit+RxJava+OkHttp 這一整套的網(wǎng)絡(luò)請求和異步操作的開源框架,從 Jake Wharton 的 Github 主頁也能看出其趨勢。
本文主要介紹 Retrofit 的基本原理,基于 2.1.0 版本的源碼。
1. 基本用法
1.1 定義 API 接口
Retrofit
的使用非常簡單,先來看一個 官網(wǎng) 上的示例代碼。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
官方的解釋是
Retrofit turns your HTTP API into a Java interface.
首先定義了一個 API 接口 GitHubService
,包含 HTTP 請求的方法 GET
和參數(shù) user
,及成功后的返回類型 List<Repo>
,方法和參數(shù)由注解聲明,非常清晰。
1.2 創(chuàng)建 Retrofit 對象并生成 API 實例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
然后創(chuàng)建一個 Retrofit
對象,這里采用 Builder 模式,傳入 baseUrl
和 ConverterFactory
等參數(shù),后面會講到。
通過 Retrofit
對象用動態(tài)代理的方式生成我們需要的 API 實例 GitHubService
。
1.3 API 實例去請求服務(wù)
Call<List<Repo>> repoCall = service.listRepos("danke77");
用生成的 API 實例調(diào)用相應(yīng)的方法,默認(rèn)返回 Call<T>
,然后調(diào)用 Call#execute
方法同步或調(diào)用 Call#enqueue
方法異步請求 HTTP。
List<Repo> repos = repoCall.execute().body();
請求返回的數(shù)據(jù)直接轉(zhuǎn)化成了 List<Repo>
,非常方便。
如果要使用 RxJava,在創(chuàng)建 Retrofit
對象時要調(diào)用 addCallAdapterFactory(RxJavaCallAdapterFactory.create())
,則返回類型會從 Call<T>
轉(zhuǎn)換成 Observable<T>
。
2. Retrofit
2.1 build
先看一下 Retrofit.Builder
類里的成員變量。
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Platform
提供了3個平臺:Java8
,Android
和 IOS
,全都繼承自 Platform
,初始化時靜態(tài)方法 Platform#findPlatform
會自動識別屬于哪一個。
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
通過 Retrofit.Builder#client
或 Retrofit.Builder#callFactory
可以自定義 OkHttpClient
。
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;
}
如果不指定 callFactory
,則默認(rèn)使用 OkHttpClient
。
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
converterFactories
和 adapterFactories
提供了2個工廠列表,用于用戶自定義數(shù)據(jù)轉(zhuǎn)換和類型轉(zhuǎn)換,后面會詳細說明。
最后調(diào)用 Retrofit.Builder#build
創(chuàng)建一個 Retrofit
對象。
public Retrofit build() {
// ... configured values
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
2.2 create
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
首先調(diào)用 Utils.validateServiceInterface
去判斷 service
是否是一個 Interface
且沒有繼承其他 Interface
,否則拋非法參數(shù)異常。
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
如果 validateEagerly
為 true
,則會調(diào)用 eagerlyValidateMethods
方法,會去預(yù)加載 service
中的所有方法,默認(rèn)為 false
。
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
然后就是通過動態(tài)代理生成 service
。前兩個 if
分支分別判斷是否是 Object
的方法及 default
方法,后者除了 Java8
其他都是 false
。
再看 loadServiceMethod
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
通過 serviceMethodCache
實現(xiàn)緩存機制,同一個 service
的同一個方法只會創(chuàng)建一次,生成 ServiceMethod
同時存入 Cache
。
用 ServiceMethod
和需要的參數(shù)生成一個 OkHttpCall
對象。然后用 CallAdapter
將生成的 OkHttpCall
轉(zhuǎn)換為我們需要的返回類型,這個后面會說到。
3. ServiceMethod
Adapts an invocation of an interface method into an HTTP call.
ServiceMethod
的作用就是把一個 API 方法轉(zhuǎn)換為一個 HTTP 調(diào)用。
從 Retrofit#loadServiceMethod
方法中可以看出一個 API 方法對應(yīng)一個 ServiceMethod
。
以 GitHubService
為例
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
@GET("users/{user}/repos")
是 MethodAnnotations
,@Path("user") String user
是 ParameterAnnotations
,Call<List<Repo>>
是 CallAdapter
。
3.1 ServiceMethod.Builder
先看下 ServiceMethod.Builder
的構(gòu)造函數(shù)
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
傳入 retrofit
和 method
對象,通過 method
獲取到方法注解 methodAnnotations
、參數(shù)類型 parameterTypes
和參數(shù)注解 parameterAnnotationsArray
,parameterAnnotationsArray
是一個二維數(shù)組 Annotation[][]
,因為一個參數(shù)可以有多個注解。
關(guān)鍵看 ServiceMethod.Builder#build
方法,會生成一個 ServiceMethod
對象,接下來按順序解析。
3.2 createCallAdapter
callAdapter = createCallAdapter()
會遍歷 adapterFactories
,通過 API 方法的 annotations
和 returnType
取到第一個符合條件的 CallAdapter
。
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
然后取到 responseType = callAdapter.responseType()
并進行判斷,如果是 retrofit2.Response<T>
或 okhttp3.Response
則拋異常,目前支持的有默認(rèn)的 retrofit2.Call<T>
,RxJava 的 rx.Observable
,Java8 的 java.util.concurrent.CompletableFuture
和 Guava 的 com.google.common.util.concurrent.ListenableFuture
。
3.3 createResponseConverter
responseConverter = createResponseConverter()
會遍歷 converterFactories
,通過 API 方法的 annotations
和 responseType
取到第一個符合條件的 Converter<ResponseBody, T>
。
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}
3.4 parseMethodAnnotation
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
遍歷 API 方法的所有 annotations
,如實例中的 @GET("users/{user}/repos")
,根據(jù)所屬類型和值解析成 HTTP 請求需要的數(shù)據(jù)。
在 package retrofit2.http
下包含了所有的 Method Annotation
和 Parameter Anootation
。
DELETE
、GET
、HEAD
、PATHC
、POST
、PUT
、OPTIONS
、HTTP
類型的 annotaion
會調(diào)用 parseHttpMethodAndPath
,生成 httpMethod
、hasBody
、relativeUrl
、relativeUrlParamNames
。
retrofit2.http.Headers
類型的 annotaion
會調(diào)用 parseHeaders
,生成 headers
。
Multipart
和 FormUrlEncoded
類型的 annotaion
分別生成 isMultipart
和 isFormEncoded
,兩者互斥,不能同時為 true
,否則會拋異常。
然后對生成的部分參數(shù)檢查,httpMethod
不能為空,如果 hasBody
為 false
,則 isMultipart
和 isFormEncoded
必須也為 false
,否則會拋異常。
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
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).");
}
}
3.5 parseParameterAnnotation
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
...
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
遍歷每個參數(shù)的 parameterAnnotations
,如實例中的 @Path("user") String user
,根據(jù)所屬類型和值解析成對應(yīng)的 ParameterHandler
,每個 Parameter Anootation
類型都有對應(yīng)的 ParameterHandler
,且每個參數(shù)只能有一個 ParameterHandler
。
可以看下 parseParameter
的邏輯
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
return result;
}
關(guān)鍵在 parseParameterAnnotation
,根據(jù) annotation
的類型并做參數(shù)校驗,會生成不同的 ParameterHandler
,如 RelativeUrl
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl();
} else {
throw parameterError(p, "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
由于 Retrofit 不依賴 Android SDK,判斷 type
時無法獲取到 android.net.Uri.class
,因此采用了 "android.net.Uri".equals(((Class<?>) type).getName())
的技巧。
每個 Parameter Anootation
都會對應(yīng)一個 ParameterHandler
,如 static final class Path<T> extends ParameterHandler<T>
,它們都實現(xiàn)了 ParameterHandler<T>
。
ParameterAnnotation | ? extends ParameterHandler |
---|---|
Url | RelativeUrl |
Path | Path |
Query | Query |
QueryMap | QueryMap |
Header | Header |
HeaderMap | HeaderMap |
Field | Field |
FieldMap | FieldMap |
Part | Part |
PartMap | PartMap |
Body | Body |
每種 ParameterHandler
都通過 Converter<F, T>
將我們的傳參類型轉(zhuǎn)化成 RequestBuilder
需要的類型,并設(shè)置其參數(shù)。舉個例子
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, T value) throws IOException {
if (value == null) return; // Skip null values.
builder.addQueryParam(name, valueConverter.convert(value), encoded);
}
}
valueConverter.convert
將我們的傳參類型 T
轉(zhuǎn)換成 String
,并設(shè)置到 RequestBuilder
中。其他的配置也是按同樣的方式。
4. OkHttpCall
OkHttpCall
實現(xiàn)了 retrofit2.Call<T>
,看下它的構(gòu)造函數(shù),傳入 ServiceMethod
和請求參數(shù)。
OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
4.1 createRawCall
先看下 OkHttpCall#createRawCall
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
將已經(jīng)生成的 serviceMethod
通過 toRequest(args)
轉(zhuǎn)成一個 okhttp3.Request
對象。再用創(chuàng)建 Retrofit
時指定的 okhttp3.Call.Factory
創(chuàng)建一個 okhttp3.Call
,這里如果不指定 okhttp3.Call.Factory
,則默認(rèn)是 okhttp3.OkHttpClient
。
在 ServiceMethod#toRequest
方法中,用 method
相關(guān)的配置生成一個 retrofit2.RequestBuilder
后,再用之前準(zhǔn)備好的 parameterHandlers
處理每一個參數(shù),最后生成一個 okhttp3.Request
。
/** Builds an HTTP request from method arguments. */
Request toRequest(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 requestBuilder.build();
}
4.2 execute
okhttp3.Call#execute
用于同步請求 HTTP,線程會被阻塞,請求成功后返回我們指定的數(shù)據(jù)類型。
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
首先檢查 okhttp3.Call
是否已被執(zhí)行。
一個 okhttp3.Call
只能被執(zhí)行一次,可以調(diào)用 OkHttpCall#clone
重新創(chuàng)建一個新的相同配置的 HTTP 請求。
@Override public OkHttpCall<T> clone() {
return new OkHttpCall<>(serviceMethod, args);
}
然后檢查并創(chuàng)建 okhttp3.Call
,調(diào)用 okhttp3.Call#execute
執(zhí)行同步請求。
最后調(diào)用 parsePesponse
將返回的 okhttp3.Response
解析成我們需要的數(shù)據(jù)。
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();
// ... 狀態(tài)碼檢查
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
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;
}
}
對 okhttp3.Response
進行一些狀態(tài)碼檢查后調(diào)用 ServiceMethod#toResponse
生成我們需要的數(shù)據(jù)類型。這里就用到了我們之前準(zhǔn)備好的 responseConverter
。最后封裝成一個 retrofit2.Response<T>
,包含了原始的 rawResponse
、我們需要的 body
和 errorBody
,我們?nèi)⌒枰臄?shù)據(jù)。
4.3 enqueue
okhttp3.Call#enqueue
和 okhttp3.Call#execute
流程類似,異步請求 HTTP,然后將回調(diào)都交給 retrofit2.Callback<T>
處理。
看下 retrofit2.Callback#onFailure
的注釋
Invoked when a network exception occurred talking to the server or when an unexpected exception occurred creating the request or processing the response.
這里 retrofit2.Callback#onFailure
除了處理網(wǎng)絡(luò)異常外,還會處理創(chuàng)建網(wǎng)絡(luò)請求和解析數(shù)據(jù)的異常,在回調(diào)中處理,而不是直接 crash,這點做的非常好。
-
createRawCall
拋出的異常try { call = rawCall = createRawCall(); } catch (Throwable t) { failure = creationFailure = t; }
如果出異常,直接回調(diào),不執(zhí)行接下來
enqueue
方法。 執(zhí)行
okhttp3.Call#enqueue
時okhttp3.Callback
拋出的網(wǎng)絡(luò)請求異常-
網(wǎng)絡(luò)請求成功后在
okhttp3.Callback#onResponse
中parseResponse
時拋出的異常try { response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; }
5. CallAdapter
前面已經(jīng)簡單介紹過 ServiceMethod#createCallAdapter
,它會從 adapterFactories
中找到第一個符合條件的 CallAdapter.Factory
。
5.1 retrofit-adapters
先來看 Retrofit 提供的 retrofit-adapters
模塊,目前供我們選擇使用的有 guava
、java8
和 rxjava
,分別對應(yīng)的 CallAdapter.Factory
是 GuavaCallAdapterFactory
、Java8CallAdapterFactory
和 RxJavaCallAdapterFactory
。
在 Retrofit#build
時,除了我們自己添加的 CallAdapter.Factory
, 還會添加兩個默認(rèn)的 CallAdapter.Factory
:ExecutorCallAdapterFactory
和 DefaultCallAdapterFactory
。
// 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));
在 Retrofit
源碼中有大量類似 List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
的例子,不直接使用成員變量,而是將成員變量重新拷貝給一個新的臨時變量,這樣雖然多申請了4個字節(jié)內(nèi)存,但如果以后將成員變量改成入?yún)ⅲ涂梢圆挥酶拇a直接使用了,是一種好的編碼習(xí)慣。
5.2 default
再看默認(rèn)的 CallAdapter.Factory
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
DefaultCallAdapterFactory
和 ExecutorCallAdapterFactory
返回的類型都是 retrofit2.Call<R>
。
在 DefaultCallAdapterFactory
中,CallAdapter#adapt
什么都不做,直接返回 retrofit2.Call<R>
。而 ExecutorCallAdapterFactory
的 CallAdapter#adapt
則返回 ExecutorCallbackCall<T>
,它實現(xiàn)了 retrofit2.Call<R>
,會傳入一個 Executor
,同步調(diào)用不變,異步調(diào)用時會在指定的 Executor
上執(zhí)行。
5.3 adapt
看下 CallAdapter
的 adapt
方法
/**
* Returns an instance of {@code T} which delegates to {@code call}.
*/
<R> T adapt(Call<R> call);
它的作用就是把 retrofit2.Call<R>
轉(zhuǎn)換成我們需要的 T
。
CallAdapters | ? extends CallAdapter.Factory | T |
---|---|---|
guava | retrofit2.adapter.guava.GuavaCallAdapterFactory | com.google.common.util.concurrent.ListenableFuture |
java8 | retrofit2.adapter.java8.Java8CallAdapterFactory | java.util.concurrent.CompletableFuture |
rxjava | retrofit2.adapter.rxjava.RxJavaCallAdapterFactory | rx.Observable |
default | retrofit2.ExecutorCallAdapterFactory | retrofit2.Call<R> |
default | retrofit2.DefaultCallAdapterFactory | retrofit2.Call<R> |
List<CallAdapter.Factory>
中添加的順序是我們指定的一個或多個 CallAdapter.Factory
,默認(rèn)的 ExecutorCallAdapterFactory
和 DefaultCallAdapterFactory
,查找時按順序查找。
6. Converter
Converter
的作用就是將 HTTP 請求返回的數(shù)據(jù)格式轉(zhuǎn)換成我們需要的對象,或?qū)⑽覀兲峁┑膶ο筠D(zhuǎn)換成 HTTP 請求需要的數(shù)據(jù)格式。
public interface Converter<F, T> {
T convert(F value) throws IOException;
}
接口非常清晰,將 F
轉(zhuǎn)換成 T
。
6.1 Factory
來看 Converter.Factory
abstract class Factory {
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
}
-
responseBodyConverter
用于將 HTTP 請求返回的 response 轉(zhuǎn)換成我們指定的類型。 -
requestBodyConverter
用于將Body
、Part
、PartMap
3種類型的參數(shù)轉(zhuǎn)換成 HTTP 的請求體。 -
stringConverter
用于將Field
、FieldMap
、Header
、Path
、Query
、QueryMap
這幾種類型的參數(shù)轉(zhuǎn)換成String
。
6.2 retrofit-converters
和 CallAdapter
類似,Retrofit 也提供了默認(rèn)的 Converter.Factory
——BuiltInConverters
,只能處理基本的 ResponseBody
、RequestBody
和 String
類型。
在 Retrofit 提供的 retrofit-converters
模塊,供我們選擇的有 Gson
、Jackson
、Moshi
、Protocol Buffers
、XML
、Scalar
和 Wire
,我們常用的有 GsonConverterFactory
。
需要注意的是,Jake Wharton 在他的一篇演講 Simple HTTP with Retrofit 2 中說道
I want to stress that the order matters. This is the order in which we’re going to ask each one whether or not it can handle a type. What I have written above is actually wrong. If we ever specify a proto, it’s going to be encoded as JSON, which will try and deserialize the response buddy as JSON. That’s obviously not what we want. We will have to flip these because we want to check protocol buffers first, and then JSON through GSON.
說的就是 Retrofit.Builder#addConverterFactory
的順序非常重要,先添加的 Converter.Factory
會先用來解析,而 Gson 非常強大,如果第一個添加 GsonConverterFactory
,則其他想要轉(zhuǎn)換的類型如 Protocol Buffers
就不會執(zhí)行,因此建議將 GsonConverterFactory
作為最后一個添加。
7. 總結(jié)
Retrofit 的源碼還是很難的,反反復(fù)復(fù)看了很多遍,除了其原理和流程外,從中也學(xué)到了一些技巧和設(shè)計模式。在寫這篇文章的同時又把思路和流程重新理了一遍,對自己幫助還是非常大的。關(guān)于源碼最大的感受就是各個類之間傳對象調(diào)用感覺非常亂,也增加了理解的難度,如 Retrofit
和 ServiceMethod
之間就互相依賴。
本文是 慌不要慌 原創(chuàng),發(fā)表于 https://danke77.github.io/,請閱讀原文支持原創(chuàng) https://danke77.github.io/2016/08/06/retrofit-source-analysis/,版權(quán)歸作者所有,轉(zhuǎn)載請注明出處。