1. 程式人生 > >【Android】Retrofit原始碼分析

【Android】Retrofit原始碼分析

Retrofit簡介

retrofit n. 式樣翻新,花樣翻新 vt. 給機器裝置裝配(新部件),翻新,改型

Retrofit 是一個 RESTful 的 HTTP 網路請求框架的封裝。注意這裡並沒有說它是網路請求框架,主要原因在於網路請求的工作並不是 Retrofit 來完成的。Retrofit 2.0 開始內建 OkHttp,前者專注於介面的封裝,後者專注於真正的網路請求。即通過 大量的設計模式 封裝了 OkHttp ,使得簡潔易用。

我們的應用程式通過 Retrofit 請求網路,實際上是使用 Retrofit 介面層封裝請求引數、Header、Url 等資訊,之後由 OkHttp

完成後續的請求操作,在服務端返回資料之後,OkHttp 將原始的結果交給 Retrofit,後者根據使用者的需求對結果進行解析的過程。Retrofit的大概原理過程如下:

  1. RetrofitHttp請求 抽象 成 Java介面
  2. 在接口裡用 註解 描述和配置 網路請求引數
  3. 用動態代理 的方式,動態將網路請求介面的註解 解析 成HTTP請求
  4. 最後執行HTTP請求

這篇文章我將從Retrofit的基本用法出發,按照其使用步驟,一步步的探究Retrofit的實現原理及其原始碼的設計模式。

Retrofit Github: https://github.com/square/retrofit

使用步驟

使用 Retrofit 非常簡單,首先需要在 build.gradle 中新增依賴:

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

如果需要使用Gson解析器,也需要在build.gradle中新增依賴(後文會詳細講到Retrofit的Converter):

implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

1. 定義Interface

Retrofit使用java interface和註解描述了HTTP請求的API引數,比如Github的一個API:

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

其中Repo類定義如下:

public class Repo {
    public String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2. 建立Retrofit例項

這樣呼叫Retrofit就會為上面這個interface自動生成一個實現類:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())     //新增Gson解析器
    .build();

GitHubService service = retrofit.create(GitHubService.class);

3. 發起請求

然後呼叫interface的具體方法時(這裡是listRepos())就構造好了一個Call

Call<List<Repo>> call = service.listRepos("octocat");

返回的 call 其實並不是真正的資料結果,只是封裝成了一個隨時可以執行的請求,需要在合適的時機去執行它:

// 同步呼叫
List<Repo> data = repos.execute(); 

// 非同步呼叫
repos.enqueue(new Callback<List<Repo>>() {
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                List<Repo> data = response.body();
            }

            @Override
            public void onFailure(Call<List<Repo>> call, Throwable t) {
                t.printStackTrace();
            }
        });

怎麼樣,有沒有突然覺得請求介面就好像訪問自家的方法一樣簡單?下面我們轉入原始碼分析,按照使用步驟來探索Retrofit的實現原理。

原始碼分析

我們先來看看Retrofit的例項化步驟。先看看Retrofit這個類的引數

public final class Retrofit {
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();

  final okhttp3.Call.Factory callFactory;   // 生產網路請求器(Call)的工廠,預設使用OkHttp
  final HttpUrl baseUrl;    // url地址
  final List<Converter.Factory> converterFactories; // 資料轉換器(converter)工廠
  final List<CallAdapter.Factory> callAdapterFactories; // 生產網路請求介面卡(CallAdapter)的工廠List
  final @Nullable Executor callbackExecutor;    // 回撥方法執行器
  final boolean validateEagerly;    // 是否提前對業務介面中的註解進行驗證轉換的標誌位


  //建構函式
  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }


  //...省略其他程式碼...
}

Retrofit的建構函式是package包可見的,並不是public的,所以外部並不能直接new,而是要通過Retrofit.Builder來例項化。

Retrofit.Builder

Retrofit.Builder 是 Retrofit 類中的一個子類,負責用來建立 Retrofit 例項物件,使用『Builder模式』的好處是清晰明瞭可定製化。

public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
    }

    //建構函式
    public Builder() {
      // Retrofit支援Android Java8 預設Platform 三種平臺,此處確認當前是在哪個平臺環境執行
      this(Platform.get());
    }

    //...省略其他程式碼...
}

可以看到Retrofit.Builder 中的成員變數跟Retrofit中基本上是一一對應的,就不過多解釋了。這裡可以看到Builder的建構函式中預設判斷了一下當前的執行平臺。

最後,在建立 Retrofit.Builder 物件並進行自定義配置後,我們就要呼叫 build() 方法來構造出 Retrofit 物件了。那麼,我們來看下 build() 方法裡幹了什麼:

public Retrofit build() {
    // 必須要配置baseUrl
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }

    // 預設為 OkHttpClient
    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }

    // Android 平臺下預設為 MainThreadExecutor
    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);
    // 新增預設的 ExecutorCallAdapterFactory
    callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories =
            new ArrayList<>(1 + this.converterFactories.size());

    // Add the built-in converter factory first. This prevents overriding its behavior but also
    // ensures correct behavior when using converters that consume all types.
    // 首先新增預設的 BuiltInConverters
    converterFactories.add(new BuiltInConverters());
    converterFactories.addAll(this.converterFactories);

    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
            unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

build() 中,做的事情有:檢查配置、設定預設配置、建立 Retrofit 物件。並且在執行 .build() 方法前,只有 .baseUrl() 是必須呼叫來設定訪問地址的,其餘方法則是可選的。同時我們可以看到設定了很多預設成員,但這裡我們重點關注四個成員:callFactorycallAdapterresponseConverterparameterHandlers

  1. callFactory 負責建立 HTTP 請求,HTTP 請求被抽象為了 okhttp3.Call 類,它表示一個已經準備好,可以隨時執行的 HTTP 請求;
  2. callAdapter 負責把 retrofit2.Call<?> 裡的Call轉換為 另一種型別T(注意和 okhttp3.Call 區分開來,retrofit2.Call<?> 表示的是對一個 Retrofit 方法的呼叫),這個過程會發送一個 HTTP 請求,拿到伺服器返回的資料(通過 okhttp3.Call 實現),並把資料轉換為宣告的 T 型別物件(通過 Converter<F, T> 實現);
  3. responseConverterConverter<ResponseBody, T> 型別,負責把伺服器返回的資料(JSON、XML、PB、二進位制或者其他格式,由 ResponseBody 封裝)轉化為 T 型別的物件;
  4. parameterHandlers 則負責解析 API 定義時每個方法的引數,並在構造 HTTP 請求時設定引數;

CallAdapter和Converter到底是幹什麼的?

這裡多插兩句,給大家解釋一下這個CallAdapterConverter到底是幹什麼的?我們知道,最簡單的Retrofit介面一般定義如下:

public interface GitHubService {
    @GET("users/{user}/repos")
    Call<ResponseBody> listRepos(@Path("user") String user);
}

在給Retrofit不新增任何CallAdapterFactory的情況下,介面方法的返回型別必須是Call<?>,不能是其他型別。因而Retrofit提供了對這個Call進行轉換為其他型別的功能,那就是CallAdapter。比如新增一個RxJava的CallAdapter:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.example.com")
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())   // RxJava轉換器
    .build();

然後我們就可以這樣定義介面:

interface MyService {
    @GET("/user")
    Observable<User> getUser();
}

如果添加了一個Java8的CallAdapter,就可以這樣定義介面:

interface MyService {
    @GET("/user")
    CompletableFuture<User> getUser();
}
Retrofit提供的CallAdapter:
CallAdapter Gradle依賴
guava com.squareup.retrofit2:adapter-guava:latest.version
Java8 com.squareup.retrofit2:adapter-java8:latest.version
rxjava com.squareup.retrofit2:adapter-rxjava:latest.version
rxjava2 com.squareup.retrofit2:adapter-rxjava2:latest.version
scala com.squareup.retrofit2:adapter-scala:latest.version

同樣地,如果在不給Retrofit新增任何ConverterFactory的情況下,介面方法返回型別Call<T>裡的泛型T必須是ResponseBody,而不能是其他型別(比如List<User>),這就是Converter的作用,直白點也就是資料解析器,負責把ResponseBody解析成List<User>

另外,在我們構造 HTTP 請求時,我們傳遞的引數都是使用的註解型別(諸如 PathQueryField 等),那 Retrofit 是如何把我們傳遞的各種引數都轉化為 String 的呢?還是由 Retrofit 類提供Converter

Converter.Factory 除了提供responseBodyConverter,還提供 requestBodyConverter 和 stringConverter,API 方法中除了 @Body@Part 型別的引數,都利用 stringConverter 進行轉換,而 @Body@Part 型別的引數則利用 requestBodyConverter 進行轉換。

Retrofit提供的Converter
Converter Gradle依賴
Gson com.squareup.retrofit2:converter-gson:latest.version
Guava com.squareup.retrofit2:converter-guava:latest.version
Jackson com.squareup.retrofit2:converter-jackson:latest.version
Java8 com.squareup.retrofit2:converter-java8:latest.version
Jaxb com.squareup.retrofit2:converter-jaxb:latest.version
Moshi com.squareup.retrofit2:converter-moshi:latest.version
Protobuf com.squareup.retrofit2:converter-protobuf:latest.version
Scalars com.squareup.retrofit2:converter-scalars:latest.version
Wire com.squareup.retrofit2:converter-wire:latest.version
Simple XML com.squareup.retrofit2:converter-simplexml:latest.version

Platform

這裡我們再來個小插曲,來看下 Retrofit 是如何確定當前執行的是哪個平臺環境的。

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的callbackExecutor
    @Nullable
    Executor defaultCallbackExecutor() {
        return null;
    }

    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor != null) {
            return new ExecutorCallAdapterFactory(callbackExecutor);
        }
        return DefaultCallAdapterFactory.INSTANCE;
    }

    boolean isDefaultMethod(Method method) {
        return false;
    }

    @Nullable
    Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
                               @Nullable Object... args) throws Throwable {
        throw new UnsupportedOperationException();
    }
}

從上面的程式碼中可以看到,是通過反射判斷有沒有該類來實現的。比較巧妙,大家可以的學習一下。

而此處的AndroidJava8均是Platform的子類:

static class Android extends Platform {

    //Android平臺的預設callbackExecutor,實際上就是拋到UI執行緒去執行回撥
    @Override 
    public Executor defaultCallbackExecutor() {
        return new MainThreadExecutor();
    }

    //Android平臺的預設CallAdapterFactory
    @Override 
    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor == null) throw new AssertionError();
        return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override 
        public void execute(Runnable r) {
            handler.post(r);
        }
    }
}

Java8的定義如下:

@IgnoreJRERequirement // Only classloaded and used on Java 8.
static class Java8 extends Platform {

    //判斷被呼叫的method是否Java8的預設方法
    @Override 
    boolean isDefaultMethod(Method method) {
        return method.isDefault();
    }

    //呼叫預設方法
    @Override 
    Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
                                         @Nullable Object... args) throws Throwable {
        // Because the service interface might not be public, we need to use a MethodHandle lookup
        // that ignores the visibility of the declaringClass.
        Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
        constructor.setAccessible(true);
        return constructor.newInstance(declaringClass, -1 /* trusted */)
                .unreflectSpecial(method, declaringClass)
                .bindTo(object)
                .invokeWithArguments(args);
    }
}

Java 8 的interface引入了新的語言特性——預設方法(Default Methods)。大家可以參考這篇文章:Java8 預設方法 default method

預設方法允許您新增新的功能到現有庫的介面中,並能確保與採用舊版本介面編寫的程式碼的二進位制相容性。

所以如果在Java8的平臺上使用Retrofit的話,Retrofit需要排除我們定義的interface中的這些Default Methods。

在使用Retrofit.Builder例項化得到 Retrofit 物件後就是呼叫 Retrofit#create() 方法來建立我們 API 介面的例項。

Retrofit

所以我們需要跟進Retrofit類中的 create(final Class<T> service) 方法來看下:

public <T> T create(final Class<T> service) {
  // 校驗是否為介面,且不能繼承其他介面
  Utils.validateServiceInterface(service);
  // 是否需要提前解析介面方法
  if (validateEagerly) {
    eagerlyValidateMethods(service);
  }
  // 動態代理模式, 返回一個 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 serviceMethod = loadServiceMethod(method);
          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

在上面的程式碼中,最關鍵的就是『動態代理』,返回了一個 Proxy 代理類,呼叫介面中的任何方法都會呼叫 proxy 裡的 invoke 方法。實際上,進行網路操作的都是通過代理類來完成的。簡單的說,在我們前面的示例程式碼中呼叫 GitHubService.listRepos 時,實際上呼叫的是這裡的 InvocationHandler.invoke 方法。

InvocationHandler.invoke這個方法的意思是:如果呼叫的是 Object 的方法,例如 equalstoString,那就直接呼叫。如果是 default 方法(Java 8 引入的新語法),就呼叫 default 方法。這些我們都先不管,因為我們在Android平臺呼叫 listRepos,肯定不是這兩種情況,那這次呼叫真正幹活的就是這三行程式碼了:

// 將介面中的方法構造為 ServiceMethod
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);

這三句程式碼,下面我們著重來看。

在代理中,會根據引數中傳入的具體介面方法來構造出對應的 serviceMethodServiceMethod 類的作用就是把介面的方法適配為對應的 HTTP call 。

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    // 先從快取中取,若沒有就去建立對應的 ServiceMethod
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        // 沒有快取就建立,之後再放入快取中
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
}

可以看到在內部還維護了一個 serviceMethodCache 來快取 ServiceMethod ,同一個 API 的同一個方法,只會建立一次。由於我們每次獲取 API 例項都是傳入的 class 物件(比如示例中的GitHubService.class),而 class 物件是程序內單例的,所以獲取到它的同一個方法 Method 例項也是單例的,所以這裡的快取是有效的。我們就直接來看 ServiceMethod 是如何被建立的吧。

ServiceMethod

ServiceMethod<R, T> 類的作用正如其 JavaDoc 所言:

Adapts an invocation of an interface method into an HTTP call. 把對介面方法的呼叫轉為一次 HTTP 呼叫。

一個 ServiceMethod 物件對應於一個 API interface 的一個方法,上面的loadServiceMethod(method)方法負責載入了 ServiceMethod。我們發現 ServiceMethod 也是通過建造者模式(ServiceMethod.Builder)來建立物件的。那就進入對應構造方法:

// 位於ServiceMethod類中
Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      // 介面方法的註解
      this.methodAnnotations = method.getAnnotations();
      // 介面方法的引數型別
      this.parameterTypes = method.getGenericParameterTypes();
      // 介面方法引數的註解
      this.parameterAnnotationsArray = method.getParameterAnnotations();
}

在構造方法中沒有什麼特別的地方,我們單刀直入 build() 方法:

public ServiceMethod build() {
      // 根據介面方法的註解和返回型別建立 callAdapter
      // 如果沒有新增 CallAdapter 那麼預設會用 ExecutorCallAdapterFactory
      callAdapter = createCallAdapter();
      // calladapter 的響應型別中的泛型,比如 Call<User> 中的 User
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
          throw methodError("'"
                  + Utils.getRawType(responseType).getName()
                  + "' is not a valid response body type. Did you mean ResponseBody?");
      }

      // 根據之前泛型中的型別以及介面方法的註解建立 ResponseConverter
      responseConverter = createResponseConverter();

      // 根據介面方法的註解構造請求方法,比如 @GET @POST @DELETE 等
      // 另外還有新增請求頭,檢查url中有無帶?,轉化 path 中的引數
      for (Annotation annotation : methodAnnotations) {
          parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
          throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      // 若無 body 則不能有 Multipart 和 FormEncoded 的註解
      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).");
          }
      }

      // 解析介面方法引數中的註解,比如 @Path @Query @QueryMap @Field 等等
      // 相應的,每個方法的引數都建立了一個 ParameterHandler<?> 物件
      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);
      }

      // 檢查構造出的請求有沒有不對的地方
      if (relativeUrl == null && !gotUrl) {
          throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
          throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
          throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
          throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
  }

build() 中程式碼挺長的,總結起來就一句話:就是將 API 介面中的方法進行解析,構造成 ServiceMethod,交給下面的 OkHttpCall 使用。

基本上做的事情就是:

  1. 建立 CallAdapter ;
  2. 建立 ResponseConverter;
  3. 根據 API 介面方法的註解構造網路請求方法;
  4. 根據 API 介面方法引數中的註解構造網路請求的引數;
  5. 檢查有無異常;

下面我們看看第二句重要的程式碼OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall

OkHttpCall 實現了 retrofit2.Call,我們通常會使用它的 execute()enqueue(Callback<T> callback) 介面。前者用於同步執行 HTTP 請求,後者用於非同步執行。我們先看 execute()

@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 if (creationFailure instanceof RuntimeException) {
                throw (RuntimeException) creationFailure;
            } else {
                throw (Error) creationFailure;
            }
        }

        call = rawCall;
        if (call == null) {
            try {
                // 根據 serviceMethod 中的眾多資料創建出 Okhttp 中的 Request 物件
                // 注意的一點,會呼叫上面的 ParameterHandler.apply 方法來填充網路請求引數
                // 然後再根據 OkhttpClient 創建出 Okhttp 中的 Call
                // 這一步也說明了在 Retrofit 中的 OkHttpCall 內部請求最後會轉換為 OkHttp 的 Call
                call = rawCall = createRawCall();
            } catch (IOException | RuntimeException | Error e) {
                throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
                creationFailure = e;
                throw e;
            }
        }
    }

    if (canceled) {
        call.cancel();
    }

    // 執行 call 並轉換成響應的 response
    return parseResponse(call.execute());
}

execute() 做的就是將 Retrofit 中的 call 轉化為 OkHttp 中的 Call 。最後讓 OkHttp 的 Call 去執行。

主要包括三步:

  1. 呼叫createRawCall()建立了 okhttp3.Call,包括構造引數;
  2. 使用call.execute()執行網路請求;
  3. 解析網路請求返回的資料;

我們分別來看看createRawCall()parseResponse()這兩個方法:

// OkHttpCall類中
private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}

createRawCall() 函式中,我們呼叫了 serviceMethod.toCall(args) 來建立 okhttp3.Call,而在後者中,我們之前準備好的 parameterHandlers 就派上了用場。

然後我們再呼叫 serviceMethod.callFactory.newCall(request) 來建立 okhttp3.Call,這裡之前準備好的 callFactory 同樣也派上了用場,由於工廠在構造 Retrofit 物件時可以指定,所以我們也可以指定其他的工廠(例如使用過時的 HttpURLConnection 的工廠),來使用其它的底層 HttpClient 實現。

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();

    // 如果返回的響應碼不是成功的話,返回錯誤 Response
    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();
        }
    }

    // 如果返回的響應碼是204或者205,返回沒有 body 的成功 Response
    if (code == 204 || code == 205) {
        rawBody.close();
        return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
        // 將 body 轉換為對應的泛型,然後返回成功 Response
        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.Call#execute() 來執行網路請求,這個方法是阻塞的,執行完畢之後將返回收到的響應資料。收到響應資料之後,我們進行了狀態碼的檢查,通過檢查之後我們呼叫了 serviceMethod.toResponse(catchingBody) 來把響應資料轉化為了我們需要的資料型別物件T。

// ServiceMethod類中
R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
}

serviceMethodtoResponse 函式中,我們之前準備好的 responseConverter 也派上了用場。我們分別看下:

  1. responseConverter這個例項哪裡來?
  2. ResponseConverterconvert()方法幹了什麼?

預設的Converter

#1. responseConverter這個例項哪裡來?

ServiceMethod.Builder類中,我們找到了它的賦值的地方:

// 在ServiceMethod.Builder類中
public ServiceMethod build() {
      // 建立預設的CallAdapter
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }

      // 建立預設的ResponseConverter
      responseConverter = createResponseConverter();

      //...省略其他程式碼...
}

很明顯,在build()方法中同時建立了預設的CallAdapter和ResponseConverter。我們先繼續前往createResponseConverter關注ResponseConverter:

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(Type type, Annotation[] annotations)去找:

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");

    // 根據介面方法的返回型別、註解等資訊找到對應的ResponseConverter
    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;
        }
    }

    // 找不到任何ResponseConverter的話,就拋異常
    StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
            .append(type)
            .append(".\n");
    if (skipPast != null) {
        builder.append("  Skipped:");
        for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
        }
        builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = converterFactories.size(); i < count; i++) {
        builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
}

Retrofit 類內部,將遍歷一個 converterFactories 列表,讓工廠們提供,如果最終沒有工廠能(根據 returnTypeannotations)提供需要的 ResponseConverter,那將丟擲異常。而這個工廠列表我們可以在構造 Retrofit 物件時進行新增。

還記得我們在使用Retrofit.Builder構造Retrofit物件的時候,預設新增的converterFactory嗎?

public Retrofit build() {

      //...省略其他程式碼...

      // 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());      // 預設的Converter
      converterFactories.addAll(this.converterFactories);   // 我們自定義的Converter

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
#2. ResponseConverterconvert()方法幹了什麼?

我們看看這個內建轉換器(BuildInConverters)是什麼東西:

final class BuiltInConverters extends Converter.Factory {
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        // 內建的BuiltInConverters直接返回ResponseBody或者Void型別
        if (type == ResponseBody.class) {
            return Utils.isAnnotationPresent(annotations, Streaming.class)
                    ? StreamingResponseBodyConverter.INSTANCE
                    : BufferingResponseBodyConverter.INSTANCE;
        }
        if (type == Void.class) {
            return VoidResponseBodyConverter.INSTANCE;
        }
        return null;
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
            return RequestBodyConverter.INSTANCE;
        }
        return null;
    }

    //...省略其他程式碼...

    static final class StreamingResponseBodyConverter
      implements Converter<ResponseBody, ResponseBody> {

        static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();

        @Override 
        public ResponseBody convert(ResponseBody value) {
            // 直接返回,不進行任何處理
            return value;
        }
    }
}

內建的BuiltInConverters會直接返回ResponseBody或者Void型別,不做其他任何的轉換操作,所以如果我們不新增任何ConverterFactory的預設情況下,我們定義的介面方法返回型別只能接受ResponseBody或者Void這兩種型別。

預設的CallAdapter

下面,我們來看下那三句重要程式碼中的最後一句return serviceMethod.adapt(okHttpCall);。ServiceMethod類中的adapt()方法如下:

// ServiceMethod類中
T adapt(Call<R> call) {
    return callAdapter.adapt(call);
}

這裡我們分別看下:

  1. 這個callAdapter例項哪裡來的?
  2. CallAdapter類的adapt()方法幹了什麼?
#1. 這個callAdapter例項哪裡來的?

這個callAdapter例項是在哪裡賦值的呢,我們找到了ServiceMethod.Builderbuild()方法,可以回到上面看看這個方法的原始碼,可以看到它是呼叫了createCallAdapter這個方法建立的,如下。

// ServiceMethod.Builder類中
private CallAdapter<T, R> createCallAdapter() {
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
    }

    // 介面方法返回的型別不能是void
    if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
    }

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

可以看到,callAdapter 還是由 Retrofit 類提供的。

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}


public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
                                         Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    // 根據介面方法的返回型別、註解等資訊找到對應的CallAdapter
    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;
        }
    }

    // 找不到任何CallAdapter,拋異常
    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
            .append(returnType)
            .append(".\n");
    if (skipPast != null) {
        builder.append("  Skipped:");
        for (int i = 0; i < start; i++) {
            builder.append(