十二、Retrofit2 源碼解析(絕對詳細)

Retrofit2 源碼解析

注意: 本文是對源碼的一個跟蹤梢莽,會對每一行代碼有具體的闡述萧豆,但是不會介紹 Retrofit 的設計模式。

Retrofit:一個 Restful 設計風格的 HTTP 網絡請求框架的封裝昏名′汤祝基于 OkHttp

A type-safe HTTP client for Android and Java

0. 基本使用

1、Retrofit 將我們的 HTTP API 轉換成一個 接口形式轻局。所以我們第一步定義一個 interface

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

2洪鸭、然后構建一個 Retrofit,通過 create 方法生成 GitHubService 的一個實現仑扑。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

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

3卿嘲、調用 listRepos 拿到 Call 實例,可以做同步或異步請求夫壁。

 Call<List<Integer>> repos = service.listRepos("octocat");

每個 Call 實例只能使用一次,但調用 clone() 將創(chuàng)建一個可以使用的新實例沃疮。

1. Retrofit 構建

1.1 Retrofit

首先看看 Retrofit 吧盒让,這個類里面有7個實例變量。我們根據類型和變量名先猜猜是干什么用的司蔬,留個大體印象即可邑茄。

  // 一個線程安全的、支持高效并發(fā)的HashMap俊啼,Key 是 Method肺缕,Value 是 ServiceMethod。Method 我們能猜到應該就是上面接口中定義的 listRepos,而這個方法中有很多注解同木,@GET浮梢、@Path 啥的,那這個 ServiceMethod 很有可能是這個方法的封裝彤路。而變量名帶個 Cache 說明秕硝,會把這個 Method 對應的 ServiceMethod 緩存起來。
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();

  // 想必你知道 Retrofit 就是基于 OkHttp 的封裝洲尊,那這個 Call.Factory远豺,明顯就是 Call 的工廠類。至于 Call 是干嘛的坞嘀,負責創(chuàng)建 HTTP 請求躯护,HTTP 請求被抽象為了 okhttp3.Call 類,它表示一個已經準備好丽涩,可以隨時執(zhí)行的 HTTP 請求棺滞;
  final okhttp3.Call.Factory callFactory;
  // 這個很好理解了,就是上面 基本使用 中的 baseUrl内狸,可是這是個 HttpUrl 類型的检眯,我們傳的可是 String 類型的呀,那估計是通過 Builder 做了處理的昆淡。
  final HttpUrl baseUrl;
  // Converter 根據字面意思可得 這應該是個轉換器锰瘸,用于把我們的 響應 轉換成特定的格式
  final List<Converter.Factory> converterFactories;
  // CallAdapter 根據字面意思,難道是對 Call 的一個適配昂灵?
  final List<CallAdapter.Factory> callAdapterFactories;
  // Executor 很熟悉了避凝,這是個回調 Executor,想必就是用來切換線程的了
  final @Nullable Executor callbackExecutor;
  // 這個就猜不出了眨补,只能暫時理解為一個標志位
  final boolean validateEagerly;

再來看看 Retrofit 的構造函數

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

并沒做什么特殊的處理管削,就是簡單的賦值,那想必所有初始化的操作都在 Builder 里了撑螺。

那么成功建立一個 Retrofit 對象的標準就是:配置好Retrofit 里的成員變量含思。

  • callFactory : 網絡請求 工廠
  • baseUrl :網絡請求的基本 Url 地址
  • converterFactories :數據轉換器 工廠集合
  • callAdapterFactories :網絡請求適配器 工廠集合
  • callbackExecutor :回調方法執(zhí)行器

1.2 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() {
      this(Platform.get());
    }

    // ... ...
    }

我們可以看到 Builder 與 Retrofit 的參數幾乎一樣,只是少了 serviceMethodCache甘晤,多了個 Platform含潘。這個 Platform 很重要。我們通過 Builder 的構造函數可以知道线婚,調用了 Platform.get()方法遏弱,然后賦值給自己的 platform 變量。 我們看看這個 Platform 類塞弊。

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();
  }
  
  // ... ...
 }

get 方法會去調用 findPlatform 方法漱逸,這個里面很明顯跟平臺相關泪姨,Class.forName 要求 JVM 根據 className 查找并加載指定的類,如果未找到則拋出 ClassNotFoundException 饰抒。這里很明顯我們分析 Android 平臺肮砾,所以會 return 一個 Android()對象。

//Platform 內部
static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

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

我們在這里面可以看到兩個重要的方法

  • defaultCallbackExecutor :這個方法返回的是個 Executor 循集,我們想到 Retrofit 正好有個 Executor 類型的變量唇敞,那么想必就是它了,它是 MainThreadExecutor 類型的咒彤,內部采用 handler 執(zhí)行任務疆柔。
  • defaultCallAdapterFactory :這個方法返回的是個 CallAdapter.Factory,Retrofit 成員變量中也正好有個 CallAdapter.Factory 類型的變量镶柱,所以說這個 Platform 很重要嘛旷档,跟我們 Retrofit 類中的兩個成員變量都有重大的關系。這里最終返回的是個 ExecutorCallAdapterFactory 歇拆,話說我們一開始就不知道這個 CallAdapter 是什么鞋屈,更不用說這個 Factory 了,那我們先看看這個 ExecutorCallAdapterFactory 吧故觅。
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

  //... ... 省略
}

這里我們可以看到厂庇,把我們傳進來的 Executor 保存起來了,這個 Executor 想必就是 MainThreadExecutor 了输吏。至于 get 方法权旷,我們暫時還不知道哪里用到了,所以后面的暫時不看了贯溅,到了這里還是不知道 CallAdapter.Factory 干嘛用的拄氯。

看來 Builder 方法很復雜呀,寫了這么多只是講了個 Platform它浅,不過幸好這里面也包括了 Executor 和 CallAdapter.Factory 译柏,那么現在我們正式看看 Builder.build()方法。

public Retrofit build() {
      // 這一句告訴我們姐霍,baseUrl 是必不可少的鄙麦。
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      // 這里如果你沒配置 callFactory , 會默認配置為 OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      // 同樣的,沒配置的話镊折,會默認配置為 Platform 的 defaultCallbackExecutor黔衡,這里我們之前分析過,它所返回的就是 MainThreadExecutor
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //這里會把你所配置的 CallAdapter.Factory 加到 List 里去腌乡,最后把 Platform 默認的 defaultCallAdapterFactory 即 ExecutorCallAdapterFactory 加到 List 的最后邊,
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      //這里一樣會把你配置的 Converter.Factory 加到 List 里去夜牡,但是會把一個 BuiltInConverters 加到第一個与纽,而不是最后一個侣签,請注意這點。
      // 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.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);

      //最后返回一個 Retrofit 對象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

到這里急迂,我們的 Retrofit 就構建完成了影所。如果按照我們 基本使用 中的例子,那么此刻僚碎,Retrofit 成員變量的值如下:

  • serviceMethodCache :暫時為空的 HashMap 集合
  • callFactory : OkHttpClient 對象
  • baseUrl : 根據配置的baseUrl " https://api.github.com/ " 字符串, 構建出了一個 HttpUrl 對象
  • converterFactories :一個 ArrayList 對象勺阐,里面存放著一個BuiltInConverters 對象
  • callAdapterFactories :一個 ArrayList 對象卷中,里面存放著一個 ExecutorCallAdapterFactory 對象
  • callbackExecutor :MainThreadExecutor 對象
  • validateEagerly :默認值 false

2. 創(chuàng)建網絡請求接口實例,即 GitHubService service = retrofit.create(GitHubService.class);

接下來我們看看是怎樣獲得 GitHubService 實例的渊抽。
同樣上源碼蟆豫,注意這里的 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, @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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

這里我們看到了 validateEagerly 變量十减,讓我們看看它到底控制了什么。進 eagerlyValidateMethods 方法愤估。

  private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }
  
  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    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;
  }

這里又見到了 Platform 帮辟,在 Retrofit.Builder 我們知道它返回的是 Android() 對象。 接著是個 循環(huán) 玩焰,循環(huán)取出接口中的 Method 由驹,接著調用 loadServiceMethod 。 loadServiceMethod 里面會根據 Method 生成一個 ServiceMethod震捣,然后存入 serviceMethodCache 荔棉, 那么我們大概知道,這是屬于提前驗證蒿赢,會提前把接口中每個方法進行解析得到一個 ServiceMethod 對象润樱,然后存入緩存中。 在 loadServiceMethod 中會取緩存中的值羡棵,如果有就直接返回 ServiceMethod壹若。

由此可以知道 validateEagerly 變量是用于 判斷是否需要提前驗證解析的。

create 方法中 繼續(xù)往下走皂冰,會看到 return 一個 代理對象 Proxy 店展,并轉成了 T 類型,即 GitHubService 秃流。
此時我們這句代碼 GitHubService service = retrofit.create(GitHubService.class); 中的 service 有值了赂蕴,它指向一個 實現了 GitHubService 接口的 代理對象 Proxy 。

3. 拿到 Call 對象 舶胀, 即 Call<List<Repo>> repos = service.listRepos("octocat");

這里我們的 service 是個代理對象概说,所以執(zhí)行 listRepos 方法時碧注, 會先走 InvocationHandler 中的 invoke 方法。

  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, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            // 如果這個方法是聲明在 Object 類中糖赔,那么不攔截萍丐,直接執(zhí)行
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            // 這個總是返回的false,所以不用關心
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }

            // 下面三行代碼非常重要放典,重點分析逝变,分別對應 3.1 3.2 3.3 三個小節(jié)
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

3.1 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);

首先 ServiceMethod 我們之前猜測過,應該是對 Method 的一個封裝奋构, 而這個 loadServiceMethod 壳影,如果你還記得的話,我們在 create 的時候就碰到過声怔,eagerlyValidateMethods 這個方法內部調用過 loadServiceMethod 态贤,是為了加載這個 ServiceMethod 。現在我們來深入分析這個 loadServiceMethod 方法醋火。

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    // 首先從 緩存 serviceMethodCache 中取 ServiceMethod 悠汽,如果存在就返回,不存在繼續(xù)往下走芥驳。
    // 也就是說 我們的 ServiceMethod 只會創(chuàng)建一次柿冲。
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      //這里又從緩存取了一遍,看到這里有沒有一種熟悉的感覺兆旬,是不是跟 DCL 單例模式特別像假抄,雙重校驗。
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

到這里其實 loadServiceMethod 已經分析完了丽猬,很簡單宿饱,就是個 DCL 單例模式,然后獲得 ServiceMethod 脚祟。
那其實我們現在的分析任務就很明確了谬以,弄清楚這個 ServiceMethod 究竟是什么 。

3.1.1 ServiceMethod 分析
 final class ServiceMethod<R, T> {
  // ... 省略部分代碼
  private final okhttp3.Call.Factory callFactory;
  private final CallAdapter<R, T> callAdapter;
  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;

  // 同樣先猜猜什么意思吧
  // 應該是網絡請求的 Http 方法由桌,比如 GET为黎、POST 啥的
  private final String httpMethod;
  // 相對地址 ,應該就是 "user/{user}/repos" 這一段
  private final String relativeUrl;
  // http 請求頭
  private final Headers headers;
  // 網絡請求的 http 報文的 body 的類型
  private final MediaType contentType;
  // 是否有 body
  private final boolean hasBody;
  // post 提交數據時行您,是否使用 表單提交 方式
  private final boolean isFormEncoded;
  // post 提交數據時铭乾,是否使用 Mutipart 方式,一般用來文件上傳
  private final boolean isMultipart;
  // 方法參數處理器娃循,應該是解析方法中的 參數 的吧炕檩,這個估計也得詳細分析下。
  private final ParameterHandler<?>[] parameterHandlers;

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }

  // ... 省略部分代碼

首先看看 ServiceMethod 的構造方法捌斧。 也是通過建造者模式構建的笛质。其中很多變量其實都很熟悉了吹泡,比如 callFactory 、 baseUrl 经瓷。 對于 callAdapter、responseConverter 我們別弄混了洞难,我們在 Retrofit 類中的變量是 callAdapterFactories 和 converterFactories 舆吮, 是它們的工廠,是生產它們的地方队贱。

接下來看 Builder 吧色冀,畢竟這是真正做事的。

  public ServiceMethod build() {
      // 拿到具體的 CallAdapter 即 網絡請求適配器柱嫌,具體看 3.1.1.1
      callAdapter = createCallAdapter();
      // 根據上面拿到的 callAdapter 獲取 響應類型锋恬,在 3.1.1.1 小節(jié)分析完后可知道
      // 在我們的例子中 responseType = java.util.List<java.lang.Integer>
      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?");
      }
      // 獲取 響應轉換器 ,具體看 3.1.1.2 小節(jié)
      responseConverter = createResponseConverter();
      // 解析網絡請求接口中方法的注解编丘,這里我們就只有一個 @GET 注解与学,具體看 3.1.1.3 小節(jié)
      // 這里解析完可以拿到 Http 請求方法、請求體嘉抓、相對 url索守、相對 url 中的參數
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      //解析完方法上的注解后,做校驗
      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).");
        }
      }

      // 解析當前方法的參數抑片,這里就我們的例子而言
      // parameterAnnotationsArray 就是 @Path 卵佛,所以這里的 length 就是 1
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        // parameterTypes 是參數類型,就本例而言是 String
        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.");
        }
        // 解析參數
        // p : 0
        // parameterType : String
        // parameterAnnotations : 雖然是數組敞斋,但是就一個元素 @Path
        // 這個 parseParameter 就不分析了截汪,大家自己看看源碼就清楚了,無非就是構建 ParameterHandler 數組植捎,而這個 ParameterHandler 其實就是負責解析 API 定義時每個方法的參數衙解,并在構造 HTTP 請求時設置參數
        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);
    }
3.1.1.1 createCallAdapter ()
  private CallAdapter<T, R> createCallAdapter() {
      // 拿到網絡請求接口里方法的返回值類型鸥跟,在我們的例子中會返回如下類型
      // retrofit2.Call<java.util.List<java.lang.Integer>>
      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.");
      }
      // 拿到方法的 注解 ,在我們的例子中就是如下所示医咨,大家可以自己實驗下
      // @retrofit2.http.GET(value=users/{user}/repos)
      Annotation[] annotations = method.getAnnotations();
      try {
        // 拿到注解后枫匾,返回個 CallAdapter ,跟進去看看究竟是做了什么
        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);
      }
    }


  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    // 這里會去調用 nextCallAdapter
    return nextCallAdapter(null, returnType, annotations);
  }

  // 這里的參數大家注意
  // skipPast 上面?zhèn)鞯氖?null
  // returnType 就是  retrofit2.Call<java.util.List<java.lang.Integer>>
  // annotations 在我們的例子中就是 @retrofit2.http.GET(value=users/{user}/repos)
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    // callAdapterFactories 是一個 ArrayList 對象拟淮,里面存放著一個 ExecutorCallAdapterFactory 對象 干茉,這個是在 Retrofit Builder 的時候創(chuàng)建的,也就是我們上面所說的生產 CallAdapter 的地方很泊,大家可以回過頭去看看角虫。 這里的 skipPast 是null沾谓, 所以 indexOf 肯定返回的 -1, 所以這里 start = 0
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    // 循環(huán)戳鹅, 這里由于我們的 callAdapterFactories 只有一個 元素均驶, 所以直接看 ExecutorCallAdapterFactory 的 get方法
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    // 錯誤信息 builder
    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("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

到這里,我們別忘了我們是在干嘛枫虏,我們是在獲取 CallAdapter<T, R> 妇穴,好了,繼續(xù)看 ExecutorCallAdapterFactory 的 get 方法隶债。 解釋都在代碼注釋里喲腾它,一定要看看才知道現在到底是在干啥。話說源碼分析死讹,還是得靠自己認認真真讀一次源碼才行瞒滴。

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // getRawType 會返回該類型的原始類類型 , 比如傳進去的是 List<? extends Runnable> 會返回 List.class
    // 那么在我們的例子中,我們的 returnType 是 retrofit2.Call<java.util.List<java.lang.Integer>>
    // 那么 getRawType 后赞警,返回的是 retrofit2.Call 妓忍,所以這里是相等的
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    // 根據 returnType 拿到 responseType ,這里就不跟進了仅颇,可以自己去看看
    // 在我們的例子中单默, responseType = java.util.List<java.lang.Integer>
    final Type responseType = Utils.getCallResponseType(returnType);
    // 最后返回一個 CallAdapter
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

到這里,其實我們大概知道這個 CallAdapter 有什么用了忘瓦,就是提供兩個東西

  • 網絡請求響應要返回的類型 responseType
  • retrofit2.Call< T > 搁廓,注意這里不是 okhttp3 下的 Call ,這里暫不深究耕皮。

因為我們不要忘了現在在做什么境蜕,我們現在是在獲取 ServiceMethod 中的 callAdapter 變量值。所以看到這里返回了一個 CallAdapter 對象即可凌停。

3.1.1.2 createResponseConverter ()

這里個方法是獲取 響應轉換器粱年, 就是把網絡請求得到的響應數據轉換成相應的格式。

  private Converter<ResponseBody, T> createResponseConverter() {
      // 拿到方法上所有的注解罚拟,在我們的例子中就只有 @GET 注解
      Annotation[] annotations = method.getAnnotations();
      // 這里的 responseType 就是上面我們得到的 List<Integer>
      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);
      }
    }

這里想必大家也知道套路了台诗,跟獲取 CallAdapter 是一樣的,代碼就不貼了赐俗,代碼里同樣是循環(huán)遍歷 Retrofit 里的 converterFactories 變量拉队。而這個 converterFactories 在我們的例子中是沒有設置轉換器的,所以它也只有一個默認的元素阻逮,即 BuiltInConverters 粱快。 那么我們直接查看 它的 responseBodyConverter 方法。

 final class BuiltInConverters extends Converter.Factory {
  // 注意這里的參數,別忘了到底是什么
  // type : 就是我們的 responseType 事哭,即 List<Integer>
  // annotations : 這里我們方法的注解只有一個漫雷,所以就是 @GET
  @Override
  public 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;
  }

通過這里我們可以知道,其實它會返回 null 鳍咱。 所以我們 ServiceMethod 中的 Builder 中的 responseConverter 變量就等于 null 降盹。

3.1.1.3 parseMethodAnnotation ()

我們來看看 解析方法注解 ,注意我們例子中這個方法里傳的參數是 @GET 注解

   private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        //我們這里是 GET 注解谤辜,所以進這個方法
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      }
      // 省略后續(xù)代碼澎现,后續(xù)還有很多其他類型的判斷
    }


   // 這里的三個參數的值
   // httpMethod : GET
   // value : users/{user}/repos
   // hasBody : false
   private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      // 此處判斷 httpMethod 的值是否存在,說明只允許一個 HTTP 方法存在
      if (this.httpMethod != null) {
        throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // 下面是解析 value 中的 相對 url
      // Get the relative URL path and existing query string, if present.
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError("URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }

      this.relativeUrl = value;
      // 相對地址中的參數名字每辟,這里不具體分析了,可以把結果告訴你
      // 在我們的例子中 value = “users/{user}/repos”
      // 這里的 relativeUrlParamNames 是個 Set<String> 集合 干旧,里面只有一個元素 user 渠欺。
      this.relativeUrlParamNames = parsePathParameters(value);
    }

至此,我們的 Builder 把 Http 的方法以及它的 Url 給分析完了椎眯,現在只剩 參數解析了挠将。參數解析在 ServiceMethod 的 build 方法里已經講過了 ,記得看注釋编整。
呼~ 終于講完了 ServiceMethod 的構造舔稀。這么大篇幅,由此可以看出 ServiceMethod 這個類非常重要≌撇猓現在來總結一下内贮,我們究竟擁有了些什么。

  • callFactory : ExecutorCallAdapterFactory 實例
  • callAdapter : ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 實例
  • baseUrl : HttpUrl 實例
  • responseConverter : 由于我們沒設置汞斧,所以為 null
  • httpMethod : 字符串 GET
  • relativeUrl :字符串 users/{user}/repos
  • headers : 沒有設置 Headers 夜郁,所以為 null
  • contentType : null
  • hasBody : false
  • isFormEncoded : false
  • isMultipart : false
  • parameterHandlers : 就我們例子而已,該數組有一個元素粘勒,Path 對象竞端,它是 ParameterHandler 抽象類里的一個靜態(tài)內部類。

由此可以看出庙睡,ServiceMethod 對象包含了訪問網絡的所有基本信息事富。

好吧,接下來還是得繼續(xù)前行乘陪,別忘了统台,我們構建 ServiceMethod 只是在 invoke 方法內,并且這還只是第一步暂刘。接下來看第二步饺谬。

3.2 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

這里是 new 一個 OkHttpCall 對象,這個 OkHttpCall 是 Retrofit 的 Call,它里面就是做請求的地方募寨,會有 request族展、enqueue 等同步、異步請求方法拔鹰,但是在這里面真正執(zhí)行請求的是 okhttp3.Call 仪缸,即把請求委托給 okHttp 去執(zhí)行。下面簡要看看它的構造方法和一些成員變量吧列肢,因為這里只是 new 操作恰画,所以暫時不分析其余方法,用到的時候再看瓷马。

 final class OkHttpCall<T> implements Call<T> {
  // 含有所有網絡請求參數信息的 ServiceMethod
  private final ServiceMethod<T, ?> serviceMethod;
  private final @Nullable Object[] args;

  private volatile boolean canceled;

  // 實際進行網絡請求的 Call
  private @Nullable okhttp3.Call rawCall;
  @GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
  private @Nullable Throwable creationFailure;
  @GuardedBy("this")
  private boolean executed;

  // 傳入配置好的 ServiceMethod 和 請求參數
  OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

這樣就把 OkHttpCall 給構建好了拴还,接下來看第三步碎绎。

3.3 return serviceMethod.adapt(okHttpCall);

直接上代碼

 T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

這是 前面構建好的 ServiceMethod 中的 adapt 方法挚躯,會去調用 callAdapter 的 adapt 方法,我們知道 ServiceMethod 中的 callAdapter 是 ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 實例合蔽。而這個實例的 adapt 方法會返回一個 ExecutorCallbackCall 對象怀骤。

 <!-- ExecutorCallAdapterFactory 內部類 -->
 static final class ExecutorCallbackCall<T> implements Call<T> {
    // 這里在之前創(chuàng)建ExecutorCallAdapterFactory時费封,就知道它的值了,就是 MainThreadExecutor 蒋伦,用來切換線程的
    final Executor callbackExecutor;
    // 這就是剛剛傳進來的 OkHttpCall
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

到這里為止弓摘,我們已經成功的返回了一個 Call<List<Integer>>

4. 調用 Call 的 enqueue

趁熱打鐵,我們執(zhí)行異步請求痕届,看看怎樣切換線程的韧献。

 <!-- ExecutorCallbackCall 內部 -->
 @Override
 public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      // 真正的 Call 去執(zhí)行請求
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          // 回調后 利用 MainThreadExecutor 中的 Handler 切換到主線程中去。
          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);
            }
          });
        }
      });
    }

可以看到是 delegate 執(zhí)行了 enqueue 操作研叫,而 delegate 就是我們的 OkHttpCall 势决,在 OkHttpCall 里的 enqueue 方法是這樣工作的。
通過 okhttp3.Call call = serviceMethod.toCall(args); 構建一個真正執(zhí)行請求的 Call 蓝撇,即把請求交給 okhttp 去完成果复。而構建一個 Call 利用到了 ServiceMethod 中的 ParameterHandler 對象,這個對象是用來處理參數的渤昌。 它會把具體參數的值與 RequestBuilder 綁定起來虽抄。當然也用到了 ServiceMethod 自己,ServiceMethod 類似請求響應的大管家独柑。

別忘了拿到響應后迈窟,在 okhttp3.Callback 中會去調用 response = parseResponse(rawResponse); 將響應轉換成自己想要的格式,即定義的 Converter 忌栅。

到這里終于結束了车酣,當然在響應解析這里還有許多沒講曲稼,但是 Retrofit 一個主體的流程已經走完了。真累湖员。贫悄。。
沒啥總結的了娘摔,這篇文章只是用來跟蹤具體的源碼窄坦,具體到每一句代碼都有解釋。至于 Retrofit 的設計思路凳寺,別的文章都有講鸭津。
總之,在自己跟著分析完這么一大段后肠缨,已經對 Retrofit 相當熟悉了逆趋,遇到問題,相信也可以定位到源碼中去找到問題的根源晒奕,然后解決父泳,至此,目標已達成吴汪。

參考
https://blog.csdn.net/carson_ho/article/details/73732115
http://www.reibang.com/p/fb8d21978e38
https://blog.csdn.net/justloveyou_/article/details/72783008
https://imququ.com/post/four-ways-to-post-data-in-http.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蒸眠,隨后出現的幾起案子漾橙,更是在濱河造成了極大的恐慌,老刑警劉巖楞卡,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霜运,死亡現場離奇詭異,居然都是意外死亡蒋腮,警方通過查閱死者的電腦和手機淘捡,發(fā)現死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來池摧,“玉大人焦除,你說我怎么就攤上這事∽魍” “怎么了膘魄?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長竭讳。 經常有香客問我创葡,道長,這世上最難降的妖魔是什么绢慢? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任灿渴,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘骚露。我一直安慰自己蹬挤,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布荸百。 她就那樣靜靜地躺著闻伶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪够话。 梳的紋絲不亂的頭發(fā)上蓝翰,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音女嘲,去河邊找鬼畜份。 笑死,一個胖子當著我的面吹牛欣尼,可吹牛的內容都是我干的爆雹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼愕鼓,長吁一口氣:“原來是場噩夢啊……” “哼钙态!你這毒婦竟也來了?” 一聲冷哼從身側響起菇晃,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤册倒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后磺送,有當地人在樹林里發(fā)現了一具尸體驻子,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年估灿,在試婚紗的時候發(fā)現自己被綠了崇呵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡馅袁,死狀恐怖域慷,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情汗销,我是刑警寧澤芒粹,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站大溜,受9級特大地震影響化漆,放射性物質發(fā)生泄漏。R本人自食惡果不足惜钦奋,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一座云、第九天 我趴在偏房一處隱蔽的房頂上張望疙赠。 院中可真熱鬧,春花似錦朦拖、人聲如沸圃阳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捍岳。三九已至,卻和暖如春睬隶,著一層夾襖步出監(jiān)牢的瞬間锣夹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工苏潜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留银萍,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓恤左,卻偏偏與公主長得像贴唇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子飞袋,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容