Retrofit 知識梳理(1) 流程分析

澤毛發表於2017-12-21

一、概述

Retrofit之所以能做到如此簡潔,最重要的一個原因就是它把網路請求當中複雜的引數設定都封裝了起來,對於使用者而言,只需要定義一個interface,並在interface當中定義好請求的引數,Retrofit在構建請求的時候就會幫我們自動配置。 除此之外,它還提供了Converter/CallAdapter讓使用者進行充分的定製,要理解整個Retrofit的架構,還是應當從一個簡單的流程開始,一步步地Debug,這篇文章,我們就以一個最簡單的例子,從建立到返回的流程,來看一下整個Retrofit的框架。

二、整體流程

下面是一個使用Retrofit的最簡單的例子,我們將通過這個例子,一步步地Debug,看一下整個的過程:

    public void simpleExample(View view) {
        Retrofit retrofit = new Retrofit
                .Builder()
                .baseUrl("https://api.github.com/")
                .build();
        GitHubService service = retrofit.create(GitHubService.class);
        Call<ResponseBody> call = service.listRepos("octocat");
        try {
            call.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {}
                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {}
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
複製程式碼

三、構建Retrofit物件

3.1 Retrofit.Builder建構函式

Retrofit的構建,採用了建造者模式,在第2步中,我們傳入了一個url,我們看一下Retrofit.Builder做了什麼,這裡,我們只擷取例子中呼叫了的部分:

 public static final class Builder {

    Builder(Platform platform) {
      this.platform = platform;
      converterFactories.add(new BuiltInConverters());
    }

    public Builder() {
      this(Platform.get());
    }
    //....
  }
複製程式碼

首先,當我們呼叫無參的建構函式之後,在它的內部會呼叫Builder(Platform platform),這裡面會確定當前的平臺,接著給它的converterFactories列表當中新增一個預設的BuiltInConverters,下面我們看一下這個類的定義。

3.2 Converter / Converter.Factory / BuiltInConverters

BuiltInConverters繼承了Converter.Factory這個抽象類:

final class BuiltInConverters extends Converter.Factory { }
複製程式碼

Converter是一個帶有convert的介面,它就是把一個型別轉換成另一個型別,但是由於使用階段的不同,所以它有三個工廠方法。 至於為什麼要定義這個,這裡先說結論:

  • 因為Retrofit在處理返回的請求時,預設是把Response轉換為ResponseBody,如果使用者希望得到別的型別,那麼就需要定義自己的Converter.Factory,並將它設定給Retrofit。在網上很多例子中使用的GsonConverterFactory就是用來做這個事的,它可以把標準的Call<ResponseBody>轉換成Call<任意型別>,而從ResponseBody任意型別JSON解析也是由它完成的。
  • 而後兩個方法,則是用來初始化ServiceMethod中的變數,這些變數又會決定發起請求的Request的引數,Retrofit抽象出了其中可定製的部分來給使用者。
public interface Converter<F, T> {
  //和它的類名類似,只有一個介面,就是進行一個型別的轉換。
  T convert(F value) throws IOException;

  //內部工廠類,呼叫不同的工廠方法來生成Converter
  abstract class Factory {

    //(1)將返回的ResponseBody轉換成interface中Call<T>所指定的T.
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return null;
    }

    //(2)利用引數構建Request,它依賴於@Body/@Part/@PartMap.
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        return null;
    }

    //(3)利用引數構建String,它依賴於@Field/@FieldMap/@Header/@HeaderMap/@Path/@Query/@QueryMap.
    public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return null;
    }
  }
}
複製程式碼

在上面的例子中,我們最終是會得到一個BuiltInConverters例項,它繼承了Convert.Factory,並重寫了response/request這兩個方法,它會根據傳入的Type來判斷生成哪個Convert例項,因為我們現在不知道這兩個方法是什麼時候呼叫的,所以我們先大概瞭解一下它的邏輯,之後再來解釋。

final class BuiltInConverters extends Converter.Factory {
  
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    //如果Type是ResponseBody,那麼當註解中包含了Streaming.class時,返回StreamingXXX,否則返回BufferingXXX
    //這兩個其實都是Converter<ResponseBody, ResponseBody>
    if (type == ResponseBody.class) {
      return Utils.isAnnotationPresent(annotations, Streaming.class)
          ? StreamingResponseBodyConverter.INSTANCE
          : BufferingResponseBodyConverter.INSTANCE;
    }
    //如果Type為空,那麼返回null。
    if (type == Void.class) {
      return VoidResponseBodyConverter.INSTANCE;
    }
    return null;
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    //如果是RequestBody,或者是它的父類或者介面,那麼返回Convert<RequestBody, RequestBody>,否則返回null。
    if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
      return RequestBodyConverter.INSTANCE;
    }
    return null;
  }
}
複製程式碼

3.3 baseUrl(String url)方法

現在Builder的建構函式已經解釋完了,那麼我們再來看一下baseUrl方法,這個沒什麼好說的,就是把String轉換成為HttpUrl

    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;
    }
複製程式碼

3.4 呼叫build方法,構建Retrofit物件

    public Retrofit build() {
      //1.這個就是傳入的“https://api.github.com/”
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

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

      //3.根據平臺選擇相應的執行者。
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //4.新增預設的CallAdapter.Factory,預設的Factory放在最後一個
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      //5.新增Converter.Factory,預設BuiltInConverters放在第一個.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      //6.返回,內部其實就是給各個變數賦值,並把45生成的列表定義為不可更改的。
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
複製程式碼

為了之後分析方便,我們看一下上面沒有接觸過的兩個類:ExecutorCallAdapter.Factory,因為我們是Android平臺,因此我們直接看這兩個平臺中返回的例項:

static class Android extends Platform {
     //返回MainThreadExecutor
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    //返回ExecutorCallAdapterFactory
    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
  }
複製程式碼

下面,我們通過3.43.5來看一下這兩個例項的內部實現。

3.5 Executor / MainThreadExecutor

對於Android平臺,返回的是MainThreadExecutor,它其實就是把Runnable中的任務放到主執行緒中去執行,後面我們可以知道,它的作用就是把非同步執行的結果返回給主執行緒

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
複製程式碼

3.6 CallAdapter / CallAdapter.Factory / ExecutorCallAdapterFactory

CallAdapter的定義和我們上面看到的Converter很類似,都是定義了介面,然後內部有一個抽象工廠類:

public interface CallAdapter<R, T> {
  
  //(1)返回型別.
  Type responseType();

  //(2)將Call<R>轉換為T.
  T adapt(Call<R> call);

  //內部抽象工廠.
  abstract class Factory {

    //(1)工廠方法,工廠類需要實現該方法來返回對應的CallAdapter.
    public abstract 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);
    }
  }
}
複製程式碼

看上面的描述不是很清楚,我們看一下ExecutorCallAdapterFactory是怎麼實現它的:

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

  //這裡傳入的Executor,就是前面我們構造的MainThreadExecutor,即把任務放到主執行緒中執行.
  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }
   
   //只重寫了get方法,沒有重寫另外兩個方法.
  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //....
    //獲得Call<?>中型別,對於例子來說,就是ResponseBody.
    final Type responseType = Utils.getCallResponseType(returnType);
    
    //get方法返回的是CallAdapter物件
    return new CallAdapter<Object, Call<?>>() {

       //(1)對於第一個介面而言,就是Call<T>中T的型別.
      @Override public Type responseType() {
        return responseType;
      }

      //(2)對於第二個介面,就是把傳入的Call<Object>進行了包裝,並沒有改變它的型別.
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
  //..定義了ExecutorCallbackCall.
}
複製程式碼

3.7 Call / Callback / ExecutorCallbackCall

ExecutorCallbackCall實現了Call介面,我們先看一下Call介面的定義:

//T表示的是返回的型別,也就是前面的List<Repo>.
public interface Call<T> extends Cloneable {
  //同步執行
  Response<T> execute() throws IOException;
  //非同步執行
  void enqueue(Callback<T> callback);
  //正在執行.
  boolean isExecuted();
  //取消.
  void cancel();
  //已經取消.
  boolean isCanceled();
  //引數並且目標伺服器相同的請求,那麼呼叫clone方法.
  Call<T> clone();
  //最初始的請求.
  Request request();
}
複製程式碼

接下來,看一下Callback的定義:

//T表示的是最終返回結果的型別,也就是List<Repo>
public interface Callback<T> {
  //返回成功.
  void onResponse(Call<T> call, Response<T> response);
  //返回失敗.
  void onFailure(Call<T> call, Throwable t);
}
複製程式碼

ExecutorCallbackCall的建構函式中傳入了一個Executor和一個Call作為delegate,其實它對於Call介面的實現,都是呼叫了delegate的對應實現,唯一不同是對於enqueue方法,它會把callback的回撥放在Executorrun()方法中執行

    delegate.enqueue(new Callback<T>() {
        //在實際執行任務的Call完成之後,呼叫MainThreadExecutor,使得使用者收到的回撥是執行在主執行緒當中的.
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          //通過executor執行.
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              //如果取消了,那麼仍然算作失敗.
              if (delegate.isCanceled()) {
                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);
            }
          });
        }
      });
    }
複製程式碼

3.8 構造Retrofit小結

從上面的分析來看,這個Retrofit最終它內部的成員變數包括:

  final okhttp3.Call.Factory callFactory; //OkHttpClient.
  final HttpUrl baseUrl; //baseUrl傳入的值.
  final List<Converter.Factory> converterFactories; //列表中包括一個BuildInConverts.
  final List<CallAdapter.Factory> adapterFactories; //列表中包括一個ExecutorCallAdapterFactory.
  final Executor callbackExecutor; //MainThreadExecutor.
  final boolean validateEagerly; //沒有傳入,預設為false.
複製程式碼

我們在AS當中斷點,可以看到此時Retrofit內部的成員變數,和我們上面通過原始碼的分析的結果是相同的。

`Retrofit`的成員變數值

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

這一步其實就是構建一個動態代理,真正執行的是要等到下面這句:

Call<ResponseBody> call = service.listRepos("octocat");
複製程式碼

我們直接來看執行的部分,它可以分為三個步驟,對於這三個步驟,我們分為五、六、七這三個章節說明。

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> 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 {
            //...

            //1.得到ServiceMethod物件.
            ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);

            //2.通過serviceMethod和args來構建OkHttpCall物件,args就是“octocat”.
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

            //3.其實就是呼叫ExecutorCallbackCall.adapt方法.
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
複製程式碼

#五、例項化ServiceMethod<Object, Obejct>物件。

5.1 loadServiceMethod


  ServiceMethod<?, ?> loadServiceMethod(Method method) {
      //如果之前載入過,那麼直接返回,
      if (result == null) {
        //建立新的.
        result = new ServiceMethod.Builder<>(this, method).build();
        //加入快取.
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
複製程式碼

ServiceMethod.Builder當中,通過method首先初始化了下面這幾個變數,可以看到它持有了retrofit例項以及我們定義的GitHubService這個介面內的方法,也就是說,它知道了所有和請求相關的資訊:

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit; //就是前面構建的retrofit例項.
      this.method = method; //方法,對應於listRepo
      this.methodAnnotations = method.getAnnotations(); //方法的註解,對應於@GET("users/{user}/repos")
      this.parameterTypes = method.getGenericParameterTypes(); //方法的形參的型別,對應於String
      this.parameterAnnotationsArray = method.getParameterAnnotations(); //方法的形參前的註解,對應於@Path("user")
    }
複製程式碼

我們通過斷點看一下目前ServiceMethod中這幾個成員變數的值:

`ServiceMethod.Builder`初始化的值

5.2 ServiceMethod.Builderbuild()過程

上面只是進行簡單的初始化,而真正構建的過程會依賴這幾個引數來初始化ServiceMethod中的其它成員變數,這個方法比較長,也是**Retrofit的核心部分**,我們去掉一些引數檢查的程式碼,直接來看關鍵的五個步驟:

    public ServiceMethod build() {
      //1.初始化CallAdapter<T, R>,呼叫了retrofit.callAdapter.
      callAdapter = createCallAdapter();

      //2.得到callAdapter的返回型別.
      responseType = callAdapter.responseType();
    
      //3.初始化Converter<ResponseBody, T>,呼叫了retrofit.responseBodyConverter
      responseConverter = createResponseConverter();

      //4.處理方法的註解,
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      //5.處理形參的註解.
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        //首先得到形參的型別.
        Type parameterType = parameterTypes[p];
        //再得到形參的註解.
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        //(1)根據這兩個值來初始化和該形參關聯的ParameterHandler.
        //(2)其內部會呼叫parseParameterAnnotation
        //(3)而該方法最終會呼叫Retrofit.requestBodyConverter/stringConverter
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      return new ServiceMethod<>(this);
    }
複製程式碼

下面我們一步步來分析這些關鍵語句的作用:

5.2.1 第一步:構建CallAdapter

關鍵語句:callAdapter = createCallAdapter();
複製程式碼

看一下createCallAdapter

    private CallAdapter<T, R> createCallAdapter() {

      //方法的返回值,也就是Call<ResponseBody>
      Type returnType = method.getGenericReturnType();

      //方法的註解,就是@GET(xxxx)
      Annotation[] annotations = method.getAnnotations();

      //把返回型別和註解傳給Retrofit.
      return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);  
    }
複製程式碼

這個方法執行時,returnTypeannotation的值為:

`createCallAdapter`的`returnType/annotations`的值
下面,我們看一下Retrofit中的對應方法:

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

  public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {

    //遍歷之前初始化時的adapterFactories.
    int start = adapterFactories.indexOf(skipPast) + 1;

    //1.此時為null,所以start從0開始遍歷所有配置的CallAdapterFactory
    //2.然後呼叫它們的工廠方法,找到第一個滿足returnType和annotation的CallAdapter返回.
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
  }
複製程式碼

上面這步返回的CallAdapter其實就是我們之前分析過的,通過ExecutorCallAdapterFactoryget方法所返回的CallAdaper,它的responseType()得到就是Call<ResponseBody>中的ResponseBody

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

    //1.先判斷返回值是不是Call<T>
    if (getRawType(returnType) != Call.class) {
      return null;
    }

    //2.得到T的型別.
    final Type responseType = Utils.getCallResponseType(returnType);

    //3.利用T來決定CallAdapter的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其實就是下面這個:

Retrofit 知識梳理(1)   流程分析
小結:這一步就是得到CallAdapter,決定它的是interface的返回型別和註解

5.2.2 第二步:responseType = callAdapter.responseType()

這一步很好理解,就是呼叫第一步中生成的callAdapter的方法,對於示例來說就是ResponseBody

Retrofit 知識梳理(1)   流程分析
小結:這一步就是呼叫第一步中生成的CallAdapter#responseType來賦值給responseType

5.2.3 第三步:responseConverter = createResponseConverter()

    private Converter<ResponseBody, T> createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      //這裡和第一步不同,不是傳入介面方法的返回型別,而是傳入第二步中通過CallAdapter#responseType返回的型別,對於例子來說,就是ResponseBody.
      return retrofit.responseBodyConverter(responseType, annotations);
    }
複製程式碼

下面的程式碼和獲得CallAdapter的程式碼很類似,都是遍歷工廠,來找到可以生成符合需求的產品.

  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);
      return (Converter<ResponseBody, T>) converter;
    }

  }
複製程式碼

根據我們之前的分析,它就是呼叫了BuiltInConverters這個工廠類,最終生產出下面的這個Converter

  static final class BufferingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();

    @Override public ResponseBody convert(ResponseBody value) throws IOException {
      try {
        // Buffer the entire body to avoid future I/O.
        return Utils.buffer(value);
      } finally {
        value.close();
      }
    }
  }
複製程式碼

斷點的值:

Retrofit 知識梳理(1)   流程分析
經過第三步的分析,我們要明白兩點:

  • responseBodyConverter這個Converter的作用就很清楚了,就是如果我們要把Call<ResponseBody>中的ResponseBody轉換為其它的型別,那麼就需要通過這個Converter類實現
  • responseBodyConverter方法所傳入的type,其實是CallAdapter#responseType的型別,這也是它們相關聯的地方

小結:這一步就是得到Converter,它是由CallAdapter#responseTypeinterface的註解來決定的

5.2.4 第四步:處理方法的註解

for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
}
複製程式碼
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 {
            //....
      }
}
複製程式碼

這個步驟完畢之後,之後再呼叫parseHttpMethodAndPath()方法,來給下面幾個變數賦值:

String httpMethod; //"GET"
boolean hasBody; //false
String relativeUrl; // users/{user}/repos
Set<String> relativeUrlParamNamesl; // 大小為1,內容為user.
複製程式碼

5.2.5 第五步:處理形參的註解

處理形參,依賴於該形參上的註解和形參的型別

      //只處理有註解的形參.
      int parameterCount = parameterAnnotationsArray.length;
      //每個有註解的形參對應一個ParameterHandler.
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        //1.獲得形參的型別.
        Type parameterType = parameterTypes[p];
        //2.獲得該形參對應的註解.
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        //3.傳入這兩個變數,來構建ParameterHandler.
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
複製程式碼

我們再來看一下parseParameter這個函式:

    private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations) {
      ParameterHandler<?> result = null;
      //遍歷該形參上的所有註解.
      for (Annotation annotation : annotations) {
        //這裡處理,所以應該是每個有註解的形參上的每個註解都會對應一個ParameterHandler.
        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;
   }
複製程式碼

這個過程之後,ParameterHandler的值變為:

Retrofit 知識梳理(1)   流程分析

5.3 小結

整個過程結束之後,ServiceMethod內的變數變為:

Retrofit 知識梳理(1)   流程分析

六、構造OkHttpCall

這一步只是簡單的把這兩個變數傳入,並返回OkHttpCallOkHttpCall是實現了Call介面的,關於它的具體實現,我們在後面發起請求的部分再討論。

    OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
    }
複製程式碼

七、將OkHttpCall<Object>轉換為interface宣告的型別

return serviceMethod.callAdapter.adapt(okHttpCall);
複製程式碼

這裡面呼叫的就是ServiceMethod中的callAdapter,經過我們前面的分析,這個CallAdapter就是ExecutorCallAdapterFactory,它的adapt方法,其實就是把OkHttpCall<Object>MainExecutor包裝在一起,然後返回那個對它的包裝類。 CallAdapter一共有兩個介面,前面我們已經看到CallAdapter#responseType是用來輔助responseConvert的生成,那是它的第一個作用;現在我們可以知道,它的第二個介面adapt的作用就是把OkHttpCall<Object>轉換成為自己希望的型別

八、發起請求

經過上面幾章的分析,我們的準備工作已經做好了,現在我們呼叫下面的enqueue方法發起請求:

call.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {}
                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {}
});
複製程式碼

經過前面的分析,我們知道這個call其實就是ExecutorCallbackCall型別的,它的enqueue方法,其實是呼叫了構建它時所傳入的Call<T> delegate的方法,而此時delegate就是OkHttpCall<ResponseBody>,我們取看一下它的enqueue方法。

@Override 
 public void enqueue(final Callback<T> callback) {
    //1.構建請求
    call = rawCall = createRawCall();
    //2.發起請求.
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          //3.解析請求
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        //4.返回請求.
        callSuccess(response);
      }

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

8.1 構建請求

  private okhttp3.Call createRawCall() throws IOException {
    //通過ServiceMethod來構造OkHttpClient的Request例項,並傳入方法的實參.
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
複製程式碼

這裡會根據前面loadServiceMethod過程當中所生成的引數,來最終初始化一個Request.

  /** Builds an HTTP request from method arguments. */
  Request toRequest(Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart);
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    
    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }
複製程式碼

下面是斷點之後的值:

Retrofit 知識梳理(1)   流程分析
在構建完Request之後,再呼叫serviceMethod.callFactory來生成okHttp3.Call,這裡的callFactory就是Retrofit中的callFactory,也就是OkHttpClient

8.2 解析請求

從上面的一節可以看到,最終發起請求的使用呼叫OkHttp標準的流程,那麼返回的時候也是用的標準的OkHttpResponse,接下來,就會呼叫下面的方法來把它轉換成Response<T>

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    //1.獲得Body
    ResponseBody rawBody = rawResponse.body();
    //2.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      //構建Body.
      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;
    }
  }
複製程式碼

這裡面比較關鍵的是呼叫serviceMethodtoResponse方法,它會將對於Retrofit標準的ResponseBody轉換為T

  /** Builds a method return value from an HTTP response body. */
  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }
複製程式碼

這裡的responseConverter就是我們之前通過BuildInConvert生成的Converter,回想一下,它什麼也沒有做,只是把ResponseBody原封不動地返回:

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

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

    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();

    @Override public ResponseBody convert(ResponseBody value) throws IOException {
      try {
        // Buffer the entire body to avoid future I/O.
        return Utils.buffer(value);
      } finally {
        value.close();
      }
    }
  }
複製程式碼

因此這一步最終會返回一個Response<T>物件,對於例子來說,這個T就是ResponseBody

8.3 返回請求

加入請求成功,那麼會用回撥來通知使用者。

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

因此,最終使用者通過該回撥,會收到一個Reponse<T>的響應,以及對於該請求的包裝類Call<T>,也就是呼叫了.enqueue方法的那個物件。

相關文章