Retrofit源碼解析

  • Retrofit在代碼中的構(gòu)建方式
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http:/xx/xx/xx/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
service = retrofit.create(APIService.class);
service.getCall();
  • 根據(jù)構(gòu)建方式,我們先來看一下Retrofit類源碼

(1)Retrofit中的七個重要的成員變量

//Method是Http的請求方法,ServiceMethod是網(wǎng)絡(luò)請求接口解析注解后的請求方法的對象
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
//網(wǎng)絡(luò)請求的工廠
  final okhttp3.Call.Factory callFactory;
//網(wǎng)路請求的基地址,與接口中配置的地址拼接起來就是完整的請求地址
  final HttpUrl baseUrl;
//數(shù)據(jù)轉(zhuǎn)換器工廠的集合,工廠的作用用于生產(chǎn)數(shù)據(jù)轉(zhuǎn)換器,比如converter-gson
  final List<Converter.Factory> converterFactories;
//網(wǎng)絡(luò)請求適配器的工廠集合,比如Call轉(zhuǎn)換成RxJava平臺的Call
  final List<CallAdapter.Factory> adapterFactories;
//用于執(zhí)行回調(diào),處理異步請求。在Android平臺默認使用的是MainThreadExcecutor主線程執(zhí)行器
  final @Nullable Executor callbackExecutor;
//布爾類型,是否需要立即解析接口中的方法,解析java接口中注解的請求方法和參數(shù)用到的
  final boolean validateEagerly;
//構(gòu)造方法
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
    this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

(2)Retrofit中靜態(tài)內(nèi)部類Builder

public static final class Builder {
    //基本上和Retrofit中成員變量一致
    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> adapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      // 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());
    }

    public Builder() {
      this(Platform.get());
    }

    Builder(Retrofit retrofit) {
      platform = Platform.get();
      callFactory = retrofit.callFactory;
      baseUrl = retrofit.baseUrl;
      converterFactories.addAll(retrofit.converterFactories);
      adapterFactories.addAll(retrofit.adapterFactories);
      // Remove the default, platform-aware call adapter added by build().
      adapterFactories.remove(adapterFactories.size() - 1);
      callbackExecutor = retrofit.callbackExecutor;
      validateEagerly = retrofit.validateEagerly;
    }

  (省略部分代碼)
    ........
    ........

    /**
     * Create the {@link Retrofit} instance using the configured values.
     * <p>
     * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
     * OkHttpClient} will be created and used.
     */
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

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

      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> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

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

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

成功建立一個Retrofit對象的標準:配置好Retrofit類里的成員變量,即配置好:
serviceMethod:包含所有網(wǎng)絡(luò)請求信息的對象
baseUrl:網(wǎng)絡(luò)請求的url地址
callFactory:網(wǎng)絡(luò)請求工廠
adapterFactories:網(wǎng)絡(luò)請求適配器工廠的集合
converterFactories:數(shù)據(jù)轉(zhuǎn)換器工廠的集合
callbackExecutor:回調(diào)方法執(zhí)行器

在Retrofit內(nèi)部類Builder默認的構(gòu)造方法中,我們可以看到調(diào)用了帶參數(shù)的構(gòu)造方法this(Platform.get()),那么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();
  }

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

  @IgnoreJRERequirement // Only classloaded and used on Java 8.
  static class Java8 extends Platform {
    @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);
    }
  }

  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);
      }
    }
  }
}
  • 其中findPlatform()方法中Class.forName("android.os.Build")

Class.forName(xxx.xx.xx)返回的是一個類。
Class.forName(xxx.xx.xx)的作用是要求JVM查找并加載指定的類,也就是說JVM會執(zhí)行該類的靜態(tài)代碼段
關(guān)于生成對象兩種方式的區(qū)別可以看這里初始化一個類,生成一個實例的時候,newInstance()方法和new關(guān)鍵字

  • Android回調(diào)中的線程切換

我們主要是看android,所以重點看其中靜態(tài)內(nèi)部類Android,該類中有一個defaultCallbackExecutor()的方法,返回的是Android中一個靜態(tài)內(nèi)部類MainThreadExecutor 的實例,我們可以看到在這里做了線程切換,采用Looper.getMainLooper()(主線程的looper)構(gòu)造了handler,post了Runnable。

(3)baseUrl說明

public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

 public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

關(guān)于Retrofit中的baseUrl并沒有強制怎么寫,我可以寫成https://api.github.com也可以寫成 https://api.github.com/repos/,區(qū)別在哪呢?

https://api.github.com的格式可以看成scheme://host[:port](此種類型是不是以 /(斜線) 結(jié)尾都可以,均不會拋出IllegalArgumentException異常);
https://api.github.com/repos/的格式可以看成scheme://host[:port]/path(此種類型必須以/(斜線) 結(jié)尾,否則會拋出IllegalArgumentException異常).

還是建議baseUrl統(tǒng)一以“/”結(jié)尾

(4)GsonConverter/GsonConverterFactory

addConverterFactory(Converter.Factory factory)就是將數(shù)據(jù)轉(zhuǎn)換器工廠添加到Retrofit的數(shù)據(jù)轉(zhuǎn)換器的集合中
GsonConverterFactory.create(Gson gson)/GsonConverterFactory.create(),創(chuàng)建了一個持有g(shù)son實例的Gson數(shù)據(jù)轉(zhuǎn)換器工廠,前者可以自己定義gson實例的一些特性,后者是采用了默認的gson實例。

(5)CallAdapter/CallAdapterFactory

addCallAdapterFactory(CallAdapter.Factory factory)同樣就是將網(wǎng)絡(luò)請求適配器工廠添加到Retrofit的網(wǎng)絡(luò)請求適配器的集合中

RxJava2CallAdapterFactory代碼很短,以下是部分代碼,其中Scheduler 是RxJava中的調(diào)度器,后面會介紹,通過create我們創(chuàng)建了一個RxJava2CallAdapterFactory,然后將其加到Retrofit的網(wǎng)絡(luò)請求適配器的集合中

/**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  private final @Nullable Scheduler scheduler;
  private final boolean isAsync;

  private RxJava2CallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }
  • 下面我們具體看一下RxJava2CallAdapterFactory
    RxJava2CallAdapterFactory繼承自CallAdapter.Factory,F(xiàn)actory是接口CallAdapter的一個內(nèi)部類,CallAdapter負責(zé)將Retroift中的Call轉(zhuǎn)換成java對象,
@POST("heart.do")
Call<ABaseBean>  addFriendShip(@Body HashMap addInfo);
@POST("heart.do")
Observable<ABaseBean> addFriendShip(@Body HashMap addInfo);
public interface CallAdapter<R, T> {
  
  Type responseType();

  T adapt(Call<R> call);

  abstract class Factory {
   
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

(1) Type responseType(),此處的Type就是Http請求返回的Response解析后的類型,并不是接口的返回類型,而是接口返回類型中泛型參數(shù)的實參,比如上述代碼中ABaseBean。
(2)T adapt(Call<R> call),T對應(yīng)相應(yīng)平臺的對象,比如RxJava2CallAdapter中T對應(yīng)Observable。
(3)get方法根據(jù)接口類型、注解類型獲取需要的CallAdapter
(4)getRawType獲取原始類型,在RxJava2CallAdapter中根據(jù)這個類型來選擇生成不同的CallAdapter

RxJava2CallAdapter中的adapt方法中,會將Retrofit.create()方法過程中生成的攜帶了ServiceMethod對象的OkHttpCall進行適配,后面會講到:

public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

上述判斷條件分別是根據(jù)getRawType中獲取到的類型生成的布爾值

(6)retrofit.create(xxx.class),創(chuàng)建網(wǎng)絡(luò)請求接口實例,create使用了外觀模式和動態(tài)代理模式

Retrofit中的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.callAdapter.adapt(okHttpCall);
          }
        });
  }

validateEagerly,這是上面提到過的Retrofit的七個重要的成員變量之一,是否提前驗證解析接口,如果為true,調(diào)用eagerlyValidateMethods方法,這部分調(diào)用的說明寫在下方代碼注釋中

private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();//獲取平臺,之前提到過Android、Java等
    for (Method method : service.getDeclaredMethods()) {//利用反射獲取到網(wǎng)絡(luò)請求接口中定義的method集合,遍歷各個method
      if (!platform.isDefaultMethod(method)) {//此方法點進去可以看到默認返回false,則這里條件默認為true
        loadServiceMethod(method);
      }
    }
  }

/**
*該方法采用了常規(guī)的保存到緩存以及從緩存中獲取目標對象的方式
*獲取的ServiceMethod是對應(yīng)接口中網(wǎng)絡(luò)請求的一個方法的封裝,其中包含了url以及配置參數(shù)等等
*/
  ServiceMethod<?, ?> loadServiceMethod(Method method) {
  //serviceMethodCache,這是上面提到過的Retrofit的七個重要的成員變量之一,緩存生成的http請求接口方法的
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;//如果從緩存中獲取到,則直接返回

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {//如果沒有獲取到,則創(chuàng)建并緩存到serviceMethodCache
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;//返回目標對象ServiceMethod
  }

接下來,我們回到Retrofit的create方法中,非常重要的來了,動態(tài)代理動態(tài)創(chuàng)建網(wǎng)路請求,我們選其中重要的代碼來看:

ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

loadServiceMethod上面已經(jīng)說過了,我們先來看看ServiceMethod這個類

ServiceMethod的成員變量:

  //生產(chǎn)網(wǎng)絡(luò)請求call的工廠
  final okhttp3.Call.Factory callFactory;
  //網(wǎng)絡(luò)請求適配器,使網(wǎng)絡(luò)請求適配不同平臺,比如RxJava平臺
  final CallAdapter<R, T> callAdapter;
   //網(wǎng)絡(luò)請求基地址
  private final HttpUrl baseUrl;
  //數(shù)據(jù)轉(zhuǎn)換器
  private final Converter<ResponseBody, R> responseConverter;
  //網(wǎng)絡(luò)請求的方法,比如GET、POST等等
  private final String httpMethod;
  //網(wǎng)絡(luò)請求的相對地址,與上面baseUrl拼接成完整的請求地址
  private final String relativeUrl;
  //網(wǎng)絡(luò)請求的頭部信息
  private final Headers headers;
 //網(wǎng)絡(luò)請求的http報文的body類型
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
//非常重要的:網(wǎng)絡(luò)請求接口中參數(shù)、方法的處理器,包括注解啊、參數(shù)啊等等
  private final ParameterHandler<?>[] parameterHandlers;

從loadServiceMethod方法中我們看到生成ServiceMethod時使用的也是構(gòu)建者模式,看一下ServiceMethod的內(nèi)部類Builder

Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();//網(wǎng)絡(luò)請求接口中的請求方法以及header等注解,比如POST/GET/Multipart/FormUrlEncoded/Headers
      this.parameterTypes = method.getGenericParameterTypes();//網(wǎng)路請求接口方法中參數(shù)的類型
      this.parameterAnnotationsArray = method.getParameterAnnotations();//網(wǎng)路請求接口方法中注解的內(nèi)容
    }

public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();//獲取該網(wǎng)絡(luò)請求適配器的數(shù)據(jù)返回類型

      ...省略部分代碼

      responseConverter = createResponseConverter();
      //遍歷網(wǎng)絡(luò)請求接口中方法的網(wǎng)絡(luò)請求方式(就是接口名稱上邊那些)的注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);//其中通過if判斷是否是哪種網(wǎng)絡(luò)請求方式做相應(yīng)解析
      }

     ...省略部分代碼

      /**
      * 解析網(wǎng)絡(luò)請求接口方法中的參數(shù)(注解和參數(shù))
      */
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];

        ...省略部分代碼

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];

       ...省略部分代碼

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

     ...省略部分代碼

      return new ServiceMethod<>(this);
    }

生成ServiceMethod,主要是解析了網(wǎng)絡(luò)請求接口中的注解和參數(shù)等,生成了相應(yīng)的網(wǎng)絡(luò)請求適配器和數(shù)據(jù)轉(zhuǎn)換器。

build中生成了ServiceMethod實例,我們分別來看看build方法中的關(guān)鍵步驟

    1. 生成網(wǎng)絡(luò)請求的適配器 callAdapter = createCallAdapter();
private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      ...省略部分代碼
      Annotation[] annotations = method.getAnnotations();
      try {
        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);
      }
    }

最終調(diào)用了ServiceMethod創(chuàng)建時傳進來的Retrofit對象的callAdapter(Type returnType, Annotation[] annotations)方法

在retrofit中方法如下:

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    ...省略部分代碼
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    ...省略部分代碼
  }

這里根據(jù)獲取到的type和annotations從工廠類中生成相應(yīng)的網(wǎng)絡(luò)請求適配器,沒有得到會拋出異常

    1. 生成數(shù)據(jù)轉(zhuǎn)換器 responseConverter = createResponseConverter();
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);
      }
    }

同樣,生成數(shù)據(jù)轉(zhuǎn)換器也調(diào)用了ServiceMethod創(chuàng)建時傳進來的Retrofit對象的方法,responseBodyConverter(Type type, Annotation[] annotations)

Retrofit中方法如下(和生成網(wǎng)絡(luò)請求適配器非常類似):

  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) {
    ...省略部分代碼
    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;
      }
    }
    ...省略部分代碼
  }

converterFactories.get(i)獲取到相應(yīng)的數(shù)據(jù)轉(zhuǎn)換器工廠,調(diào)用數(shù)據(jù)轉(zhuǎn)換器工廠中相應(yīng)的responseBodyConverter方法,比如常用的GsonConverterFactory

public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
  • 3 之后build中還對網(wǎng)絡(luò)請求接口中方法的注解和參數(shù)進行了解析,這部分都是在ServiceMethod類中的方法完成的,不再單獨介紹,上述build方法代碼中有簡單的注釋。

到這部分,Retrofit.create()方法中的三行核心代碼中的第一行,ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method),生成ServiceMethod的實現(xiàn)基本分析完畢。
那么接下來繼續(xù)看第二行OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args)

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;//上面講過的非常重要的一個對象
  private final @Nullable Object[] args;//參數(shù)
  private volatile boolean canceled;
  private @Nullable okhttp3.Call rawCall;//原生call,所有的操作最后實際上還是通過它來完成
  private @Nullable Throwable creationFailure; // Either a RuntimeException or IOException.
  private boolean executed;

   OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
  ...省略了部分代碼
}

OkHttpCall就是對OkHttp原生Call的封裝,包含了各種Call的方法,比如enqueue、execute、cancel、isCanceled,總之需要用到OkHttp的Call中方法的來這里就對了。

第二行代碼簡單分析之后,然后就是第三行代碼了:return serviceMethod.callAdapter.adapt(okHttpCall)
這里就是調(diào)用了adapt方法,比如加入使用了RxJava2CallAdapter,那callAdapter就對應(yīng)RxJava2CallAdapter,如下:

public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

(7)retrofit.create完成之后,具體去請求接口時:service.getCall(),因為service是一個接口,那接口去調(diào)用方法肯定是不行的,這里實際上是通過Retrofit中的create方法中動態(tài)代理進行了攔截,用InvocationHandler中的invoke方法進行實際操作,最后會返回一個OkHttpCall的適配器對象。

(8)Retrofit的同步和異步請求:

  • Retrofit同步請求流程:

ParameterHandler——>ServiceMethod——>Okhttp發(fā)送網(wǎng)絡(luò)請求——>數(shù)據(jù)轉(zhuǎn)換器converter

同步請求依然得依靠OkHttpCall中封裝的請求方法來執(zhí)行:

public Response<T> execute() throws IOException {
    okhttp3.Call call;
    ...省略部分代碼
      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }
    if (canceled) {//如果返回true,需要取消請求
      call.cancel();
    }
    return parseResponse(call.execute());
  }

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

上述代碼我們發(fā)現(xiàn)會有一個生成原生call的過程,可以看到先調(diào)用了ServiceMethod的toRequest生成一個request對象,然后去執(zhí)行request返回得到call,得到call的過程實際上是用OkHttp庫生成的。

ServiceMethod中的相關(guān)方法,根據(jù)傳入的各個請求參數(shù)對應(yīng)ParameterHandler進行解析:

Request toRequest(@Nullable Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    ...省略部分代碼
    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

在execute方法中,最終用了原生的call去執(zhí)行,執(zhí)行的結(jié)果又調(diào)用了parseResponse(okhttp3.Response rawResponse)方法來解析

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    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 {
      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;
    }
  }

可以看到獲取網(wǎng)絡(luò)請求的狀態(tài)碼等等,我們關(guān)注解析的核心過程serviceMethod.toResponse(catchingBody),又是調(diào)用了ServiceMethod中的方法

R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

這里使用了數(shù)據(jù)轉(zhuǎn)換器的convert方法,會使用我們的數(shù)據(jù)轉(zhuǎn)換器,比如GsonRequestBodyConverter

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
  private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
  private static final Charset UTF_8 = Charset.forName("UTF-8");

  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }
}
  • Retrofit異步請求:
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 {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

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

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

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

異步請求會將執(zhí)行結(jié)果交給一個回調(diào)執(zhí)行器去處理請求結(jié)果。其中一些關(guān)鍵性的代碼同步時已經(jīng)說過,不再說了。


【END】到這里,整個的網(wǎng)絡(luò)請求就完成了,相應(yīng)的源碼也就分析完成了,Retrofit使用了的設(shè)計模式有構(gòu)建者模式(Retrofit、ServiceMethod)、動態(tài)代理模式(實際調(diào)用請求方法時)、工廠模式(CallAdapter)、靜態(tài)工廠模式(Platform)、外觀模式/門面模式(Retrofit內(nèi)部封裝了很多子系統(tǒng)ServiceMethod、Factory等)、策略模式(CallAdapter是抽象層、具體的CallAdapter比如RxJava2CallAdapter)、適配器模式(CallAdapter)、觀察者模式(OkHttpCall和Callback)
外觀模式/門面模式說明:比如android studio點擊執(zhí)行按鈕去執(zhí)行程序,內(nèi)部實際上是執(zhí)行了很多復(fù)雜的子系統(tǒng)之間的操作,開發(fā)者只需要通過android studio提供的按鈕來操作就可以了,屏蔽了子系統(tǒng)之間的變化,高內(nèi)聚低耦合。
策略模式:比如要完成一項任務(wù),有很多方法,可以根據(jù)不同的情況使用不同的方法來完成。
工廠模式(強調(diào)生成不同的對象)和策略模式(adapt產(chǎn)生具體的實現(xiàn),強調(diào)的是不同對象的方法不同的實現(xiàn))
觀察者模式:一個被觀察者可以對應(yīng)多個觀察者,多個觀察者之間沒有相互聯(lián)系

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,762評論 2 372

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