Retrofit2 源碼及流程分析

本篇提綱.png

一.Retrofit中Builder模式完成初始化工作

Retrofit現在已經是各種網絡請求類APP的標配了,我們今天主要看下他的內部是如何解耦實現的
首先展示一下基本用,也就是我們源碼分析的入口代碼:

    Retrofit retrofit = new Retrofit.Builder().
            baseUrl(BASE_URL).
            //addCallAdapterFactory(RxJavaCallAdapterFactory.create()). 如果有這句的話就沒有下面的call.enqueue(new Call<List<Bean>>()那段了,直接就用了RxJava那一套了
            addConverterFactory(GsonConverterFactory.create()).
            build();
    Service service = retrofit.create(Service.class);

    Call<List<Bean>> call = service.getBeanLists(“username”);
    call.enqueue(new Call<List<Bean>>(){
        @Override
        public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
            beanList = response.body();
            ...     //doSomething();
        }

        @Override
        public void onFailure(Call<List<hot>> call, Throwable t) {
            Toast.makeText(getContext(), "讀取失敗,請檢查網絡設置", Toast.LENGTH_SHORT).show();
        }
    });
public interface Service {
    @GET("{username}")
    Call<List<Bean>> getBeanLists(@Path("username") String username);
}

上述我們就創建了一個異步請求的Retrofit類,我們先從.Build();開始看起:

public static final class Builder {
    private final Platform platform;    //選擇平臺:Android,java等
    private okhttp3.Call.Factory callFactory;   //okhttp的Call工廠類,自定義newCall將Request轉為Call
    private HttpUrl baseUrl;            //okhttp中的類,保存解析過的url。baseUrl就是上面BASE_URL
    private final List<Converter.Factory> converterFactories = new ArrayList<>();//類型轉換工廠列表
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//CallAdapter工廠列表
    private Executor callbackExecutor;  //回調線程池
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      converterFactories.add(new BuiltInConverters());  //添加默認的轉換器(如果上面addConverterFactory中不添加的話)
    }

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

當程序執行完Retrofit retrofit = new Retrofit.Builder()這一句的時候,也就是執行了上述代碼中的

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

這個方法,其中Platform.get()這個方法,實際上就是獲取當前執行的平臺,在Retrofit 2.0版本中,他支持Android,iOS,Java8三個平臺。但是在2.2版本的源碼中,刪去了iOS平臺選擇的那部分源碼,不知道是否還兼容iOS平臺,這個不在本文討論范圍內,有興趣的同學可以自行考證。判斷完平臺之后,賦值給Platform實例變量,我們都是Android平臺。
??上面我們看了.Builder()方法,這個方法中實際上就行選擇了一下平臺。這個方法執行完之后,開始進行addCallAdapterFactory()addConverterFactory()等Build模式中的方法:

    /** Add converter factory for serialization and deserialization of objects. */
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
    /**
     * Add a call adapter factory for supporting service method return types other than {@link Call}.
     */
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

可以看到,這里我們添加的RxJavaCallAdapterFactory.create()GsonConverterFactory.create()都加到了上面我們提到過的Builder類中的實例變量List<Converter.Factory> converterFactoriesList<CallAdapter.Factory> adapterFactories這兩個List中,一遍后面解析使用。
??Build模式的最后一步.build()方法:

    public Retrofit build() {
      if (baseUrl == null) {    //baseUrl肯定是要設置的,不設置的話會拋出異常
        throw new IllegalStateException("Base URL required.");
      }

      //如果我們需要對OkHttp做出一些改進,比如添加鏈接超時什么得,就需要重新構建OkHttpClient并傳入這里
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {    //如果沒有設置callFactory,則默認用OkHttpClient()
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //讀取設置的adapterFactories,也就是addCallAdapterFactory(RxJavaCallAdapterFactory.create())
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // 讀取converterFactories,也就是addConverterFactory(GsonConverterFactory.create())
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);   //最后一步,調用Retrofit構造函數,創建一個實例
    }

上面的.build()中方法中,主要做了這么幾件事情:
① 首先指定baseUrl,這個是必須指定的,否則會拋出異常
② 獲取callFactory,如果沒有設置,則默認返回new OkHttpClient()
③獲取當前的callbackExecutor,即回調線程池。這個東西可以自己設,當然一般情況下我們是用平臺默認設置的:

    Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
  static class Android extends Platform {       //我們一般都是Android平臺看這部分就行了
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();     //可以看到,defaultCallbackExecutor()中new MainThreadExecutor()
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      //可以看到,這里實例化了一個獲取了主線程Looper的Handler,也就是說這個Handler實例是像主線程中發送消息的
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);    //采用Hanlder#post回調到主線程
      }
    }
  }

④adapterFactories,這個對象主要用于對Call進行轉化,基本上不需要我們自己去自定義。如果我們像最上面代碼中注釋掉的那樣添加一個addCallAdapterFactory(RxJavaCallAdapterFactory.create()),那么就不會有下面的call.enqueue(new Call<List<Bean>>(){這種的寫法了,直接轉換成RxJava那一套形式了。
⑤converterFactories,這個對象用于網絡請求轉換返回數據的轉換。最開始那段示例代碼中,我們用的是GsonConverterFactory,即Json數據解析,直接轉換成我們需要的List<Bean>中的Bean實體類獨對象了。
??當然,我們可以看到List<Converter.Factory> converterFactories,即converterFactories是一個Converter.Factory類型的對象,對于Converter.Factory類來說,網絡請求轉換返回數據的轉換只是我們最常用的一個功能,我們如果看他的源碼的話就會發現,該接口類中有三個方法,也就是三種功能:

  • public Converter<ResponseBody, ?> responseBodyConverter()用于將ResponseBody轉換為指定類型,通常用于對響應結果的類型轉換。

  • public Converter<?, RequestBody> requestBodyConverter()用于將指定類型轉為RequestBody。一般用于將@Body,@Part,@PartMap轉為RequestBody

  • public Converter<?, String> stringConverter()用于將指定類型轉為String,用于將@Field,@FieldMap,@Path,@Query,@Header等注解的參數類型轉為String。
    對于該接口類的用法我們在之后的使用中進一步解釋。

OK,Build完之后,調用Retrofit構造函數,創建一個實例:

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      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;
  }

到這里Build模式創建Retrofit的準備工作就完成了。

二.retrofit.create中動態代理模式創建接口實例

Build完之后,就該Service service = retrofit.create(Service.class);了:

  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 {
            ......
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

這里出現了一個重量級的設計模式——動態代理。好吧這個東西剛開始聽到的時候我感覺也挺嚇人的,遂研究之。關于動態代理的詳細知識我們在這里不詳細說明,不理解的話我們可以暫時把它理解成一個類/方法攔截器,我們在Service service = retrofit.create(Service.class);這句代碼中,我們通過create(Service.class)這句代碼傳遞給了上面的源碼中的public <T> T create(final Class<T> service)方法,Service.class也就是我們定義各種接口的方法:

public interface Service {
    @GET("{username}")
    Call<List<hot>> getBeanLists(@Path("username") String username);
}

因此,可以理解為,這里的(T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler()就是攔截下了service.class這個類,public Object invoke(Object proxy, Method method, Object[] args)就是在我們調用該類中的接口方法的時候,攔截下了我們所調用的方法,然后作進一步處理。
??關于動態代理,我們可以先做這樣一個狹隘的理解,我們重點要看的是上面代碼中的后三句代碼:

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

我們接下來要有很長的篇幅是圍繞這三句代碼展開的。

1.loadServiceMethod(method);

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method); //首先從map中取看看是否已經緩存過
    if (result != null) return result;  //否則構造ServiceMethod

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result); //緩存方法到map中
      }
    }
    return result;
  }

該方法傳入的method就是上面動態代理的過程中攔截下的方法,也就是開頭我們的示例中getBeanLists()方法。這里出現了一個ServiceMethod類,該類應該是Retrofit源碼中最復雜的一個類了,它包含了將一個method轉化為Call的所有的信息。我們從這一句開始看result = new ServiceMethod.Builder<>(this, method).build();

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations(); //方法注解
      this.parameterTypes = method.getGenericParameterTypes();  //參數類型
      this.parameterAnnotationsArray = method.getParameterAnnotations();  //參數注解
    }
  public ServiceMethod build() {
      callAdapter = createCallAdapter();    //創建CallAdapter,用來代理Call
      responseType = callAdapter.responseType();    //返回的是我們方法的實際類型,例如:Call<User>,則返回User類型
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'" + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      responseConverter = createResponseConverter(); //創建ResponseConverter,轉換ResponseBody為指定類型

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);  //遍歷解析方法注解
      }

      ......
      int parameterCount = parameterAnnotationsArray.length;  //parameterAnnotationsArray為參數注解數組
      parameterHandlers = new ParameterHandler<?>[parameterCount];  //初始化ParameterHandler,用來處理參數相關
      for (int p = 0; p < parameterCount; p++) {    //遍歷參數注解數組
        Type parameterType = parameterTypes[p]; //獲取參數類型
        ......
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];   //獲取參數注解數組
        ......
        //通過注解和參數類型,解析并賦值到parameterHandlers中
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      ......
      return new ServiceMethod<>(this);
  }
1).callAdapter的創建——createCallAdapter()

callAdapter 是Call方法的代理,把retrofit2.Call<T> 轉為 T(注意和 okhttp3.Call 區分開來,retrofit2.Call<T> 表示的是對一個 Retrofit 方法的調用,也就是我們開始舉得例子中Call<List<Bean>> getBeanLists的Call),這個過程會發送一個 HTTP 請求,拿到服務器返回的數據(通過 okhttp3.Call 實現),并把數據轉換為聲明的 T 類型對象(通過 Converter<F, T> 實現);

    private CallAdapter<T, R> createCallAdapter() {
      ......
      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);
      }
    }

可以看到調用了retrofit類中的callAdapter()方法:

  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());
  }
還記得adapterFactories嗎?

這里出現了一個adapterFactories變量,還記得這個變量嗎?好吧,你肯定忘了——這個就是我們開始舉得例子中,注釋掉的那一行//addCallAdapterFactory(RxJavaCallAdapterFactory.create()).代碼所設置的東西,這里再貼一遍代碼:

 public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

如果我們不addCallAdapterFactory()方法的話,那么在Retrofit.build()方法中,系統會添加一個平臺默認的值:

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

這里又出來了一個變量——callbackExecutor同樣他也是我們之前說過的,向主線程中Post消息的回調線程池,忘了的同學可以回過頭去看一看,
??OK,示例代碼中我們注釋掉了addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就是沒有設置,那么這里應該會添加平臺默認的CallAdapterFactory,我們追蹤platform.defaultCallAdapterFactory(callbackExecutor)最終到了ExecutorCallAdapterFactory類的public CallAdapter<?, ?> get()方法中,該方法最終返回了一個new ExecutorCallbackCall<>(callbackExecutor, call):

    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

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

該ExecutorCallbackCall唯一做的事情就是將原本call的回調轉發至UI線程,因為,我們之前說過,call.enqueue(new Call<List<Bean>>(){是開啟一個異步線程。

回到nextCallAdapter()中

所以,CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);這句最終返回的就是“這個將原本call的回調轉發至UI線程的ExecutorCallbackCall”,createCallAdapter()同樣返回的是這個結果。
??通過上面的講解,我們可以知道,這個CallAdapterFactory實際上就是決定網絡請求回調方式的一個工廠。如果我們像之前注釋掉的代碼中的那樣,添加一個addCallAdapterFactory(RxJavaCallAdapterFactory.create()),那么就會調用RxJava的回調方式返回結果,而不是默認的call.enqueue(new Call<List<Bean>>(){這種的。關于Retrofit和RxJava的配合使用,不在本文的討論范圍內。

2).createResponseConverter()

responseConverter 是 Converter<ResponseBody, T> 類型,負責把服務器返回的數據(JSON、XML、二進制或者其他格式,由 ResponseBody 封裝)轉化為 T 類型的對象。
??createResponseConverter()方法拿到的是responseConverter對象,它根據我們構建retrofit時,addConverterFactory()添加的ConverterFactory對象來尋找一個合適的返回,尋找的依據主要看該converter能否處理你編寫方法的返回值類型。
??什么意思?就是說,你在接收Json文件的時候,需要根據后臺給你返回的Json格式來編寫實體類,這樣Gson()或者GsonConverterFactory.create()才能正確的解析數據成我們想要的實體類對象,否則就會轉換失敗。不過這個問題現在已經不是很嚴重了,因為有各種格式化Json數據的插件(如Android Studio 的GsonFormat插件),一般不會出錯。

   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);
      }
    }
  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) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

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

    ......
    throw new IllegalArgumentException(builder.toString());
  }

這里我們貼了一遍源碼,可以看到,整個執行的流程跟createCallAdapter()一模一樣。如果我們不指定addConverterFactory()這個參數的話,默認實現為BuiltInConverters,僅僅支持返回值的實際類型為ResponseBody和Void,也就說明了默認情況下,是不支持Call<User>這類類型的。關于BuiltInConverters我呢這里不展開說了,對本篇文章意義不大,有興趣自行看源碼。

3).遍歷解析方法注解——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 if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {

                        /**自定義HTTP請求注解**/
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {

                        /**請求頭注解**/
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError("@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {

                        /**FormUrlEncoded**/
        if (isFormEncoded) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {

                        /**Multipart**/
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }
解析請求方法注解和路徑參數——parseHttpMethodAndPath()

該方法主要用于解析我們設置的方法頂部的網絡請求方式注解,如GET,POST等(@GET("{username}")),先判斷是那種請求方式(上面的代碼中已經判斷完了),完了之后再具體解析請求方法中的路徑參數。
??這里復習一下,Http協議的URL格式為:schema://host[:port#]/path/.../[;url-params][?query-string][#anchor],“?”前面(準確的說是從域名后的第一個“/”開始到最后一個“/”為止)是訪問資源的路徑從“?”開始到“#”為止,為參數部分,又稱搜索部分、查詢部分,參數與參數之間用“&”作為分隔符。,忘了的同學可以參照我的這篇文章:HTTP協議詳解與Android相關基礎網絡編程
??在Retrofit中訪問zhy的信息的兩種形式:
http://baseurl/user/zhy

public interface IUserBiz{
    @GET("{username}")
    Call<User> getUser(@Path("username") String username);
}

http://baseurl/users?sortby=username

public interface IUserBiz{
    @GET("users")
    Call<List<User>> getUsersBySort(@Query("sortby") String sort);
}

也即是說,對于接口方法中的注解參數來說,@Path()仍然對應的是BASE_URL的自路徑,@Query()對應的才是“?”后面的參數查詢。忘了的同學可以參照鴻陽大神的這篇文章:Retrofit2 完全解析 探索與okhttp之間的關系

回到parseHttpMethodAndPath()源碼中:

int question = value.indexOf('?');  //查詢參數開始的符號,“?”之后是查詢的參數部分,“?”之前是查詢的路徑部分
if (question != -1 && question < value.length() - 1) {
    String queryParams = value.substring(question + 1); //截取"?"之前的路徑部
    Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);   //如果在“?”之前的路徑參數中使用了{},則拋出異常。
    if (queryParamMatcher.find()) {
      throw methodError("URL query string \"%s\" must not have replace block. "
          + "For dynamic query parameters use @Query.", queryParams);
    }
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);    //解析{}路徑參數保存到Set中
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");

可以看到,這個方法就是解析路徑參數,如果有“?”就把“?”之前的部分截取出來加以判斷,如果這部分路徑中有“{}”占位符,則拋出異常,讓你用@Query()標簽動態添加。
??最后一句this.relativeUrlParamNames = parsePathParameters(value);,這一句中parsePathParameters(value)這個方法主要就是解析“{}”中所包含的參數,然后存到一個set<>集合中,保存在relativeUrlParamNames這個全局變量中。

4).解析每個參數使用的注解類型(諸如 Path,Query等)——ParameterHandler
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
    if (Utils.hasUnresolvableType(parameterType)) {
      throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
          parameterType);
    }

    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    if (parameterAnnotations == null) {
      throw parameterError(p, "No Retrofit annotation found.");
    }

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

每個參數都會有一個 ParameterHandler,由 ServiceMethod#parseParameter 方法負責創建,其主要內容就是解析每個參數使用的注解類型(諸如 Path,Query,Field 等),對每種類型進行單獨的處理。
??上面代碼中,我們直接從最后一句看起:parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);這句主要就是將每個方法中的參數解析成一個parameterHandlers[]數組儲存:

    private ParameterHandler<?> parseParameter(
        int p, Type parameterType, Annotation[] annotations) {
      ParameterHandler<?> result = null;
      for (Annotation annotation : annotations) {
        ParameterHandler<?> annotationAction = parseParameterAnnotation(
            p, parameterType, annotations, annotation);
        ......
        result = annotationAction;
      }
      ......
      return result;
    }

可以看到parseParameter方法中主要調用的是parseParameterAnnotation()方法來構建ParameterHandler對象,關于這個parseParameterAnnotation()方法由于源碼是在是太長了(370+行代碼),所以我們不貼出來,主要知道他做了哪幾件事情就行:
??首先根據注解來判斷來校驗使用上有沒有錯誤,比如@Query注解必須在@Path和@Url后使用,使用了@Url注解那么請求方法注解中不允許設置請求路徑等等;然后獲取相應Converter用于轉換類型(String,ResponseBody),最后初始化相應ParameterHandler返回。

好了到這里我們第二大點二.retrofit.create中動態代理模式創建接口實例中三句重點代碼中的第一句loadServiceMethod()方法,中的ServiceMethod.build()就講完了,為了避免大家迷失在茫茫的細節當中,我們再在這里帖一遍本篇的提綱:

本篇提綱.png

并再帖一遍代碼:

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

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

這里我們還是要說一下這個build()方法最終Return的結果,也就是ServiceMethod()的構造函數:

ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();  //callFactory,默認為okhttp3.OkHttpClient

    //callAdapter,指定Retrofit.call網絡請求的回調式,默認為ExecutorCallbackCall對象,也就是文章最開頭
    //示例中的call.enqueue(new Call<List<Bean>>(){,當然我們可以指定為我們想要的的形式,如RxJava
    this.callAdapter = builder.callAdapter;

    this.baseUrl = builder.retrofit.baseUrl();//BASE_URL沒什么好說的

    //responseConverter,負責轉化服務器返回的數據成我們想要的實體對象,如果返回的是Json數據的話一般用Gson解析
    this.responseConverter = builder.responseConverter; 

    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;

    //parameterHandlers,包裝API 定義時每個方法的參數(諸如 Path,Query等),并在構造 HTTP 請求時設置參數
    this.parameterHandlers = builder.parameterHandlers;
}

這個構造函數中包含了ServiceMethod類的各種實例變量,這里我們需要重點注意幾個變量:callFactorycallAdapterresponseConverterparameterHandlers,這四個變量我們之前都有過詳細的講解,可以結合注釋復習一下。

2.構建OkHttpCall()

我們這里再帖一遍我們說過的那三句重點的代碼:

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

經過上面的分析,我們應該知道這個serviceMethod實際上就是一個包含了我們網絡請求的callFactorycallAdapterresponseConverterparameterHandlers等重要信息的一個對象。接下來我們看第二句代碼:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);這句中實例化一個okHttpCall對象,構造函數僅僅是簡單的賦值:

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

接下來看第三句代碼return serviceMethod.callAdapter.adapt(okHttpCall);,這句代碼中的serviceMethod.callAdapter,也就是我們在1.1中講的callAdapter,如何返回回調值的參數。經過上面的分析,假設我們這里沒有指定addCallAdapterFactory(RxJavaCallAdapterFactory.create())這個參數,那么我們這里的callAdapter就是默認的CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
??而這個adapterFactories是ExecutorCallAdapterFactory類的對象,我們去該類中看下:

代碼2.2(1)
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

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

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //看這里看這里,這里重寫了get方法,也就是默認的CallAdapter<?, ?> adapter =
    //apterFactories.get(i).get(returnType, annotations, this);中的get()方法
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        //看這里看這里,這句就是return serviceMethod.callAdapter.adapt(okHttpCall);中的adapt()代碼
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

調用new ExecutorCallbackCall<>(callbackExecutor, call),這個類我們將在下節中講解。
??這兩個步驟都是之前講過的,建議大家回過頭去看下(好吧我寫到這里都有點忘了之前寫過)。也就是說,ExecutorCallbackCall僅僅是對Call對象進行封裝,類似裝飾者模式,只不過將其執行時的回調通過callbackExecutor進行回調到UI線程中去了

三.發起網絡請求

首先我們再貼一遍文章開頭的示例代碼:

    Retrofit retrofit = new Retrofit.Builder().
            baseUrl(BASE_URL).
            //addCallAdapterFactory(RxJavaCallAdapterFactory.create()).
            addConverterFactory(GsonConverterFactory.create()).
            build();
    Service service = retrofit.create(Service.class);

    Call<List<Bean>> call = service.getBeanLists(“username”);
    call.enqueue(new Call<List<Bean>>(){
        @Override
        public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
            beanList = response.body();
            ...     //doSomething();
        }

        @Override
        public void onFailure(Call<List<hot>> call, Throwable t) {
            Toast.makeText(getContext(), "讀取失敗,請檢查網絡設置", Toast.LENGTH_SHORT).show();
        }
    });
public interface Service {
    @GET("{username}")
    Call<List<Bean>> getBeanLists(@Path("username") String username);
}

經過我們上述的講解,Retrofit底層的基礎設施基本就講完了,現在我們來發起一個網絡請求。嗯,網絡請求是在哪里發起的呢?實際上只要我們執行了Call<List<Bean>> call = service.getBeanLists(“username”);這一句之后,網絡請求就開始了,然后我們只需要在call.enqueue(new Call<List<Bean>>(){中等著回調參數就行了。

我們這里要講的是,網絡請求的數據,是如何下發到我們重寫的

call.enqueue(new Call<List<Bean>>(){
    @Override
    public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
    }

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

中來的?

1.從ExecutorCallAdapterFactory到OkHttpCall

首先我們得接著上一節“構建OkHttpCall()”代碼2.2(1)說起,我們說過,代碼2.2(1)中實現了示例代碼中“retrofit.create(HotService.class);”這句對應的源碼中,三句關鍵代碼的第三句return serviceMethod.callAdapter.adapt(okHttpCall);這句代碼,我們把這個類的代碼再貼一遍,這次順便帶上ExecutorCallbackCall這個靜態內部類:

ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
代碼3.1(1)
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }
  ......(省略部分代碼2.2(1)中的內容)
  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

      @Override public Call<Object> adapt(Call<Object> call) {
        //我們說過,這里重寫的adapt()就是三句關鍵代碼中第三就的adapt,也即是說,這里的參數Call<Object> call
        //就是第二句中構建的OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

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

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      //這個callbackExecutor就是一個線程池對象,用來開啟異步線程,沒有什么好說的
      this.callbackExecutor = callbackExecutor;
      //在ExecutorCallbackCall類的構造函數中,又將okHttpCall對象遞給delegate對象
      this.delegate = delegate;
    }

    @Override 
    public void enqueue(final Callback<T> callback) {                             (enqueue.1)
      if (callback == null) throw new NullPointerException("callback == null");
      //delegate是一個OkHttpCall類的對象,這一點要明確
      delegate.enqueue(new Callback<T>() {                                          (enqueue.2)
        @Override
        public void onResponse(Call<T> call, final Response<T> response) {            (onResponse.1)
          callbackExecutor.execute(new Runnable() {
            @Override
            public void run() {
              if (delegate.isCanceled()) {
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));  (onFailure.1)
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);                 (onResponse.2)
              }
            }
          });
        }

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

為什么要貼這么一串又臭又長的源碼呢?可以看到上面的代碼中我們標出了2個enqueue()方法,2個onResponse()方法,3個onFailure()方法~~好吧我剛開始看也看懵逼了,后來才發現,這里有兩個接口在嵌套使用,所以必須對照源碼才能說的清楚。

2個enqueue()方法

我們要分清楚這兩個enqueue()方法都是干什么的。首先我們看(enqueue.1)處的這個enqueue方法,可以看到他是@Override,即重寫的方法,重寫的誰的呢?當然是ExecutorCallbackCall類實現的Call<T>中的方法,這里需要注意一點,這里的Call<T>retrofit2.call<T>,不要和待會出現的okhttp3.Call搞混了。
??我們再來看(enqueue.2)處的enqueue,這個enqueue是由delegate調用的,我們之前強調過,delegate是OkHttpCall類的對象,也就是說,這里的enqueue(new Callback<T>() {實際上是OkHttpCall類中傳過來的,我們進入到該類中,看看該類中的enqueue()方法(retrofit-2.2.0-source.jar/retrofit2/OkHttpCall):

代碼3.1(2)
public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("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(); //createRawCall()方法創建原始Call,即okhttp3.Call對象
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

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

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

    call.enqueue(new okhttp3.Callback() {   //調用okhttp3.Call發起一個enqueue()異步請求
    //注意這里的enqueue()方法是OkHttp中的"真"異步請求方法,前面的都是自定義的"假"方法
    @Override
      public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)   (onResponse.4)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);    //解析服務器返回的內容,生成response對象
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

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

      private void callFailure(Throwable e) {
        try {
          //這里通過callBack將錯誤結果返回給ExecutorCallbackCall類
          callback.onFailure(OkHttpCall.this, e);                       (onFailure.3)
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          //這里通過callback回調接口將網絡請求并解析后的結果返回給ExecutorCallbackCall類
          callback.onResponse(OkHttpCall.this, response);                           (onResponse.3)
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

OkHttpCall類中的enqueue()方法很簡單,實際上就是先創建一個okhttp3.Call對象,然后利用這個okhttp3.Call發起一個異步請求,完了時候講返回的結果通過callback接口返回給ExecutorCallbackCall類。
??我們需要注意這里的調用關系:

3.1(1)
delegate.enqueue(new Callback<T>() {
3.1(2)
public void enqueue(final Callback<T> callback) {

也就是說,代碼3.1(1)中(enqueue.2)處的new Callback,就是我們代碼3.1(2)中的參數final Callback<T> callback,所以我們在代碼3.1(2)中的(onFailure.3),(onResponse.3)都會通過這個callback實例回調到代碼3.1(2)中的(onResponse.1)和(onFailure.2),這個對應關系一定要看清楚。
??我們再強調一遍,代碼3.1(2)中的(onResponse.1)和(onFailure.2)兩個@Override類型的方法,它們是OkHttpCall類(3.1(2))中(onFailure.3)和(onResponse.3)兩處的方法,的回調!!!
??而OkHttpCall類(3.1(2))中(onFailure.4)和(onResponse.4)兩處重寫的方法,它們重寫的是call.enqueue(new okhttp3.Callback() {這個OkHttp異步請求的接口的,onFailure和onResponse方法,表示OkHttp網絡請求的結果。
??是不是感覺腦子暈暈的?沒錯,不知道Squareup為什么這段代碼寫的可讀性這么差~~~嗯,更精彩的還在后面,這里假設你已經理解了上面這幾個長的一模一樣但是卻代表不同意義的幾個方法和回調。

回到ExecutorCallAdapterFactory(3.1(1))類中,如果你已經理解了上面所說的話,就應該知道,(onResponse.1)和(onFailure.2)這兩個重寫方法,是OkHttpCall類(3.1(2))中OkHttp的異步網絡請求所回調回來的結果。我們再貼一下代碼:

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;
    ......
    @Override 
    public void enqueue(final Callback<T> callback) {                             (enqueue.1)
      if (callback == null) throw new NullPointerException("callback == null");
      //delegate是一個OkHttpCall類的對象,這一點要明確
      delegate.enqueue(new Callback<T>() {                                          (enqueue.2)
        @Override
        public void onResponse(Call<T> call, final Response<T> response) {            (onResponse.1)
          callbackExecutor.execute(new Runnable() {
            @Override
            public void run() {
              if (delegate.isCanceled()) {
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));  (onFailure.1)
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);                 (onResponse.2)
              }
            }
          });
        }

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

我們再來看看這個(onFailure.1)和(onResponse.2)這兩種方法,這里有出現了一個callback,這里的callback又是什么呢?Ok,如果你看源碼的化就會發現,這個Callback是(enqueue.1)處:

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

這個重寫的enqueue()的參數,我們之前說過,這里的enqueue重寫的是Call<T>接口中的方法,因為ExecutorCallbackCall<T> implements Call<T>,而另一端回調這個Call<T>接口的地方,是在我們縮寫的代碼中:

call.enqueue(new Call<List<Bean>>(){
    @Override
    public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
    }

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

看到了吧?(onFailure.2)(onResponse.2)這兩處的callback回調,最終回調到了我們所寫的call.enqueue(new Call<List<Bean>>(){中,并且攜帶著已經轉換成我們想要的特定實體類型的數據。
??到這里,我們已經拿到了我們想要的數據,整個分析的過程也就走完了。

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

推薦閱讀更多精彩內容