Android網(wǎng)絡(luò)請(qǐng)求庫(kù)【Retrofit 2.9.0】基本用法與原理分析


Retrofit官網(wǎng):https://square.github.io/retrofit/
Github地址:https://github.com/square/retrofit


前言

Retrofit是Square公司開(kāi)發(fā)的一款A(yù)ndroid網(wǎng)絡(luò)請(qǐng)求庫(kù)爸黄,Retrofit僅負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求接口的封裝,它使用運(yùn)行時(shí)注解的方式提供請(qǐng)求參數(shù)的配置功能奔浅,底層基于OkHttp實(shí)現(xiàn)真正的網(wǎng)絡(luò)請(qǐng)求馆纳。

如果還不了解OkHttp框架,強(qiáng)烈建議先閱讀Android 網(wǎng)絡(luò)請(qǐng)求庫(kù)OkHttp基本原理與實(shí)現(xiàn)再來(lái)閱讀本篇文章汹桦,會(huì)更加酣暢淋漓哦~

本文所提及的網(wǎng)絡(luò)請(qǐng)求如無(wú)特殊說(shuō)明鲁驶,都是異步網(wǎng)絡(luò)請(qǐng)求

為什么選擇Retrofit(與其他主流框架對(duì)比)

現(xiàn)在市場(chǎng)上比較主流的網(wǎng)絡(luò)請(qǐng)求框架有:

一圖讓你了解全部的網(wǎng)絡(luò)請(qǐng)求庫(kù)和他們之間的區(qū)別舞骆!


Retrofit基本用法

1. 導(dǎo)入庫(kù)

    implementation("com.squareup.okhttp3:okhttp:4.9.3")
    // define a BOM and its version
    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
    implementation("com.squareup.okhttp3:logging-interceptor")

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation("com.squareup.retrofit2:converter-gson:2.9.0") //支持返回值為Gson類型的數(shù)據(jù)

默認(rèn)情況下钥弯,Retrofit只能將數(shù)據(jù)反序列化為OkHttp的ResponseBody類型,并且它只能接受@Body注解的RequestBody類型督禽。

除了默認(rèn)情況脆霎,我們也可以添加轉(zhuǎn)換器以支持其他類型。

  • Gson: com.squareup.retrofit2:converter-gson
  • Jackson: com.squareup.retrofit2:converter-jackson
  • Moshi: com.squareup.retrofit2:converter-moshi
  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire
  • Simple XML: com.squareup.retrofit2:converter-simplexml
  • JAXB: com.squareup.retrofit2:converter-jaxb
  • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

2. 注解分類

Retrofit注解分為三大類狈惫,分別是請(qǐng)求方法注解睛蛛、標(biāo)記類注解和參數(shù)類注解。

請(qǐng)求方法注解有8種:GET/POST/PUT/DELETE/HEAD/PATCH/OPTIONS/HTTP胧谈,前7種與HTTP請(qǐng)求方法是對(duì)應(yīng)的忆肾,最后的HTTP可以替換前面七種,也可以擴(kuò)展請(qǐng)求方法菱肖。

標(biāo)記類注解有3種:FormUrlEncoded客冈、Multipart、Streaming稳强。

參數(shù)類注解有Header场仲、Headers、Body退疫、Path渠缕、Field、FieldMap褒繁、Query亦鳞、QueryMap、Part、PartMap等蚜迅。

3. GET網(wǎng)絡(luò)請(qǐng)求

首先編寫請(qǐng)求網(wǎng)絡(luò)接口

open interface ApiService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo?>?>?
}

@GET 注解指定當(dāng)前網(wǎng)絡(luò)請(qǐng)求方式,注解參數(shù)是訪問(wèn)地址俊抵,方法返回Call<List<Repo?>?>類型的數(shù)據(jù)谁不。@Path注解用來(lái)動(dòng)態(tài)配置Url地址,@Path("user")對(duì)應(yīng)@GET注解中的{user}徽诲,即使用傳入的 user: String?值動(dòng)態(tài)替換{user}

接下來(lái)創(chuàng)建Retrofit對(duì)象刹帕,創(chuàng)建接口類(動(dòng)態(tài)代理)調(diào)用網(wǎng)絡(luò)請(qǐng)求方法,得到Call并發(fā)起異步請(qǐng)求谎替,回調(diào)的Callback運(yùn)行在UI線程偷溺。

val retrofit = Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())  //數(shù)據(jù)轉(zhuǎn)換器Factory
        .build()
val listRepos = retrofit.create(ApiService::class.java).listRepos("octocat")
listRepos?.enqueue(object : Callback<List<Repo?>?> {
    override fun onResponse(call: Call<List<Repo?>?>, response: Response<List<Repo?>?>) {
        Log.d("retrofit", response.toString())
    }

    override fun onFailure(call: Call<List<Repo?>?>, t: Throwable) {

    }
})

請(qǐng)求的Url是由baseUrl和@GET注解參數(shù)拼接出來(lái)的:https://api.github.com/users/octocat/repos

一般情況下為了更準(zhǔn)確地去查找網(wǎng)絡(luò)數(shù)據(jù),我們需要在Url中添加查詢參數(shù)钱贯,這種情況可以使用Query指定查詢條件挫掏。例如根據(jù)id查找數(shù)據(jù),我們修改代碼如下:

@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String?, 
              @Query("id") id: Int?): Call<List<Repo?>?>?
val listRepos = retrofit.create(ApiService::class.java).listRepos("octocat", 132935648)

這樣請(qǐng)求Url變?yōu)椋?a target="_blank">https://api.github.com/users/octocat/repos?id=132935648

如果有多個(gè)查詢參數(shù)使用@QueryMap

@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String?,
              @QueryMap map:HashMap<String, Any>): Call<List<Repo?>?>?
val hashMap = HashMap<String, Any>()
hashMap.put("id", 132935648)
val listRepos = retrofit.create(ApiService::class.java).listRepos("octocat", hashMap)

4. POST網(wǎng)絡(luò)請(qǐng)求

POST請(qǐng)求最常見(jiàn)的情況是傳輸鍵值對(duì)的數(shù)據(jù)類型秩命,使用@Field注解就可以為POST請(qǐng)求添加鍵值對(duì)

@FormUrlEncoded
@POST("user/edit")
fun listRepos(@Field("first_name") first: String,
              @Field("last_name") last: String, ): Call<List<Repo?>?>?
val listRepos = retrofit.create(ApiService::class.java).listRepos("張", "三")

@FormUrlEncoded表明這是一個(gè)表單請(qǐng)求尉共,使用@Field注解標(biāo)注對(duì)應(yīng)的鍵值對(duì)。

POST請(qǐng)求除了傳輸鍵值對(duì)弃锐,還可以傳輸JSON字符串袄友,對(duì)應(yīng)注解@Body。

package android.com.retrofit
data class User(val id: Int,
                val age: Int,
                val school: String) {
    constructor() : this(999, 16, "abc")
}
@POST("user/edit")
fun listRepos(@Body user: User): Call<List<Repo?>?>?
val listRepos = retrofit.create(ApiService::class.java).listRepos(User())

上傳單個(gè)文件


 * @param photo 上傳的文件
 * @param desc 文件描述(簡(jiǎn)單的鍵值對(duì))
 */
@Multipart //表示允許多個(gè)part
@POST("user/photo")
fun uploadPhoto(@Part photo: MultipartBody.Part,
                @Part("desc") desc:
val file = File("文件路徑")
val create = file.asRequestBody("image".toMediaTypeOrNull())
val photo = MultipartBody.Part.createFormData("photos", "aaa", create)
val requestBodyDesc = "picture".toRequestBody(null)
val listRepos = retrofit.create(ApiService::class.java).uploadPhoto(photo,requestBodyDesc)

上傳多個(gè)文件
與上傳單個(gè)文件類似霹菊,使用Map封裝上傳的文件剧蚣,用@PartMap注解標(biāo)注

更多用法可參考Carson帶你學(xué)Android:網(wǎng)絡(luò)請(qǐng)求庫(kù)Retrofit使用教程(含實(shí)例講解)

Retrofit原理解析

Retrofit最終的目的是通過(guò)使用大量的設(shè)計(jì)模式進(jìn)行功能模塊的解耦,使得網(wǎng)絡(luò)請(qǐng)求過(guò)程變得更加簡(jiǎn)單流暢旋廷。

下圖可以直觀對(duì)比出一般網(wǎng)絡(luò)請(qǐng)求流程與Retrofit請(qǐng)求的區(qū)別


Retrofit流程

詳細(xì)步驟如下:

  1. 通過(guò)解析網(wǎng)絡(luò)請(qǐng)求接口的注解配置網(wǎng)絡(luò)請(qǐng)求參數(shù)
  2. 通過(guò)動(dòng)態(tài)代理生成網(wǎng)絡(luò)請(qǐng)求對(duì)象
  3. 通過(guò)網(wǎng)絡(luò)請(qǐng)求適配器將網(wǎng)絡(luò)請(qǐng)求對(duì)象進(jìn)行平臺(tái)適配(平臺(tái)包括:Android鸠按、Rxjava、Guava和java8)
  4. 通過(guò)網(wǎng)絡(luò)請(qǐng)求執(zhí)行器發(fā)送網(wǎng)絡(luò)請(qǐng)求
  5. 通過(guò)數(shù)據(jù)轉(zhuǎn)換器解析服務(wù)器返回的數(shù)據(jù)
  6. 通過(guò)回調(diào)執(zhí)行器切換線程(子線程 ->>主線程)
  7. 用戶在主線程處理返回結(jié)果
主要角色說(shuō)明

源碼分析(基于Retrofit 2.9.0)

我們從Retrofit最基本的使用方式作為切入口柳洋,一步步深入源碼探索Retrofit實(shí)現(xiàn)原理待诅。

Retrofit使用主要分為以下幾步:

  1. 創(chuàng)建Retrofit對(duì)象(建造者模式)
  2. 實(shí)例化接口類并調(diào)用請(qǐng)求方法(動(dòng)態(tài)代理)
  3. 使用第2步返回的Call發(fā)起網(wǎng)絡(luò)請(qǐng)求,Callback回調(diào)會(huì)運(yùn)行在UI線程

接下來(lái)展開(kāi)分析:

1. Retrofit.Builder()

因?yàn)镽etrofit可配置的參數(shù)較多熊镣,所以采用建造者模式創(chuàng)建Retrofit實(shí)例卑雁。

Builder類主要代碼如下:

  public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;  //網(wǎng)絡(luò)請(qǐng)求基本地址
    private final List<Converter.Factory> converterFactories = new ArrayList<>();   //用于創(chuàng)建Converter.Factory
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();   //用于創(chuàng)建CallAdapter.Factory
    private @Nullable Executor callbackExecutor;    //切換線程執(zhí)行回調(diào)任務(wù)(默認(rèn)是主線程)
    private boolean validateEagerly;

    //指定OkHttpClient
    public Builder client(OkHttpClient client) {  
      return callFactory(Objects.requireNonNull(client, "client == null"));
    }

    //設(shè)置baseUrl
    public Builder baseUrl(URL baseUrl) {  
      Objects.requireNonNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl.toString()));
    }

    /** 添加自定義的Converter Factory:用于創(chuàng)建數(shù)據(jù)轉(zhuǎn)換器Converter  */
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

    /**
     * Add a call adapter factory for supporting service method return types other than {@link
     * Call}.  添加自定義的CallAdapter Factory:用于創(chuàng)建網(wǎng)絡(luò)請(qǐng)求適配器CallAdapter
     */
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

    //指定執(zhí)行回調(diào)任務(wù)的Executor
    public Builder callbackExecutor(Executor executor) {
      this.callbackExecutor = Objects.requireNonNull(executor, "executor == null");
      return this;
    }

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      //設(shè)置默認(rèn)OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;  
      if (callFactory == null) {
        callFactory = new OkHttpClient(); 
      }
     //android平臺(tái)默認(rèn)使用MainThreadExecutor,用于切換到主線程執(zhí)行任務(wù)
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {  
        callbackExecutor = platform.defaultCallbackExecutor();  
      }

      //添加平臺(tái)默認(rèn)CallAdapter.Factory到CallAdapterFactories
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);  
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      //添加平臺(tái)默認(rèn)Converter.Factory到converterFactories 
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

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

如果未配置參數(shù),build()方法會(huì)為我們提供大多數(shù)的默認(rèn)配置窘行,例如callAdapterFactories(創(chuàng)建網(wǎng)絡(luò)請(qǐng)求適配器)资铡、converterFactories(創(chuàng)建數(shù)據(jù)轉(zhuǎn)換器)、callbackExecutor(執(zhí)行回調(diào)任務(wù))等待扣甲。

2. retrofit.create(ApiService::class.java).listRepos("octocat")

第一步:采取動(dòng)態(tài)代理的方式創(chuàng)建請(qǐng)求接口的實(shí)現(xiàn)類

  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
            //如果是Object的成員函數(shù),直接使用反射調(diào)用方法
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                //platform.isDefaultMethod(method)返回true表示方法是公共的非抽象實(shí)例方法
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);   //接口方法會(huì)執(zhí)行到此處
              }
            });
  }

ApiService.kt是一個(gè)接口類,當(dāng)我們調(diào)用接口內(nèi)的方法時(shí)會(huì)執(zhí)行代碼:InvocationHandler# invoke(Object proxy, Method method, @Nullable Object[] args) -> loadServiceMethod(method).invoke(args)琉挖,先分析loadServiceMethod(method)方法:

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

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

代碼很簡(jiǎn)單启泣,調(diào)用ServiceMethod.parseAnnotations(this, method)解析接口中的注解方法并封裝成ServiceMethod。并且利用serviceMethodCache緩存解析結(jié)果示辈,這樣可以防止重復(fù)解析寥茫,使用緩存是因?yàn)榻馕龅倪^(guò)程用到了比較耗費(fèi)性能的反射機(jī)制。

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //注釋2.1:解析方法注解和參數(shù)注解矾麻,把注解中的網(wǎng)絡(luò)請(qǐng)求參數(shù)封裝到RequestFactory中
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); 

    //注釋2.2:保證方法返回類型不是Unresolvable和void.class
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    //注釋2.3
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

注釋2.1:RequestFactory.parseAnnotations(retrofit, method)解析注解信息纱耻,把信息封裝到RequestFactory中
注釋2.2:保證方法返回類型不是Unresolvable和void.class
注釋2.3:調(diào)用HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)獲取ServiceMethod

#HttpServiceMethod
//這里只貼出部分代碼
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;  //方法返回值類型
    //isKotlinSuspendFunction默認(rèn)為false,進(jìn)入else語(yǔ)句獲取adapterType 
    if (isKotlinSuspendFunction) {  
      ……
    } else {
      adapterType = method.getGenericReturnType(); 
    }
    //注釋2.3.1:從callAdapterFactories列表中取出CallAdapter.Factory創(chuàng)建CallAdapter
    //我們可以使用Retrofit.Builder#addCallAdapterFactory(Factory)添加CallAdapter.Factory到列表callAdapterFactories
    //CallAdapter負(fù)責(zé)執(zhí)行網(wǎng)絡(luò)請(qǐng)求Call的適配工作
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);  
    Type responseType = callAdapter.responseType();

    ……

    //注釋2.3.2:從converterFactories列表中取出Converter.Factory創(chuàng)建Converter
    //我們可以使用Retrofit.Builder#addConverterFactory(Factory)添加Converter .Factory到converterFactories列表
    //Converter負(fù)責(zé)將服務(wù)端返回的數(shù)據(jù)轉(zhuǎn)換成對(duì)象實(shí)例
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    //注釋2.3.3:把requestFactory, callFactory, responseConverter, callAdapter封裝進(jìn)最終的HttpServiceMethod
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
  }

注釋2.3.1:從callAdapterFactories列表中取出CallAdapter.Factory創(chuàng)建CallAdapter险耀,具體流程如下:

//HttpServiceMethod.java
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }

調(diào)用retrofit.callAdapter(returnType, annotations)

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

  public CallAdapter<?, ?> nextCallAdapter(
      @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    //遍歷callAdapterFactories列表獲取CallAdapter.Factory來(lái)創(chuàng)建CallAdapter
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {  
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    //獲取失敗
  }

最終遍歷callAdapterFactories列表獲取CallAdapterFactory來(lái)創(chuàng)建我們需要的網(wǎng)絡(luò)請(qǐng)求適配器CallAdapter弄喘,在構(gòu)建Retrofit時(shí)已經(jīng)添加Android平臺(tái)默認(rèn)的platform.defaultCallAdapterFactories到callAdapterFactories

//Retrofit.Builder#build()
//添加默認(rèn)Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

除了使用默認(rèn)的CallAdapterFactory,我們也可以使用Retrofit.Builder#addCallAdapterFactory(Factory)主動(dòng)添加CallAdapter.Factory到列表callAdapterFactories

CallAdapter主要負(fù)責(zé)執(zhí)行網(wǎng)絡(luò)請(qǐng)求Call的適配工作甩牺,注釋2.3.2會(huì)詳細(xì)分析

注釋2.3.2:從converterFactories列表中取出Converter.Factory創(chuàng)建Converter蘑志,具體流程如下:

//HttpServiceMethod.java
  private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create converter for %s", responseType);
    }
  }

調(diào)用retrofit.responseBodyConverter(responseType, annotations)

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

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    Objects.requireNonNull(type, "type == null");
    Objects.requireNonNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    //遍歷converterFactories列表獲取Converter.Factory來(lái)創(chuàng)建Converter
    for (int i = start, count = converterFactories.size(); i < count; i++) {  
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

    //獲取失敗
  }

最終遍歷converterFactories列表獲取Converter.Factory來(lái)創(chuàng)建我們需要的Converter,在構(gòu)建Retrofit時(shí)已經(jīng)添加Android平臺(tái)默認(rèn)的platform.defaultConverterFactories()到defaultConverterFactories

//Retrofit.Builder#build()
List<Converter.Factory> converterFactories = new ArrayList<>(
     1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());

除了使用默認(rèn)的ConverterFactory柴灯,我們也可以使用Retrofit.Builder#addConverterFactory(Factory)添加Converter .Factory到converterFactories列表卖漫;Converter負(fù)責(zé)將服務(wù)端返回的數(shù)據(jù)轉(zhuǎn)換成對(duì)象實(shí)例

注釋2.3.3:把requestFactory, callFactory, responseConverter, callAdapter封裝進(jìn)最終的HttpServiceMethod

如果未使用Kotlin的Suspend功能,注釋2.3.3處會(huì)直接執(zhí)行if語(yǔ)句赠群,即創(chuàng)建一個(gè)CallAdapted羊始,它繼承自HttpServiceMethod,代碼如下:

  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }

CallAdapted主要是為了實(shí)現(xiàn)HttpServiceMethod的抽象方法ReturnT adapt(Call<ResponseT> call, Object[] args)查描,而具體工作交由callAdapter.adapt(call)方法執(zhí)行突委。

我們?cè)倩氐絩etrofit.create(ApiService::class.java)方法,重新貼一下代碼:

  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

第二步:當(dāng)我們調(diào)用接口ApiService中的listRepos("octocat")方法冬三,動(dòng)態(tài)代理機(jī)制會(huì)調(diào)用InvocationHandler內(nèi)的invoke(Object proxy, Method method, @Nullable Object[] args)方法匀油,然后會(huì)執(zhí)行loadServiceMethod(method).invoke(args)

通過(guò)前面的分析我們知道勾笆,loadServiceMethod(method)方法返回的是一個(gè)ServiceMethod敌蚜,查看它的invoke()方法:

//ServiceMethod.java
abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

invoke(Object[] args)方法在HttpServiceMethod中實(shí)現(xiàn):

//HttpServiceMethod.java
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

創(chuàng)建一個(gè)OkHttpCall對(duì)象作為adapt(call, args)方法的參數(shù),前面已經(jīng)分析過(guò)CallAdapted中實(shí)現(xiàn)了adapt(call, args)方法窝爪,call最終傳遞給callAdapter.adapt(call)方法適配出新call弛车。(適配器模式)

如果沒(méi)有手動(dòng)指定callAdapter,默認(rèn)使用DefaultCallAdapterFactory創(chuàng)建callAdapter:

//精簡(jiǎn)后的代碼
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

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

    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

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

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

  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) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

  }
}

默認(rèn)的網(wǎng)絡(luò)請(qǐng)求適配器主要做了兩件事:

  1. 在CallAdapter#adapt(Call<Object> call) 方法中將OkHttpCall適配成ExecutorCallbackCall來(lái)執(zhí)行網(wǎng)絡(luò)請(qǐng)求(適配器模式)蒲每,真正的網(wǎng)絡(luò)請(qǐng)求依然由OkHttpCall自己發(fā)起(代理模式)
  2. 請(qǐng)求完成后將Callback回調(diào)方法切換到callbackExecutor中執(zhí)行纷跛,Retrofit提供的默認(rèn)callbackExecutor負(fù)責(zé)將任務(wù)提交到主線程

3. OkHttpCall發(fā)起網(wǎng)絡(luò)請(qǐng)求

我們已經(jīng)知道真正的網(wǎng)絡(luò)請(qǐng)求由OkHttpCall發(fā)起,那還等什么快去看看吧

  @Override
  public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();  //注釋3.1: 使用OkHttpClient創(chuàng)建okhttp3.Call
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

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

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

    //注釋3.2:使用創(chuàng)建好的okhttp3.Call發(fā)起異步請(qǐng)求
    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);  //注釋3.3:解析服務(wù)端返回的數(shù)據(jù)
            } catch (Throwable e) {
              throwIfFatal(e);
              callFailure(e);
              return;
            }

            try {
              callback.onResponse(OkHttpCall.this, response); 
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            callFailure(e);
          }

          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }
        });
  }

注釋3.1: 使用OkHttpClient創(chuàng)建okhttp3.Call

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

注釋3.2:使用創(chuàng)建好的okhttp3.Call發(fā)起異步請(qǐng)求

注釋3.3:處理服務(wù)端返回的數(shù)據(jù)

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse =
        rawResponse
            .newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();

    //返回碼處理
    int code = rawResponse.code();
    if (code < 200 || code >= 300) {  //網(wǎng)絡(luò)請(qǐng)求出現(xiàn)異常
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {  //返回Body為null的Response
      rawBody.close();
      return Response.success(null, rawResponse);  
    }

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      //responseConverter開(kāi)始轉(zhuǎn)換網(wǎng)絡(luò)數(shù)據(jù)
      T body = responseConverter.convert(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;
    }
  }

執(zhí)行responseConverter.convert(catchingBody)方法轉(zhuǎn)換Response數(shù)據(jù)邀杏,那么responseConverter具體類型是什么呢贫奠?

我們?cè)诔跏蓟疪etrofit時(shí)調(diào)用了Retrofit.Builder()#addConverterFactory(GsonConverterFactory.create())方法

val retrofit = Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())  //添加Gson轉(zhuǎn)換器
        .build()
#Retrofit.java
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

也就是將GsonConverterFactory添加到列表converterFactories,看一下GsonConverterFactory源碼:

public final class GsonConverterFactory extends Converter.Factory {

  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(
      Type type, Annotation[] annotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(
      Type type,
      Annotation[] parameterAnnotations,
      Annotation[] methodAnnotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

通過(guò)注釋2.3.2可知,我們要尋找的responseConverter就是GsonResponseBodyConverter唤崭,重新回到注釋3.3中的Response轉(zhuǎn)換過(guò)程responseConverter.convert拷恨,本質(zhì)上是執(zhí)行GsonResponseBodyConverter.convert:

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

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

  @Override
  public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }
}

convert(ResponseBody value)方法負(fù)責(zé)把ResponseBody轉(zhuǎn)換成指定的數(shù)據(jù)類型

到此為止,還剩最后一個(gè)任務(wù):異步請(qǐng)求任務(wù)完成之后會(huì)以回調(diào)的方式通知發(fā)起方請(qǐng)求已經(jīng)結(jié)束谢肾,為了方便將請(qǐng)求結(jié)果展示到UI上挑随,需要把回調(diào)操作切換到主線程執(zhí)行,這個(gè)任務(wù)由ExecutorCallbackCall負(fù)責(zé)完成

  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) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

    @Override
    public Response<T> execute() throws IOException {
      return delegate.execute();
    }
    
    ……
  }

具體方法是將callback.onXxxxx()回調(diào)方法丟到callbackExecutor執(zhí)行勒叠,可以在Retrofit中使用方法callbackExecutor(Executor executor)配置callbackExecutor。

如果未配置callbackExecutor膏孟,Retrofit會(huì)提供默認(rèn)callbackExecutor眯分,默認(rèn)配置相關(guān)的實(shí)現(xiàn)依然是在Retrofit.Builder#build()方法中

//Retrofit.Builder#build()
  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }
//Android平臺(tái)
  static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Nullable
    @Override
    Object invokeDefaultMethod(
        Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
      if (Build.VERSION.SDK_INT < 26) {
        throw new UnsupportedOperationException(
            "Calling default methods on API 24 and 25 is not supported");
      }
      return super.invokeDefaultMethod(method, declaringClass, object, args);
    }

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

callbackExecutor默認(rèn)是MainThreadExecutor,MainThreadExecutor負(fù)責(zé)將任務(wù)提交到主線程執(zhí)行

源碼分析結(jié)束柒桑!

Retrofit源碼真是太牛逼了弊决,本人水平有限,如有錯(cuò)誤希望大家批評(píng)指正魁淳!


參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末飘诗,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子界逛,更是在濱河造成了極大的恐慌昆稿,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件息拜,死亡現(xiàn)場(chǎng)離奇詭異溉潭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)少欺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門喳瓣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赞别,你說(shuō)我怎么就攤上這事畏陕。” “怎么了仿滔?”我有些...
    開(kāi)封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵惠毁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我堤撵,道長(zhǎng)仁讨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任实昨,我火速辦了婚禮洞豁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己丈挟,他們只是感情好刁卜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著曙咽,像睡著了一般蛔趴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上例朱,一...
    開(kāi)封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天孝情,我揣著相機(jī)與錄音,去河邊找鬼洒嗤。 笑死箫荡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渔隶。 我是一名探鬼主播羔挡,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼间唉!你這毒婦竟也來(lái)了绞灼?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤呈野,失蹤者是張志新(化名)和其女友劉穎低矮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體被冒,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡商佛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了姆打。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片良姆。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖幔戏,靈堂內(nèi)的尸體忽然破棺而出玛追,到底是詐尸還是另有隱情,我是刑警寧澤闲延,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布痊剖,位于F島的核電站,受9級(jí)特大地震影響垒玲,放射性物質(zhì)發(fā)生泄漏陆馁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一合愈、第九天 我趴在偏房一處隱蔽的房頂上張望叮贩。 院中可真熱鬧击狮,春花似錦、人聲如沸益老。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捺萌。三九已至档冬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間桃纯,已是汗流浹背酷誓。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留态坦,地道東北人呛牲。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像驮配,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子着茸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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