Retrofit源碼分析

1. 概述

Retrofit和OkHttp都來自于Square公司拾积,而且都是在用來處理HTTP請求的翠肘,先來看下用OkHttp處理HTTP請求的實(shí)現(xiàn):

String url = "https://api.github.com/users/octocat/repos";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url(url)
        .build();
client.newCall(request).enqueue(new okhttp3.Callback() {
    @Override
    public void onFailure(okhttp3.Call call, IOException e) {

    }

    @Override
    public void onResponse(okhttp3.Call call, Response response) throws IOException {
        List<Repo> repos = JSON.parseArray(response.body().toString(), Repo.class);
    }
});

可以看到在發(fā)起HTTP請求之前需要構(gòu)造Request對象,請求完成后還需要將Response轉(zhuǎn)化成所需要的對象,如果每一個(gè)HTTP請求都要這么復(fù)雜构订,那對于需要成百上千個(gè)HTTP請求的應(yīng)用來說無疑是多了很多的重復(fù)代碼刊驴,對于一個(gè)追求完美的程序員來說是無法容忍的捐寥;因此Square公司推出了Retrofit框架福贞,Retrofit的中文意思是改造撩嚼,顧名思義就是在OkHttp的基礎(chǔ)上的進(jìn)行的一次升級和封裝,Retrofit通過定義接口的方式來構(gòu)建Request對象,通過Converter將Response轉(zhuǎn)化為需要的對象完丽,這就是Retrofit存在的意義恋技,下面看一下通過Retrofit框架實(shí)現(xiàn)與上面一樣的功能:

// 構(gòu)建Retrofit實(shí)例,一般都是通過單例模式創(chuàng)建的逻族,所以一般會創(chuàng)建一個(gè)Manager類來創(chuàng)建和管理Retrofit對象
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        // 添加一個(gè)用來創(chuàng)建Converter實(shí)例的工廠蜻底,該工廠是針對于json字符串的
        .addConverterFactory(FastJsonConverterFactory.create())
        .build();

// 在一個(gè)項(xiàng)目中,都是會對HTTP請求進(jìn)行分類的聘鳞,每一個(gè)分類都會創(chuàng)建一個(gè)與之對應(yīng)的一個(gè)接口(比如下面的GitHubService接口)
// 每一個(gè)接口包含多個(gè)方法薄辅,每一個(gè)方法對應(yīng)于一個(gè)HTTP請求(執(zhí)行的時(shí)候會根據(jù)方法來構(gòu)建Request對象)
// 每一個(gè)方法的返回值都是一個(gè)Call對象,默認(rèn)是ExecutorCallbackCall對象抠璃,針對于rxjava2就是返回的就是Observable對象
public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}

// 下面就是發(fā)起HTTP的代碼站楚,相比于OkHttp來說簡化了Request對象的構(gòu)建和Response的解析
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, retrofit2.Response<List<Repo>> response) {
        List<Repo> repoList = response.body();
    }

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

    }
});

上面代碼中提到的Call對象,其實(shí)是對OkHttp中RealCall的封裝搏嗡,這樣的設(shè)計(jì)也體現(xiàn)了一種設(shè)計(jì)模式(門面模式):

門面模式(Facade Pattern)也叫做外觀模式窿春,是一種比較常用的封裝模式,其定義如下:
Provide a unified interface to a set of interfaces in a subsystem.
Facade defines a higher-level interface that makes the subsystem easier to use.
(要求一個(gè)子系統(tǒng)的外部和內(nèi)部的通信必須通過一個(gè)統(tǒng)一的對象進(jìn)行彻况。門面模式提供一個(gè)高層次的接口谁尸,
使得子系統(tǒng)更易于使用。)

所以Retrofit示例代碼中提到的Call對象就是門面模式中說到的統(tǒng)一的對象纽甘。
Retrofit源碼地址

2. 預(yù)備知識

2.1 Java編程語言中的Type

在Retrofit中會對Method實(shí)例(對應(yīng)上面的例子,就是GitHubService的listRepos方法對應(yīng)的實(shí)例)進(jìn)行解析,因此會對Method實(shí)例的返回值類型和參數(shù)類型進(jìn)行解析抽碌,所以這里帶大家了解一下Java編程語言中的Type:


Type是Java 編程語言中所有類型的公共高級接口悍赢,Java 編程語言中的類型包括(其中后面四種類型是泛型的三種表現(xiàn)形式):
1 基本類型:也就是我們所說的java中的8中基本類型。
2 原始類型(raw types):對應(yīng)Class货徙。
3 類型變量(TypeVariable):
  該接口代表各種類型變量的公共接口左权,如Collection<T>中的T就是一個(gè)類型變量。
  主要方法:
  Type[] getBounds():獲取上邊界Type數(shù)組痴颊。
4 參數(shù)化類型(ParameterizedType):
  該接口代表參數(shù)化類型赏迟,例如Collection<String>。
  主要方法:
  Type[] getActualTypeArguments():獲取參數(shù)化類型中的所有類型的數(shù)組蠢棱。
  Type getRawType():獲取參數(shù)化類型中<>前面的類型锌杀。
5 泛型數(shù)組類型(GenericArrayType):
  該接口代表一種數(shù)組類型,其組件類型為參數(shù)化類型或類型變量
  泻仙,例如參數(shù)化類型數(shù)組Map<String, String>[]map和類型變量數(shù)組T[] arr糕再。
  主要方法:
  Type getGenericComponentType():返回其組件類型。

除了上面泛型的三種表現(xiàn)形式外還有一種并不屬于Java類型的表達(dá)形式:
通配符類型(WildcardType):
該接口代表通配符類型表達(dá)式玉转,例如 如 ?突想、? extends Number 或 ? super Integer.
主要方法:
Type[] getUpperBounds():獲取上邊界Type數(shù)組。
Type[] getLowerBounds():獲取下邊界Type數(shù)組。

3. 源碼分析

我會根據(jù)上面的例子解析分析猾担,因此在分析的過程中會依賴上面的代碼
首先看一下Retrofit處理http請求的時(shí)序圖:


3.1 構(gòu)建Retrofit實(shí)例

上圖中的前8步通過建造者模式構(gòu)建了一個(gè)Retrofit實(shí)例

建造者模式(Builder Pattern袭灯,也叫生成器模式)的定義:
Separate the construction of a complex object from its representation so that 
the same construction process can create different representations.
(將一個(gè)復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示绑嘹。)

構(gòu)建的過程也是對Retrofit實(shí)例進(jìn)行初始化的過程稽荧,初始化的結(jié)果:
1> callFactory : 顧名思義是用來創(chuàng)建Call對象的,默認(rèn)為OkHttpClient類型對象圾叼,沒錯(cuò)蛤克,這就就是OkHttp中的OkHttpClient,通常情況下不會修改該默認(rèn)值夷蚊。
2> baseUrl:默認(rèn)值為HttpUrl.parse("https://api.github.com/")构挤,通常情況下在同一個(gè)項(xiàng)目中所有的HTTP請求URL的 protocol :// hostname[:port] 部分是相同的,即在項(xiàng)目中baseUrl對應(yīng)的值惕鼓,如果一個(gè)項(xiàng)目中HTTP請求URL的 protocol :// hostname[:port] 部分多余一種的話筋现,就需要多個(gè)Retrofit對象與之對應(yīng)。
3> converterFactories:顧名思義是用來保存Converter.Factory對象的容器(Converter.Factory是用來創(chuàng)建Converter對象的箱歧,Converter有兩個(gè)常用的方法requestBodyConverter和responseBodyConverter矾飞,說到這里相信大家應(yīng)該明白了Converter的作用了),默認(rèn)只包含一個(gè)BuiltInConverters對象呀邢,通過第4步就可以在converterFactories集合的末尾添加一個(gè)FastJsonConverterFactory對象洒沦,這也是為什么接口的方法中@Body注解的參數(shù)是RequestBody類型時(shí),就不會調(diào)用FastJsonRequestBodyConverter的convert方法的原因价淌。
4> callAdapterFactories:顧名思義是用來保存CallAdapter.Factory對象的容器(CallAdapter.Factory是用來創(chuàng)建CallAdapter對象的申眼,CallAdapter的adapt方法會得到Call<R>對象的代理,這里就用到了裝飾者模式)蝉衣,默認(rèn)只包含一個(gè)ExecutorCallAdapterFactory對象括尸,通過第5步就可以在ExecutorCallAdapterFactory對象的前面插入一個(gè)RxJava2CallAdapterFactory對象。
5> callbackExecutor:顧名思義就是用來控制Retrofit示例代碼中Callback執(zhí)行的線程病毡,默認(rèn)值為MainThreadExecutor濒翻,即默認(rèn)在主線程執(zhí)行。

上面5條都是根據(jù)源碼得到的啦膜,不可能在該篇文章中完全分析所有細(xì)節(jié)有送,只有自己親自查閱源碼才會收獲更多,我只會點(diǎn)到為止功戚,這樣你們可以更加快速的翻閱源娶眷。

3.2 創(chuàng)建GitHubService接口的實(shí)例

接下來看一下第9、10步的源碼:

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

可以看到使用了動態(tài)代理模式為GitHubService接口創(chuàng)建實(shí)例啸臀。

代理模式(Proxy Pattern)是一個(gè)使用率非常高的模式届宠,其定義如下:
Provide a surrogate or placeholder for another object to control access to it.
(為其他對象提供一種代理以控制對這個(gè)對象的訪問)

動態(tài)代理:
動態(tài)代理是在實(shí)現(xiàn)階段不用關(guān)心代理誰烁落,而在運(yùn)行階段才指定代理哪一個(gè)對象。

3.3 執(zhí)行GitHubService接口中的方法

第11步調(diào)用GitHubService接口中的方法豌注,此時(shí)InvocationHandler的invoke方法被執(zhí)行(即第12步)伤塌,對應(yīng)于上面的例子listRepos方法對應(yīng)的就是invoke方法中的參數(shù)method。

3.3.1 根據(jù)Method實(shí)例構(gòu)建ServiceMethod實(shí)例

第13步loadServiceMethod方法被調(diào)用轧铁,loadServiceMethod方法會根據(jù)Method實(shí)例構(gòu)建與之對應(yīng)的ServiceMethod實(shí)例:

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

為了提高運(yùn)行時(shí)的效率每聪,構(gòu)建ServiceMethod實(shí)例的過程中使用了緩存機(jī)制,對于已經(jīng)構(gòu)建過ServiceMethod實(shí)例的Method實(shí)例齿风,直接將緩存中與之對應(yīng)的ServiceMethod實(shí)例返回药薯,接下來的14到33步就是根據(jù)Method實(shí)例構(gòu)建ServiceMethod實(shí)例的過程:

// 第14步對應(yīng)的代碼
Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  // 對應(yīng)與上面例子,methodAnnotations保存的時(shí)GitHubService接口的listRepos方法的注解(即@GET("users/{user}/repos"))
  this.methodAnnotations = method.getAnnotations();
  // 對應(yīng)與上面例子救斑,parameterTypes保存的是GitHubService接口中l(wèi)istRepos方法的所以參數(shù)的類型
  this.parameterTypes = method.getGenericParameterTypes();
  // 對應(yīng)與上面例子童本,parameterAnnotationsArray保存的是GitHubService接口中l(wèi)istRepos方法的所以參數(shù)的注解
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

// 第15對應(yīng)的代碼
public ServiceMethod build() {
  // 第16步到21步,完成CallAdapter實(shí)例的創(chuàng)建,默認(rèn)為ExecutorCallAdapterFactory創(chuàng)建
  // 的CallAdapter實(shí)例脸候,對于rxjava2而言對應(yīng)的是RxJava2CallAdapter實(shí)例
  callAdapter = createCallAdapter();
  // 對應(yīng)于上面的例子穷娱,responseType代表的是List<Repo>
  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?");
  }
  // 第22步到27步,完成 Converter<ResponseBody, T> responseConverter 實(shí)例的創(chuàng)建运沦,
  // 對于fastjson而言對應(yīng)的是FastJsonResponseBodyConverter實(shí)例
  // 泵额,用于將ResponseBody中的json字符串轉(zhuǎn)化成指定類型的對象
  responseConverter = createResponseConverter();

  // 第28到第30步,用于解析方法上的注解携添,對應(yīng)于上面的例子就是對@GET("users/{user}/repos")的解析
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }

  // 方法上的注解解析完成后嫁盲,httpMethod為空代表方法上沒有@GET, @POST等類型的注解
  if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }

  // 對于沒有請求體的情況,方法上不應(yīng)該有@Multipart和@FormUrlEncoded注解
  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).");
    }
  }

  // 第31烈掠、32步 完成方法參數(shù)上注解的解析亡资,對應(yīng)于上面的例子就是對@Path("user")的解析
  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
    // 對參數(shù)的類型進(jìn)行檢查,不應(yīng)該包含 類型變量 和 通配符類型向叉,具體可以參考2.1
    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);
}
3.3.2 發(fā)起http請求
  // 第35步,創(chuàng)建OkHttpCall實(shí)例
  OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

  // 第36步嗦董,默認(rèn)情況下callAdapter代表ExecutorCallAdapterFactory創(chuàng)建的CallAdapter實(shí)例
  T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

  // 第37步母谎,返回ExecutorCallbackCall實(shí)例
  @Override public Call<Object> adapt(Call<Object> call) {
    return new ExecutorCallbackCall<>(callbackExecutor, call);
  }

  // 第39步enqueue方法發(fā)起http請求
 @Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");

  // delegate是OkHttpCall實(shí)例,enqueue方法中會創(chuàng)建Request對象
  delegate.enqueue(new Callback<T>() {
    @Override public void onResponse(Call<T> call, final Response<T> response) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          if (delegate.isCanceled()) {
            // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
            callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
          } else {
            callback.onResponse(ExecutorCallbackCall.this, response);
          }
        }
      });
    }

    @Override public void onFailure(Call<T> call, final Throwable t) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          callback.onFailure(ExecutorCallbackCall.this, t);
        }
      });
    }
  });
}

4 細(xì)節(jié)分析

第3步中只是粗略的分析了Retrofit處理HTTP請求的大致流程京革,那么這一節(jié)就會詳細(xì)分析一些關(guān)鍵點(diǎn)

4.1 CallAdapter實(shí)例的創(chuàng)建

第16步到21步,完成CallAdapter實(shí)例的創(chuàng)建奇唤,下面是Google官方對CallAdapter的adapt方法的注解:

  /**
   * Returns an instance of {@code T} which delegates to {@code call}.
   */
  T adapt(Call<R> call);

這句話也充分的說明CallAdapter是用來干嘛的了,同時(shí)也體現(xiàn)一種設(shè)計(jì)模式(裝飾者模式)匹摇,接下來看一下16步createCallAdapter方法的源碼:

private CallAdapter<T, R> createCallAdapter() {
  Type returnType = method.getGenericReturnType();
  // 返回值類型中不能包含類型變量和通配符表達(dá)式
  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.");
  }
  // 獲取方法上的注解,對應(yīng)于上面的示例就是獲取listRepos方法的注解 @GET("users/{user}/repos")
  Annotation[] annotations = method.getAnnotations();
  try {
    // 根據(jù)方法的返回值類型和注解來創(chuàng)建CallAdapter實(shí)例
    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);
  }
}

上面的蛛絲已經(jīng)很清楚來咬扇,下面直接看第17、18步的源碼:

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

  // 因?yàn)閟kipPast為null,所以start為0,
  int start = callAdapterFactories.indexOf(skipPast) + 1;
  // 默認(rèn)情況下callAdapterFactories包含一個(gè)ExecutorCallAdapterFactory對象廊勃,
  // 對于RxJava2CallAdapterFactory對象懈贺,有興趣的同學(xué)可以自己研究一下经窖,后面的分析過程中也只會基于ExecutorCallAdapterFactory對象進(jìn)行分析。
  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實(shí)例梭灿,就會拋出IllegalArgumentException異常
  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());
}

接下來看ExecutorCallAdapterFactory的get方法画侣,即第19步:

@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
  // 如果返回值的類型不是Call類型,返回null堡妒,那么上面第18步中就會拋出IllegalArgumentException異常
  if (getRawType(returnType) != Call.class) {
    return null;
  }
  // returnType必須是參數(shù)化類型(對應(yīng)于上面的例子配乱,returnType代表的是Call<List<Repo>>),否者會拋出IllegalArgumentException異常
  // responseType是參數(shù)化類型中的類型皮迟,對應(yīng)于上面的例子搬泥,responseType代表的是List<Repo>
  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);
    }
  };
}

到這里CallAdapter實(shí)例的創(chuàng)建完成了,總結(jié)一下關(guān)鍵點(diǎn):
1> 方法的返回值類型:必須是參數(shù)化類型伏尼,并且rawtype為Call類型忿檩,并且不能包含類型變量和通配符表達(dá)式,否者會拋出異常烦粒;
2> CallAdapter是用來為Call<R>創(chuàng)建一個(gè)代理對象T休溶,默認(rèn)情況下T是ExecutorCallbackCall類型,對應(yīng)于rxjava2情況下T通常是BodyObservable類型扰她。

4.2 Converter<ResponseBody, T>實(shí)例的創(chuàng)建

第22步到27步兽掰,完成 Converter<ResponseBody, T>實(shí)例的創(chuàng)建,接下來看一下第22步的源碼:

 // 該方法返回的Converter對象是用來將ResponseBody轉(zhuǎn)化成需要類型的對象徒役,
 // 對應(yīng)于上面的示例就是轉(zhuǎn)化成<List<Repo>類型的對象孽尽。
private Converter<ResponseBody, T> createResponseConverter() {
  Annotation[] annotations = method.getAnnotations();
  try {
    // 第19步中提到過,對應(yīng)于上面的例子忧勿,responseType代表的是List<Repo>
    // 對應(yīng)于上面的例子杉女,annotations對應(yīng)于listRepos方法的注解 @GET("users/{user}/repos")
    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);
  }
}

接下來看23、24步:

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

  // 因?yàn)閟kipPast為null,所以start為0
  int start = converterFactories.indexOf(skipPast) + 1;
  // 默認(rèn)情況下converterFactories包含一個(gè)BuiltInConverters對象鸳吸,
  // 在項(xiàng)目中一般都會配置一個(gè)針對于fastjson的FastJsonResponseBodyConverter對象熏挎。
  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;
    }
  }

  // 如果沒有找到合適的Converter<ResponseBody, T>實(shí)例,就會拋出IllegalArgumentException異常
  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());
}

接下來看一下25步:

// 如果方法的返回值為Call<ResponseBody>晌砾,那么BuiltInConverters的responseBodyConverter方法的返回值不會為null
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;
}

// 對應(yīng)于上面的例子坎拐,listRepos方法的返回值不是Call<ResponseBody>類型,
// 那么FastJsonConverterFactory的responseBodyConverter方法的返回值會被使用
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                        Retrofit retrofit) {
  return new FastJsonResponseBodyConverter<>(type, mParserConfig, featureValues, features);
}

到這里Converter<ResponseBody, T>實(shí)例的創(chuàng)建完成了养匈,總結(jié)一下關(guān)鍵點(diǎn):
1> Converter<ResponseBody, T>是用來將ResponseBody對象轉(zhuǎn)化成方法的返回值類型中的參數(shù)類型哼勇,對應(yīng)于上面的例子,就是List<Repo>類型呕乎。
2> 如果方法的返回值為Call<ResponseBody>积担,那么BuiltInConverters的responseBodyConverter方法的返回值不會為null并且會被使用;否者FastJsonResponseBodyConverter對象會被使用猬仁。

4.3 OkHttpCall發(fā)起HTTP請求

OkHttpCall的enqueue方法如下:

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

  okhttp3.Call call;
  Throwable failure;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
      try {
        // 創(chuàng)建OkHttp中的RealCall實(shí)例
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

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

  // 調(diào)用RealCall的enqueue方法發(fā)起HTTP請求
  call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      Response<T> response;
      try {
        // 請求成功后帝璧,對響應(yīng)體進(jìn)行解析
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        callFailure(e);
        return;
      }

      try {
        // 執(zhí)行callback的onResponse方法
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
      callFailure(e);
    }

    private void callFailure(Throwable e) {
      try {
        // 執(zhí)行callback的onFailure方法
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}

接下來看一下createRawCall和parseResponse方法:

private okhttp3.Call createRawCall() throws IOException {
  // 根據(jù)方法的參數(shù)構(gòu)建Request實(shí)例先誉,并且使用Request實(shí)例作為參數(shù)構(gòu)建RealCall實(shí)例
  okhttp3.Call call = serviceMethod.toCall(args);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();

  // Remove the body's source (the only stateful object) so we can pass the response along.
  rawResponse = rawResponse.newBuilder()
      .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
      .build();

  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    rawBody.close();
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    // 對應(yīng)與上面的例子,下面這句代碼會使用Converter<ResponseBody, T>實(shí)例將catchingBody轉(zhuǎn)化為List<Repo>類型對象聋溜。
    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;
  }
}

到這里OkHttpCall發(fā)起HTTP請求的過程分析完了谆膳。

5 總結(jié)

到這里源碼已經(jīng)分析完了,Retrofit處理HTTP請求主要流程為(為了便于說明撮躁,會用到上面的例子):
1> 首先創(chuàng)建Retrofit實(shí)例和GitHubService接口的實(shí)例漱病。
2> 然后調(diào)用GitHubService接口中的listRepos方法(對listRepos進(jìn)行解析,得到與之對應(yīng)serviceMethod對象把曼,然后調(diào)用serviceMethod對象的adapt方法得到listRepos方法的Call<List<Repo>>類型返回值)杨帽。
3> 調(diào)用Call的enqueue方法發(fā)起請求。

4.0 參考

Retrofit分析-漂亮的解耦套路

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗤军,一起剝皮案震驚了整個(gè)濱河市注盈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叙赚,老刑警劉巖老客,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異震叮,居然都是意外死亡胧砰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門苇瓣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尉间,“玉大人,你說我怎么就攤上這事击罪≌艹埃” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵媳禁,是天一觀的道長眠副。 經(jīng)常有香客問我,道長竣稽,這世上最難降的妖魔是什么侦啸? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮丧枪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘庞萍。我一直安慰自己拧烦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布钝计。 她就那樣靜靜地躺著恋博,像睡著了一般齐佳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上债沮,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天炼吴,我揣著相機(jī)與錄音,去河邊找鬼疫衩。 笑死硅蹦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的闷煤。 我是一名探鬼主播童芹,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鲤拿!你這毒婦竟也來了假褪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤近顷,失蹤者是張志新(化名)和其女友劉穎生音,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窒升,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缀遍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了异剥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瑟由。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖冤寿,靈堂內(nèi)的尸體忽然破棺而出歹苦,到底是詐尸還是另有隱情,我是刑警寧澤督怜,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布殴瘦,位于F島的核電站,受9級特大地震影響号杠,放射性物質(zhì)發(fā)生泄漏蚪腋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一姨蟋、第九天 我趴在偏房一處隱蔽的房頂上張望屉凯。 院中可真熱鬧,春花似錦眼溶、人聲如沸悠砚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灌旧。三九已至绑咱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枢泰,已是汗流浹背描融。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衡蚂,地道東北人窿克。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像讳窟,于是被迫代替她去往敵國和親让歼。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

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