Retrofit 源碼簡介

我們先洗個請求的例子,如下

    private void retrofitTest() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://wwwcom/")
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();
        ApiService service = retrofit.create(ApiService.class);

        Call<String> call = service.getBlog("https://www.baidu.com", "abc");
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
           
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
            
            }
        });
    }


    interface ApiService {
        @GET
        Call<String> getBlog(
                @Url String url,
                @Query("type") int type
        );

        @FormUrlEncoded
        @POST()
        Call<String> getBlog1(
                @Url String url,
                @Field("type") String type,
                @Field("address") String address
        );

    }

例子是個get請求,ApiService 類中,使用了 @GET 註解,形參中使用了 @Url 和 @Query 註解,一旦使用 @Url,則以它對應的值爲準,Retrofit.Builder()  中通過 baseUrl() 設置的基準url就不使用了;如果我們使用post請求,用表格形式,接口中方法除了使用 @POST() 註解外,還要使用 @FormUrlEncoded 註解,對應的形參中要有 @Field 或 @FieldMap 其中之一,否則會報錯。


Retrofit 是載體,我們看看它的代碼,首先是個 Builder 模式,構造方法中有個參數

    public Builder() {
      this(Platform.get());
      converterFactories.add(new BuiltInConverters());
    }

看看 Platform.get() 對應的值

  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) {
    }
    ...
    return new Platform();
  }

我們是在 Android 設備上使用該網絡庫,此時對應的就是 new Android() 生成的對象,看看它是什麼 

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

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      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);
      }
    }
  }

它裏面有兩個方法,返回的對象分別是 MainThreadExecutor 和 ExecutorCallAdapterFactory。MainThreadExecutor 實現了 Executor 接口,方法中通過一個對應UI線程的Handler,把runnable 切換到主線程中。 retrofitTest() 中,如果在 Retrofit.Builder() 時,直接調用了 build() 方法

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

      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

第一步就拋異常,所以 baseUrl 必須設置,按照規範,以反斜線結尾;如果沒設置 callFactory,則在這裏new一個OkHttpClient對象,它是 Okhttp 中的類,我們如果要定製,就在外部創建好,然後通過 callFactory() 方法設置進來;callbackExecutor 也是同樣道理,默認使用就是 MainThreadExecutor 這個類;adapterFactories 是個空集合,這裏往裏面添加了一個對象,就是 ExecutorCallAdapterFactory,它的構造方法中接收了 MainThreadExecutor 這個類;

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

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

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

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


注意它內部 get() 方法返回的對象是 CallAdapter 類型,在這裏是 new 出的一個對象,它裏面又有兩個方法,其中創建 ExecutorCallbackCall 對象時把 callbackExecutor 和 call傳遞了進去。

converterFactories 集合在 Builder 的構造方法中傳遞了一個 BuiltInConverters 對象,它是 Converter.Factory 的子類,裏面有三個方法,根據名字可知,responseBodyConverter() 是把返回的 ResponseBody 對象轉換爲定義的對象 requestBodyConverter() 是把請求的對象轉換爲 RequestBody,stringConverter() 是把請求參數轉換爲 String 類型,以上三個方法不一定都會用到。我們也可以繼承 Converter.Factory ,根據自己的業務邏輯,來自定義自己的類。最後用這些參數創建一個 Retrofit 對象。


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, Object... args)
              throws Throwable {
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
}


這是個動態代理,動態代理的底層原理還是反射;這一步僅僅是通過傳入一個class文件,返回一個對應的對象,動態代理的 InvocationHandler 中的方法並沒有執行,service.getBlog("https://www.baidu.com", "abc") 執行這行代碼時,纔會觸發 InvocationHandler 中的 invoke(Object proxy, Method method, Object... args) 方法,此時 proxy 代表的是 retrofit 對象,method 代表的是對應方法 getBlog(),args這個可變參數對應的是 method 方法中的參數,在這裏對應的是 "https://www.baidu.com" 和 "abc" 這兩個參數。動態代理的常規用法是傳入一個代理對象,通過 Proxy 創建對象並返回,然後再外部調用方法,觸發invoke() 方法中通過拿到的參數進行反射來觸發要調用的方法。 Retrofit 中的這個動態代理沒按照常規的邏輯執行,來看看它都做了什麼,先看 loadServiceMethod(method) 方法


  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }


這個裏面是個Map緩存,如果有,則複用;如果沒有,則創建,這裏又引申出一個比較重要的類 ServiceMethod,它也是採用了 Builder 模式,看看其方法

    public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

上一篇文章中講過方法中 Method 中這幾個方法的作用,這裏不再重複,看看 build() 方法

  public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      ...
      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);
  }

此方法省略了一些校驗的代碼,有興趣的可以看一下源碼,這裏講一下大框架流程。createCallAdapter() 方法中獲取的是其實就是上面的 ExecutorCallAdapterFactory 中創建的對象

  private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      Annotation[] annotations = method.getAnnotations();
      try {
        return 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);
      }
  }

Retrofit:

  public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
  public CallAdapter<?> nextCallAdapter(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;
      }
    }
    ...
    throw new IllegalArgumentException(builder.toString());
  }

returnType 是方法返回值的類型,adapterFactories 就是Retrofit中創建時添加對象的集合,此時遍歷集合,通過 get() 方法來判斷是否是需要的 CallAdapter,ExecutorCallAdapterFactory 中的 get() 方法返回的對象是 new 出來的 CallAdapter 對象,不爲空,所以就是它了。

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:

  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(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) {
        return (Converter<ResponseBody, T>) converter;
      }
    }
    ...
    throw new IllegalArgumentException(builder.toString());
  }

這個與上面的原理類似,由於該集合中有 BuiltInConverters 和 ScalarsConverterFactory 兩個對象,一個是系統自帶的,一個是我們方法中設置進去的,這時候會遍歷,根據 responseBodyConverter() 返回值來確定使用哪個,BuiltInConverters 中的 Type 類型只支持兩種,即 ResponseBody 和 Void,而我們這個接口中使用的返回值類型是 String,所以這個裏面沒有合適的,繼續看 ScalarsConverterFactory,它裏面支持 String 類型,返回的是 ScalarRequestBodyConverter 對象。

final class ScalarRequestBodyConverter<T> implements Converter<T, RequestBody> {
  static final ScalarRequestBodyConverter<Object> INSTANCE = new ScalarRequestBodyConverter<>();
  private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain; charset=UTF-8");

  private ScalarRequestBodyConverter() {
  }

  @Override public RequestBody convert(T value) throws IOException {
    return RequestBody.create(MEDIA_TYPE, String.valueOf(value));
  }
}

接着是遍歷 methodAnnotations 這個方法上的註解數組,我們例子中只有一個 @GET 註解,看看 parseMethodAnnotation() 方法

  private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        ...
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
  }

  private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

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

這個方法就是確認請求頭中請求格式,並做一些屬性賦值,做邏輯判斷。繼續往下看,parameterAnnotationsArray 對應的形參中的註解,ParameterHandler 是個接口,這裏是爲了適配各種類型,注意 parseParameter() 方法

  private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations) {
      ParameterHandler<?> result = null;
      for (Annotation annotation : annotations) {
        ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);
        if (annotationAction == null) {
          continue;
        }
        if (result != null) {
          throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
        }
        result = annotationAction;
      }
      if (result == null) {
        throw parameterError(p, "No Retrofit annotation found.");
      }
      return result;
  }


這段代碼的意思是,Call<String> getBlog(@Url String url,@Query("type") int type) 這個方法中,以它爲例子,parameterAnnotationsArray 數組長度爲2,第一個數組中對應的是 @Url String url 這個形參中的 @Url 註解,此時,p爲0,parameterType 爲String,annotations 數組中只有一個對象,指的是@Url,再通過 parseParameterAnnotation() 方法來生成
ParameterHandler 對象

  private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
      if (annotation instanceof Url) {
        ...
        gotUrl = true;
        if (type == HttpUrl.class || type == String.class || type == URI.class
            || (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
          return new ParameterHandler.RelativeUrl();
        } else {
          throw parameterError(p,
              "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
        }

      } else if (annotation instanceof Query) {
        Query query = (Query) annotation;
        String name = query.value();
        boolean encoded = query.encoded();

        Class<?> rawParameterType = Utils.getRawType(type);
        gotQuery = true;
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
          ...
        } else {
          Converter<?, String> converter = retrofit.stringConverter(type, annotations);
          return new ParameterHandler.Query<>(name, converter, encoded);
        }
      } else if (annotation instanceof Field) {
        if (!isFormEncoded) {
          throw parameterError(p, "@Field parameters can only be used with form encoding.");
        }
        Field field = (Field) annotation;
        String name = field.value();
        boolean encoded = field.encoded();
        gotField = true;

        Class<?> rawParameterType = Utils.getRawType(type);
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
          ...
        } else {
          Converter<?, String> converter = retrofit.stringConverter(type, annotations);
          return new ParameterHandler.Field<>(name, converter, encoded);
        }
      }
      ...
      return null; // Not a Retrofit annotation.
  }

這是簡化後的代碼,以 @GET、@Query、@Field 爲例,方法形參 type 代表的是參數類型,annotations 是註解數組,只有一個對象,annotation 就是我們具體的註解,即 GET、Query、Field 等等,我們先看 Url,一堆校驗後走到了 if 判斷,此時我們參數是String類型,所以retrun的對象是 RelativeUrl,它是 ParameterHandler 的子類;Query 中,根據註解獲取對應的值,query.value() 對應的就是type字符串,query.encoded() 默認是false,調用 retrofit.stringConverter(type, annotations) 獲取對象,此時會重新遍歷 converterFactories 集合,通過調用 stringConverter() 方法獲取對應的值,這一次 BuiltInConverters 對象符合條件,返回的是 StringConverter 

  static final class StringConverter implements Converter<String, String> {
    static final StringConverter INSTANCE = new StringConverter();

    @Override public String convert(String value) throws IOException {
      return value;
    }
  }


獲取 Converter 後,創建 ParameterHandler.Query 對象;Field 註解中,會先校驗 isFormEncoded 屬性,這也是爲什麼必須使用 @FormUrlEncoded 註解的原因,最後返回 ParameterHandler.Field 對象,與 Query 類似。parameterHandlers 數組填充完畢後,會再校驗一些屬性,這個也可以稱之爲註解的組合使用規則。然後就是通過builder方法創建 ServiceMethod 對象了,把 Builder 中獲取的值,盡數傳遞給 ServiceMethod。

loadServiceMethod(Method method) 方法分析到此結束,繼續看動態代理的內容,創建 OkHttpCall 對象,把 serviceMethod 和參數 args 通過構造方法傳遞進去,然後調用 ServiceMethod 中的 callAdapter 屬性對象的 adapt() 方法,此時 callAdapter 對應的就是 createCallAdapter() 方法生成的 ExecutorCallAdapterFactory 類中的 get() 方法中 return 的 CallAdapter 對象;serviceMethod.callAdapter.adapt(okHttpCall)  對應的就是 CallAdapter 對象中的 adapt()  方法,它 return 的值是 ExecutorCallbackCall, Call<String> call =  service.getBlog( "https://www.baidu.com" ,  "abc" ) 中 call 實際上就是 ExecutorCallbackCall 類型。

然後就是 call.enqueue(new Callback<String>() {...}); 方法了,既然知道此時 call 是 ExecutorCallbackCall 類型,那麼看看 ExecutorCallbackCall 的源碼

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

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

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

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

明顯的,這是個裝飾模式,ExecutorCallbackCall 在創建時,傳遞了兩個參數給構造方法,new ExecutorCallbackCall<>(callbackExecutor, call) 這兩個參數類型分別對應 MainThreadExecutor 和 OkHttpCall 對象類型,所以 ExecutorCallbackCall 中的成員變量 callbackExecutor 是 MainThreadExecutor,是用 Handler 來切換線程的,delegate 是 OkHttpCall 類型,是來構建請求頭和請求體的,注意 enqueue() 方法,先對 callback 進行非空判斷,然後執行代理 delegate 的 enqueue() 方法,

OkHttpCall:

  @Override
  public void enqueue(final Callback<T> callback) {

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

首先是調用 createRawCall() 生成一個 call 對象,如果生成的過程中拋出了異常,則創建 failure 對象,接下來先校驗 failure 對象不爲空,則直接執行失敗方法的回調;如果接口被取消了,則裏也是取消;然後是 call 執行它對應的 enqueue() 方法,注意,這時候它和回調都是 Okhttp 中的類了,這一步已經把網絡請求交割給 Okhttp 了,然後就是它裏面的成功和失敗的回調了,成功的話會有個 parseResponse() 方法來封裝得到的結果,轉換類型。回調執行後,就回到了 ExecutorCallbackCall 中的 delegate 設置的回調中,在它的回調中,用 callbackExecutor 切換到UI線程,然後就回調到了 retrofitTest() 例子中對 call 設置的回到了,這裏我們可以做自己的業務邏輯,再說一遍,此時就是UI線程了。大體流程清楚了,再來看看請求的細節,先看 createRawCall() 方法

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

ServiceMethod:

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

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

RequestBuilder 是一個轉換封裝請求頭、請求體的類,感興趣的可以看看,助理主要是 ParameterHandler 數組,通過for循環,執行對象中 apply() 方法,前面講到了 @Url 和 @Field
註解對應的類型是 ParameterHandler 中內部類 RelativeUrl 和 Query

  static final class RelativeUrl extends ParameterHandler<Object> {
    @Override void apply(RequestBuilder builder, Object value) {
      builder.setRelativeUrl(value);
    }
  }
  
  static final class Query<T> extends ParameterHandler<T> {
    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addQueryParam(name, valueConverter.convert(value), encoded);
    }
  }

通過這可以知道,通過 for 循環,把參數添加到了 requestBuilder 對象中,注意 Query 中的參數,name 是 getBlog(@Url String url,@Query("type") int type) 中 @Query("type")括號中的 "type",value 是 retrofitTest() 中傳遞的參數 "abc",valueConverter 指的是前面 parseParameterAnnotation()方法中獲取的StringConverter 對象,此時它方法中返回的值是本身

 static final class StringConverter implements Converter<String, String> {
    static final StringConverter INSTANCE = new StringConverter();

    @Override public String convert(String value) throws IOException {
      return value;
    }
  }

RequestBuilder 添加參數最終還是通過 HttpUrl 、 FormBody 等,這個和 Okhttp 裏面的 Request 裏面的原理是相同的,最終通過 build() 方法來創建 Request 對象,serviceMethod.callFactory.newCall(request) 中 serviceMethod.callFactory 對應的是 Retrofit 中的 callFactory 屬性,也就是 OkHttpClient,它的 newCall() 方法返回的 Call 是 RealCall 類型的對象,所以 call執行enqueue()方法也就對應 RealCall 的 enqueue() 方法,在 Okhttp 中,用線程池開啓線程請求網絡接口;看看回調成功的邏輯,是如何轉換返回的報文類型,關鍵是 parseResponse() 方法

  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 {
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

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

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      catchingBody.throwIfCaught();
      throw e;
    }
  }

前面三四行代碼是給 rawResponse 中的body對象再包裝一層 NoContentResponseBody,然後重新設置進去;獲取code碼,如果不在200和300之間,則創建一個ResponseBody對象,然後設置到 Response 的靜態方法中,生成 Response 對象;如果是 204 或 205,也是靜態方法返回 Response 對象,不過此時設置的報文爲null; ExceptionCatchingRequestBody 裝飾模式
,在它的 source() 方法中,當解讀數據時,添加了 ForwardingSource 中間代理層,它的 read() 方法中加了try.catch 異常機制處理,當執行 serviceMethod.toResponse(catchingBody) 方法時會起到作用,serviceMethod 對應StringResponseBodyConverter ,它僅僅是獲取 ResponseBody 中的 string(),然後轉換爲字符串返回,它會觸發 bytes() 方法,這個方法觸發了 ExceptionCatchingRequestBody 中的 source() 方法及 ForwardingSource 中的 read() 方法。

到此,例子中的講解就此結束了,各位可以按照這個邏輯,自行閱讀以下 pot 請求和同步線程請求。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章