Retrofit 源碼分析

最近非常流行 Retrofit+RxJava+OkHttp 這一整套的網(wǎng)絡(luò)請求和異步操作的開源框架,從 Jake Wharton 的 Github 主頁也能看出其趨勢。

Retrofit+RxJava+OkHttp.png

本文主要介紹 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 模式,傳入 baseUrlConverterFactory 等參數(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個平臺:Java8AndroidIOS,全都繼承自 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#clientRetrofit.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();
}

converterFactoriesadapterFactories 提供了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.");
    }
}

如果 validateEagerlytrue,則會調(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 userParameterAnnotationsCall<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(); 
}

傳入 retrofitmethod 對象,通過 method 獲取到方法注解 methodAnnotations、參數(shù)類型 parameterTypes 和參數(shù)注解 parameterAnnotationsArrayparameterAnnotationsArray是一個二維數(shù)組 Annotation[][],因為一個參數(shù)可以有多個注解。

關(guān)鍵看 ServiceMethod.Builder#build 方法,會生成一個 ServiceMethod 對象,接下來按順序解析。

3.2 createCallAdapter

callAdapter = createCallAdapter() 會遍歷 adapterFactories,通過 API 方法的 annotationsreturnType 取到第一個符合條件的 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 方法的 annotationsresponseType 取到第一個符合條件的 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 AnnotationParameter Anootation

DELETEGETHEADPATHCPOSTPUTOPTIONSHTTP 類型的 annotaion 會調(diào)用 parseHttpMethodAndPath,生成 httpMethodhasBodyrelativeUrlrelativeUrlParamNames

retrofit2.http.Headers 類型的 annotaion 會調(diào)用 parseHeaders,生成 headers

MultipartFormUrlEncoded 類型的 annotaion 分別生成 isMultipartisFormEncoded,兩者互斥,不能同時為 true,否則會拋異常。

然后對生成的部分參數(shù)檢查,httpMethod 不能為空,如果 hasBodyfalse,則 isMultipartisFormEncoded 必須也為 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、我們需要的 bodyerrorBody,我們?nèi)⌒枰臄?shù)據(jù)。

4.3 enqueue

okhttp3.Call#enqueueokhttp3.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,這點做的非常好。

  1. createRawCall 拋出的異常

    try {
        call = rawCall = createRawCall();
    } catch (Throwable t) {
        failure = creationFailure = t;
    }
    

    如果出異常,直接回調(diào),不執(zhí)行接下來 enqueue 方法。

  2. 執(zhí)行 okhttp3.Call#enqueueokhttp3.Callback 拋出的網(wǎng)絡(luò)請求異常

  3. 網(wǎng)絡(luò)請求成功后在 okhttp3.Callback#onResponseparseResponse 時拋出的異常

    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 模塊,目前供我們選擇使用的有 guavajava8rxjava,分別對應(yīng)的 CallAdapter.FactoryGuavaCallAdapterFactoryJava8CallAdapterFactoryRxJavaCallAdapterFactory

Retrofit#build 時,除了我們自己添加的 CallAdapter.Factory, 還會添加兩個默認(rèn)的 CallAdapter.FactoryExecutorCallAdapterFactoryDefaultCallAdapterFactory

// 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;
}

DefaultCallAdapterFactoryExecutorCallAdapterFactory 返回的類型都是 retrofit2.Call<R>

DefaultCallAdapterFactory 中,CallAdapter#adapt 什么都不做,直接返回 retrofit2.Call<R>。而 ExecutorCallAdapterFactoryCallAdapter#adapt 則返回 ExecutorCallbackCall<T>,它實現(xiàn)了 retrofit2.Call<R>,會傳入一個 Executor,同步調(diào)用不變,異步調(diào)用時會在指定的 Executor 上執(zhí)行。

5.3 adapt

看下 CallAdapteradapt 方法

/**
  * 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)的 ExecutorCallAdapterFactoryDefaultCallAdapterFactory,查找時按順序查找。

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;
    }
}
  1. responseBodyConverter 用于將 HTTP 請求返回的 response 轉(zhuǎn)換成我們指定的類型。
  2. requestBodyConverter 用于將 BodyPartPartMap 3種類型的參數(shù)轉(zhuǎn)換成 HTTP 的請求體。
  3. stringConverter 用于將 FieldFieldMapHeaderPathQueryQueryMap 這幾種類型的參數(shù)轉(zhuǎn)換成 String

6.2 retrofit-converters

CallAdapter 類似,Retrofit 也提供了默認(rèn)的 Converter.Factory——BuiltInConverters,只能處理基本的 ResponseBodyRequestBodyString 類型。

在 Retrofit 提供的 retrofit-converters 模塊,供我們選擇的有 GsonJacksonMoshiProtocol BuffersXMLScalarWire,我們常用的有 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)用感覺非常亂,也增加了理解的難度,如 RetrofitServiceMethod 之間就互相依賴。

本文是 慌不要慌 原創(chuàng),發(fā)表于 https://danke77.github.io/,請閱讀原文支持原創(chuàng) https://danke77.github.io/2016/08/06/retrofit-source-analysis/,版權(quán)歸作者所有,轉(zhuǎn)載請注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容