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

一、概述

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其實就是下面這個:


小結:這一步就是得到CallAdapter,決定它的是interface的返回類型和注解

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

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


小結:這一步就是調用第一步中生成的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();
      }
    }
  }

斷點的值:



經過第三步的分析,我們要明白兩點:

  • 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的值變為:

5.3 小結

整個過程結束之后,ServiceMethod內的變量變為:

六、構造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();
  }

下面是斷點之后的值:


在構建完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方法的那個對象。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容