Android Retrofit源碼解析:都能看懂的Retrofit使用詳解

你在使用 Retrofit 的時候,是否會有如下幾點疑惑?

  • 什么是動態代理?

  • 整個請求的流程是怎樣的?

  • 底層是如何用 OkHttp 請求的?

  • 方法上的注解是什么時候解析的,怎么解析的?

  • Converter 的轉換過程,怎么通過 Gson 轉成對應的數據模型的?

  • CallAdapter 的替換過程,怎么轉成 RxJava 進行操作的?

  • 如何支持 Kotlin 協程的 suspend 掛起函數的?

    關于 Kotlin 協程請求網絡,首先寫一個 Demo 來看一下用協程是怎么進行網絡請求的,然后會再具體分析怎么轉換成 Kotlin 的協程的請求

我會在文章中,通過源碼,逐步解開疑惑,并且在最后文章結尾會再次總結,回答上面的幾個問題。

友情提示,本文略長但是沒有廢話,實打實的干貨,學習需要耐心
Retrofit和 OkHttp是目前最廣泛使用的網絡請求庫了,所以有必要了解它的源碼,學習它的優秀的代碼與設計,來提升自己。

本文的整體思路

首先先看一下 Retrofit 的基本用法,根據示例代碼,作為分析源碼的依據,以及分析源碼的入口,來一步一步看一下 Retrofit 的工作機制。

本文的依賴

implementation 'com.squareup.okhttp3:okhttp:4.8.1'

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.2'

implementation 'com.google.code.gson:gson:2.8.6'

implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
復制代碼

1.什么是Retrofit

Retrofit:A type-safe HTTP client for Android and Java。一個類型安全的 Http 請求的客戶端。

底層的網絡請求是基于 OkHttp 的,Retrofit 對其做了封裝,提供了即方便又高效的網絡訪問框架。

2.Retrofit的基本用法

class RetrofitActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //初始化一個Retrofit對象
        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        //創建出GitHubApiService對象
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個 Call 對象
        val repos = service.listRepos("octocat")
        //調用 enqueue 方法在回調方法里處理結果
        repos.enqueue(object : Callback<List<Repo>?> {
            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
                                t.printStackTrace()
            }

            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                "response.code() = ${response.code()}".logE()
            }
        })

    }
}
復制代碼
//自己定義的 API 請求接口
interface GitHubApiService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}
復制代碼

以上就是 Retrofit 的基本用法。

沒什么好講的,寫這個例子就是為了分析源碼做準備,有一個源碼分析的入口。

3.源碼分析的準備工作

先看幾個表面上的類

  • Retrofit:總攬全局一個類,一些配置,需要通過其內部 Builder 類構建,比如 CallAdapter、Converter 等
  • GitHubApiService:自己寫的 API 接口,通過 Retrofit 的 create 方法進行實例化
  • Call:Retrofit 的 Call,是執行網絡請求的是一個頂層接口,需要看源碼,具體實現類實際是一個 OkHttpCall,下面會具體說
  • Callback:請求結果回調

接下來重點來了,進行源碼分析。

4.源碼分析

分析的入口是我們代碼例子中的repos.enqueue(object : Callback<List<Repo>?> {…})方法

點進去,看到是 Call 的enqueue方法

public interface Call<T> extends Cloneable {

  void enqueue(Callback<T> callback);

}
復制代碼

這是一個接口,是我們 GitHubApiService 接口中定義的 listRepos 方法中返回的 Call 對象,現在就要看GitHubApiService 的初始化,以及具體返回的是 Call 對象是誰。

然后重點就要看 retrofit.create(GitHubApiService::class.java) 方法,來看下 GitHubApiService 具體是怎么創建的,以及 Call 對象的實現類

5.Retrofit 的 create 方法

//Retrofit.java
public <T> T create(final Class<T> service) {
  //1
  validateServiceInterface(service);
  //2
  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);
            }
          });
}
復制代碼

注釋 1:這個方法,就是驗證我們定義的 GitHubApiService 是一個接口,且不是泛型接口,并且會判斷是否進行方法的提前驗證,為了更好的把錯誤暴露的編譯期,這個不是我們的重點內容,具體代碼就不看了。

注釋 2 :是一個動態代理的方法,來返回 GitHubApiService 的實例

動態代理?嗯?什么是動態代理,接下來,我就寫一個具體的例子來展示一個動態代理的具體用法,以及什么是動態代理?

先插播一段動態代理代碼,這個是理解 Retrofit 的工作機制所必須的。

6.動態代理的示例

6.1.寫一個動態代理的 Demo

下面是一個 Java 項目,模擬一個 Retrofit 的請求過程

//模擬 Retrofit,定義 API 請求接口
public interface GitHubApiService {
    void listRepos(String user);
}
復制代碼
public class ProxyDemo {
    //程序的入口方法
    public static void main(String[] args) {
        //通過動態代理獲取 ApiService 的對象
        GitHubApiService apiService = (GitHubApiService) Proxy.newProxyInstance(
                GitHubApiService.class.getClassLoader(),
                new Class[]{GitHubApiService.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("method = " + method.getName() + "   args = " + Arrays.toString(args));

                        return null;
                    }
                });

        System.out.println(apiService.getClass());
        //調用 listRepos 方法
        apiService.listRepos("octcat");
    }

}
復制代碼

執行 main 方法

當我們調用 apiService.listRepos("octcat");方法時,打印出來如下結果

class com.sun.proxy.$Proxy0
method = listRepos   args = [octcat]
復制代碼

可以看到當我們調用listRepos方法的時候,InvocationHandler 的 invoke方法中攔截到了我們的方法,參數等信息。Retrofit 的原理其實就是這樣,攔截到方法、參數,再根據我們在方法上的注解,去拼接為一個正常的OkHttp 請求,然后執行。

日志的第一行,在運行時這個類一個$Proxy0的類。實際上,在運行期 GitHubApiService 的接口會動態的創建出實現類也就是這個 $Proxy0類,它大概長下面這個樣子。

我做了一個點改動,方便查看,本質上都是一樣的

class $Proxy0 extends Proxy implements GitHubApiService {

    protected $Proxy0(InvocationHandler h) {
        super(h);
    }

    @Override
    public void listRepos(String user) {

        Method method = Class.forName("GitHubApiService").getMethod("listRepos", String.class);

        super.h.invoke(this, method, new Object[]{user});
    }
}
復制代碼

我們在調用listRepos方法的時候,實際上調用的是 InvocationHandler 的 invoke 方法。

6.2總結

  • 在 ProxyDemo 代碼運行中,會動態創建 GitHubApiService 接口的實現類,作為代理對象,執行InvocationHandler 的 invoke 方法。
  • 動態指的是在運行期,而代理指的是實現了GitHubApiService 接口的具體類,實現了接口的方法,稱之為代理
  • 本質上是在運行期,生成了 GitHubApiService 接口的實現類,調用了 InvocationHandler 的 invoke方法。

現在解決了第一個疑問:什么是動態代理

好的,動態代理已經知道是啥了,回到我們 retrofit.create(GitHubApiService::class.java)方法

7.再看 Retrofit 的 create 方法

//Retrofit.java
public <T> T create(final Class<T> service) {
  validateServiceInterface(service);
  return (T)
      Proxy.newProxyInstance(
          service.getClassLoader(),//1
          new Class<?>[] {service},//2
          new InvocationHandler() {//3
            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.
              //4
              if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
              }
              args = args != null ? args : emptyArgs;
              //5
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}
復制代碼

注釋 1:獲取一個 ClassLoader 對象

注釋 2:GitHubApiService 的字節碼對象傳到數組中去,也即是我們要代理的具體接口。

注釋 3:InvocationHandler 的 invoke 是關鍵,從上面動態代理的 Demo 中,我們知道,在GitHubApiService聲明的 listRepos方法在調用時,會執行 InvocationHandler 的invoke的方法體。

注釋 4:因為有代理類的生成,默認繼承 Object 類,所以如果是 Object.class 走,默認調用它的方法

注釋 5:如果是默認方法(比如 Java8 ),就執行 platform 的默認方法。否則執行loadServiceMethod方法的invoke方法

loadServiceMethod(method).invoke(args);這個方法是我們這個 Retrofit 最關鍵的代碼,也是分析的重點入口

7.1.先看loadServiceMethod方法

我們先看loadServiceMethod方法返回的是什么對象,然后再看這個對象的 invoke 方法

//Retrofit.java
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

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

  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
      //2
      result = ServiceMethod.parseAnnotations(this, method);
      //3
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}
復制代碼

注釋 1:從 ConcurrentHashMap 中取一個 ServiceMethod 如果存在直接返回

注釋 2:通過 ServiceMethod.parseAnnotations(this, method);方法創建一個 ServiceMethod 對象

注釋 3:用 Map 把創建的 ServiceMethod 對象緩存起來,因為我們的請求方法可能會調用多次,緩存提升性能。

看一下 ServiceMethod.parseAnnotations(this, method);方法具體返回的對象是什么,然后再看它的 invoke 方法

7.2.ServiceMethod的parseAnnotations方法

這個方法接下來還會看,這里我們只看現在需要的部分。

//ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  ...
  //1
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
復制代碼

返回的是一個HttpServiceMethod對象,那么接下來看下它的 invoke 方法

7.3.HttpServiceMethod 的 invoke 方法

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

注釋 1:創建了一個Call對象,是 OkHttpCall,這個不就是在 GitHubApiService 這個接口聲明的 Call 對象嗎?

然后再看 OkHttpCall 的enqueue方法,不就知道是怎么進行請求,怎么回調的了嗎?

注釋 2:是一個 adapt 方法,在不使用 Kotlin 協程的情況下,其實調用的是子類 CallAdapted 的 adapt,這個會在下面具體分析,包括 Kotlin 協程的 suspend 函數

現在我們已經知道了 GitHubApiService 接口中定義的 listRepos中的 Call 對象,是 OkHttpCall,接下里看OkHttpCall 的 enqueue 方法

8.OkHttpCall的enqueue方法

這段代碼比較長,但這個就是這個請求的關鍵,以及怎么使用 OkHttp 進行請求的,如果解析 Response 的,如何回調的。

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

  //1
  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 {
        //2
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

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

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

  //3
  call.enqueue(
      new okhttp3.Callback() {
        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
          Response<T> response;
          try {
            //4
            response = parseResponse(rawResponse);
          } catch (Throwable e) {
            throwIfFatal(e);
            callFailure(e);
            return;
          }

          try {
            //5
            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 {
            //6
            callback.onFailure(OkHttpCall.this, e);
          } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }
      });
}
復制代碼

注釋 1:聲明一個 okhttp3.Call 對象,用來進行網絡請求

注釋 2:給 okhttp3.Call 對象進行賦值,下面會具體看代碼,如何創建了一個 okhttp3.Call 對象

注釋 3:調用 okhttp3.Call 的 enqueue 方法,進行真正的網絡請求

注釋 4:解析響應,下面會具體看代碼

注釋 5:成功的回調

注釋 6:失敗的回調

到現在,我們文章開頭兩個疑問得到解釋了

整個請求的流程是怎樣的?

底層是如何用 OkHttp 請求的?

我們還要看下一個 okhttp3.Call 對象是怎么創建的,我們寫的注解參數是怎么解析的,響應結果是如何解析的,也就是我們在 Retrofit 中配置 addConverterFactory(GsonConverterFactory.create())是如何直接拿到數據模型的。

8.1.okhttp3.Call 對象是怎么創建的

看下 call = rawCall = createRawCall();方法

//OkHttpCall.java
private final okhttp3.Call.Factory callFactory;

private okhttp3.Call createRawCall() throws IOException {
  //1 callFactory是什么
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}
復制代碼

通過 callFactory 創建的(callFactory應該是 OkHttpClient),看一下 callFactory 的賦值過程

//OkHttpCall.java
OkHttpCall(
    RequestFactory requestFactory,
    Object[] args,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, T> responseConverter) {
  this.requestFactory = requestFactory;
  this.args = args;
  //通過 OkHttpCall 構造直接賦值
  this.callFactory = callFactory;
  this.responseConverter = responseConverter;
}
復制代碼

在 OkHttpCall 構造中直接賦值,那接下來就繼續看 OkHttpCall 的初始化過程

//HttpServiceMethod.java
private final okhttp3.Call.Factory callFactory;

@Override
final @Nullable ReturnT invoke(Object[] args) {
  //在 OkHttpCall 實例化時賦值, callFactory 是 HttpServiceMethod 的成員變量
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

//callFactory 是在 HttpServiceMethod 的構造中賦值的
HttpServiceMethod(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter) {
  this.requestFactory = requestFactory;
    //通過 HttpServiceMethod 構造直接賦值
  this.callFactory = callFactory;
  this.responseConverter = responseConverter;
}
復制代碼

發現 callFactory 的值是在創建 HttpServiceMethod 時賦值的,繼續跟!

在 7.2 小節,有一行代碼HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);我們沒有跟進去,現在看一下 HttpServiceMethod 是怎么創建的

//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
  boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
  boolean continuationWantsResponse = false;
  boolean continuationBodyNullable = false;

    //1
  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
    //2
    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);
  }
}
復制代碼

注釋 1:callFactory 的值是從 Retrofit 這個對象拿到的

注釋 2:如果不是 Kotlin 的掛起函數,返回是的 CallAdapted 對象

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {}
復制代碼

CallAdapted 是 HttpServiceMethod 的子類,會調用 adapt方法進行 CallAdapter 的轉換,我們后面會詳細看。

繼續看 Retrofit 的 callFactory 的值Retrofit是通過Builder構建的,看下Builder類

//Retrofit.java
public static final class Builder {
    public Retrofit build() {

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        //1
        callFactory = new OkHttpClient();
      }

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

}
復制代碼

原來 callFactory 實際是一個 OkHttpClient 對象,也就是 OkHttpClient 創建了一個 Call 對象,嗯就是 OKHttp 網絡請求的那一套。

在創建okhttp3.Call 對象的 callFactory.newCall(requestFactory.create(args));方法中的 requestFactory.create(args)方法會返回一個 Request 的對象,這個我們也會在下面看是如何構造一個 OkHttp 的 Request 請求對象的。

8.2.請求注解參數是怎么解析的

ServiceMethod.parseAnnotations(this, method);方法

//ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  //1
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    ...
  //2
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
復制代碼

注釋 1:通過 RequestFactory 解析注解,然后返回 RequestFactory 對象

注釋 2:把 RequestFactory 對象往 HttpServiceMethod 里面傳遞,下面會具體看 RequestFactory 對象具體干什么用了?

繼續跟代碼RequestFactory.parseAnnotations

//RequestFactory.java
final class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    //看build方法
    return new Builder(retrofit, method).build();
  }

  //build方法
  RequestFactory build() {
    //1
    for (Annotation annotation : methodAnnotations) {
      parseMethodAnnotation(annotation);
    }

   ....

    return new RequestFactory(this);
  }
}
復制代碼

遍歷 GitHubApiService 這個 API 接口上定義的方法注解,然后解析注解

繼續跟代碼parseMethodAnnotation

//RequestFactory.java
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 POST) {
    parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
  }
    ....
  else if (annotation instanceof Multipart) {
    if (isFormEncoded) {
      throw methodError(method, "Only one encoding annotation is allowed.");
    }
    isMultipart = true;
  } else if (annotation instanceof FormUrlEncoded) {
    if (isMultipart) {
      throw methodError(method, "Only one encoding annotation is allowed.");
    }
    isFormEncoded = true;
  }
}
復制代碼

就是解析方法上的注解,來存到 RequestFactory 的內部。

其實 RequestFactory 這個類還有 parseParameterparseParameterAnnotation這個就是解析方法參數聲明上的具體參數的注解,會在后面分析 Kotlin suspend 掛起函數具體講。

總之:具體代碼就是分析方法上注解上面的值,方法參數上,這個就是細節問題了

總結就是:分析方法上的各個注解,方法參數上的注解,最后返回 RequestFactory 對象,給下面使用。

Retrofit 的大框架簡單,細節比較復雜。

RequestFactory 對象返回出去,具體干嘛用了?大膽猜一下,解析出注解存到 RequestFactory 對象,這個對象身上可有各種請求的參數,然后肯定是類創建 OkHttp 的 Request請求對象啊,因為是用 OkHttp 請求的,它需要一個 Request 請求對象

8.3.RequestFactory 對象返回出去,具體干嘛用了?

下面我就用一個代碼塊貼了,看著更直接,我會具體表明屬于哪個類的

//ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  //解析注解參數,獲取 RequestFactory 對象
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
  //把 RequestFactory 對象傳給 HttpServiceMethod
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

//注意換類了
//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {

    ...

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  //不是 Kotlin 的掛起函數
  if (!isKotlinSuspendFunction) {
    //把requestFactory傳給 CallAdapted
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } 
  ....
}

//HttpServiceMethod.java
//CallAdapted 是 HttpServiceMethod 的內部類也是 HttpServiceMethod 的子類
CallAdapted(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter,
    CallAdapter<ResponseT, ReturnT> callAdapter) {
  //這里把 requestFactory 傳給 super 父類的構造參數里了,也就是 HttpServiceMethod
  super(requestFactory, callFactory, responseConverter);
  this.callAdapter = callAdapter;
}

//HttpServiceMethod.java
HttpServiceMethod(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter) {
  // HttpServiceMethod 的 requestFactory 成員變量保存這個 RequestFactory 對象
  this.requestFactory = requestFactory;
  this.callFactory = callFactory;
  this.responseConverter = responseConverter;
}

//因為會調用  HttpServiceMethod 的 invoke 方法
//會把這個 RequestFactory 對象會繼續傳遞給 OkHttpCall 類中
//注意換類了
//OkHttpCall.java
OkHttpCall(
    RequestFactory requestFactory,
    Object[] args,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, T> responseConverter) {
  //給 OkHttpCall 的requestFactory成員變量賦值
  this.requestFactory = requestFactory;
  this.args = args;
  this.callFactory = callFactory;
  this.responseConverter = responseConverter;
}

復制代碼

經過層層傳遞 RequestFactory 這個實例終于是到了 HttpServiceMethod 類中,最終傳到了 OkHttpCall 中,那這個 RequestFactory 對象在什么時候使用呢? RequestFactory 會繼續在OkHttpCall中傳遞,因為 OkHttpCall 才是進行請求的。

在OkHttpCall的 創建 Call 對象時

//OkHttpCall.java
private okhttp3.Call createRawCall() throws IOException {
  //1
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}
復制代碼

注釋 1:調用了requestFactory.create(args)

注意:此時的RequestFactory的各個成員變量在解析注解那一步都賦值了

//RequestFactory.java
okhttp3.Request create(Object[] args) throws IOException {
  ...
  RequestBuilder requestBuilder =
      new RequestBuilder(
          httpMethod,
          baseUrl,
          relativeUrl,
          headers,
          contentType,
          hasBody,
          isFormEncoded,
          isMultipart);
  ...
  return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
復制代碼

最終 requestFactory 的值用來構造 okhttp3.Request 的對象

以上就是解析注解,構造出okhttp3.Request的對象全過程了。

也就解答了方法上的注解是什么時候解析的,怎么解析的?這個問題

8.4.請求響應結果是如何解析的

比如我們在構造 Retrofit 的時候加上 addConverterFactory(GsonConverterFactory.create())這行代碼,我們的響應結果是如何通過 Gson 直接解析成數據模型的?

在 OkHttpCall 的enqueue方法中

//OkHttpCall.java
@Override
public void enqueue(final Callback<T> callback) {

  okhttp3.Call call;
    ...
  call.enqueue(
      new okhttp3.Callback() {
        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
          Response<T> response;
          try {
            //1 解析響應
            response = parseResponse(rawResponse);
          } catch (Throwable e) {
            throwIfFatal(e);
            callFailure(e);
            return;
          }
        }
    ...
      });
}
復制代碼

注釋 1:通過parseResponse解析響應返回給回調接口

//OkHttpCall.java
private final Converter<ResponseBody, T> responseConverter;

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

    ...

  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
  try {
    //1 通過 responseConverter 轉換 ResponseBody
    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;
  }
}
復制代碼

注釋 1:通過 responseConverter 調用convert方法

首先那看 responseConverter 是什么以及賦值的過程,然后再看convert方法

//OkHttpCall.java
private final Converter<ResponseBody, T> responseConverter;

OkHttpCall(
    RequestFactory requestFactory,
    Object[] args,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, T> responseConverter) {
  this.requestFactory = requestFactory;
  this.args = args;
  this.callFactory = callFactory;
  //在構造中賦值
  this.responseConverter = responseConverter;
}

// OkHttpCall 在 HttpServiceMethod 類中實例化
//注意換類了
//HttpServiceMethod.java
private final Converter<ResponseBody, ResponseT> responseConverter;

HttpServiceMethod(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter) {
  this.requestFactory = requestFactory;
  this.callFactory = callFactory;
   //在構造中賦值
  this.responseConverter = responseConverter;
}

//HttpServiceMethod 在子類 CallAdapted 調用 super方法賦值
CallAdapted(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter,
    CallAdapter<ResponseT, ReturnT> callAdapter) {
  //在CallAdapted中調用super賦值
  super(requestFactory, callFactory, responseConverter);
  this.callAdapter = callAdapter;
}

復制代碼

繼續看 CallAdapted 的初始化中 responseConverter 的賦值過程

//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
   ...
  CallAdapter<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);

  //1 實例化responseConverter
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
    //2 CallAdapted的實例化賦值
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } 
  ...
}
復制代碼

繼續跟代碼 createResponseConverter方法

//HttpServiceMethod.java
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
    Retrofit retrofit, Method method, Type responseType) {
  Annotation[] annotations = method.getAnnotations();
  try {
    //調用的是 retrofit的方法
    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);
  }
}
//注意換類了
//Retrofit.java
final List<Converter.Factory> converterFactories;

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

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    ...
  //1 從 converterFactories工廠中遍歷取出
  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;
    }
  }
  ...
}

復制代碼

注釋 1:從 converterFactories 遍歷取出一個來調用 responseBodyConverter 方法,注意根據 responseType 返回值類型來取到對應的 Converter,如果不為空,直接返回此 Converter 對象

看一下 converterFactories 這個對象的賦值過程

//Retrofit.java
final List<Converter.Factory> converterFactories;

Retrofit(
    okhttp3.Call.Factory callFactory,
    HttpUrl baseUrl,
    List<Converter.Factory> converterFactories,
    List<CallAdapter.Factory> callAdapterFactories,
    @Nullable Executor callbackExecutor,
    boolean validateEagerly) {
  this.callFactory = callFactory;
  this.baseUrl = baseUrl;
  this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
  //通過 Retrofit 的構造賦值,Retrofit的 初始化是通過內部 Builder 類的build方法
  this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
  this.callbackExecutor = callbackExecutor;
  this.validateEagerly = validateEagerly;
}

//Retrofit.java 內部類 Builder 類的build方法
//Builder.java
 public Retrofit build() {

   ...
      // Make a defensive copy of the converters.
     //1
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
        //2
      converterFactories.add(new BuiltInConverters());
        //3
      converterFactories.addAll(this.converterFactories);
        //4
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }
復制代碼

注釋 1:初始化 converterFactories 這個 list

注釋 2:添加默認的構建的轉換器,其實是 StreamingResponseBodyConverter 和 BufferingResponseBodyConverter

注釋 3:就是自己添加的轉換配置 addConverterFactory(GsonConverterFactory.create())

//Retrofit.java 內部類 Builder.java
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
  return this;
}
復制代碼

注釋 4:如果是 Java8 就是一個 OptionalConverterFactory 的轉換器否則就是一個空的

注意:是怎么找到GsonConverterFactory來調用 Gson 的 convert方法的呢?在遍歷converterFactories時會根據 responseType來找到對應的轉換器。

具體 GsonConverterFactory 的 convert 方法就是 Gson 的邏輯了,就不是 Retrofit 的重點了。

到現在Converter 的轉換過程,我們也就清楚了。

還有一個問題,我們寫的 API 接口是如何支持 RxJava 的

9.CallAdapter的替換過程

9.1.使用 RxJava 進行網絡請求

怎么轉成 RxJava

比如:我們在初始化一個Retrofit時加入 addCallAdapterFactory(RxJava2CallAdapterFactory.create())這行

//初始化一個Retrofit對象
val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    //加入 RxJava2CallAdapterFactory 支持
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build()
復制代碼

加入 RxJava2 的配置支持后,把 RxJava2CallAdapterFactory 存到 callAdapterFactories 這個集合中,記住這一點,下面要用到。

interface GitHubApiService {
    @GET("users/{user}/repos")
    fun listReposRx(@Path("user") user: String?): Single<Repo>
}
復制代碼

我們就可以這么請求接口了

//創建出GitHubApiService對象
val service = retrofit.create(GitHubApiService::class.java)
service.listReposRx("octocat")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ repo ->
        "response name = ${repo[0].name}".logE()
    }, { error ->
        error.printStackTrace()
    })
復制代碼

我們可以在自己定義的 API 接口中直接返回一個 RxJava 的 Single 對象的,來進行操作了。

我們下面就來看下是如何把請求對象轉換成一個 Single 對象的

//Retrofit.java 內部類 Builder.java
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
  callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
  return this;
}
復制代碼

把 RxJava2CallAdapterFactory 存到了callAdapterFactories 這個 list 中了。

接下來我們看下是如何使用 callAdapterFactories 的 RxJava2CallAdapterFactory 中的這個 CallAdapter 的吧

這就要看我們之前看到了一個類了 HttpServiceMethod 的parseAnnotations之前看過它的代碼,只是上次看的是Converter是如何賦值的也就是第 8.4 小節,這次看 CallAdapter 是如何被賦值使用的。

9.2CallAdapter是如何被賦值過程

HttpServiceMethod的parseAnnotations方法

//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {

  ....
  //1
  CallAdapter<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
    //2
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } 
    ...
}
復制代碼

注釋 1:初始化 CallAdapter

注釋 2:給 CallAdapted 中的 callAdapter 變量賦值,然后調用它的adapt 方法。

我們先找到具體 CallAdapter 賦值的對象,然后看它的adapt就知道了,是如何轉換的了

接下來就是跟代碼的過程了

//HttpServiceMethod.java
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
    Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
  try {
    //noinspection unchecked
    //調用retrofit的callAdapter方法
    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);
  }
}

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

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

  ...

  //遍歷 callAdapterFactories
  int start = callAdapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    //是具體CallAdapterFactory的 get 方法
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }
  ...
}

復制代碼

遍歷 callAdapterFactories 根據 returnType類型 來找到對應的 CallAdapter 返回

比如:我們在 GitHubApiService 的 returnType 類型為 Single,那么返回的就是 RxJava2CallAdapterFactory 所獲取的 CallAdapter

interface GitHubApiService {
    @GET("users/{user}/repos")
    fun listReposRx(@Path("user") user: String?): Single<Repo>
}
復制代碼

RxJava2CallAdapterFactory的 get方法

//RxJava2CallAdapterFactory.java
@Override public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  Class<?> rawType = getRawType(returnType);

  if (rawType == Completable.class) {
    return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
        false, true);
  }

  boolean isFlowable = rawType == Flowable.class;
  //當前是Single類型
  boolean isSingle = rawType == Single.class;
  boolean isMaybe = rawType == Maybe.class;
  if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
    return null;
  }
  ...
    //返回 RxJava2CallAdapter對象,isSingle參數為 true
  return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
      isSingle, isMaybe, false);
}
復制代碼

返回的是 RxJava2CallAdapter 對象,并且根據 rawType 判斷當前是個什么類型

看下 RxJava2CallAdapter 的adapt方法

//RxJava2CallAdapter.java
@Override public Object adapt(Call<R> call) {
  //1 把Call包裝成一個Observable對象
  Observable<Response<R>> responseObservable = isAsync
      ? new CallEnqueueObservable<>(call)
      : new CallExecuteObservable<>(call);

  Observable<?> observable;
  if (isResult) {
    observable = new ResultObservable<>(responseObservable);
  } else if (isBody) {
    observable = new BodyObservable<>(responseObservable);
  } else {
    observable = responseObservable;
  }

  if (scheduler != null) {
    observable = observable.subscribeOn(scheduler);
  }

  if (isFlowable) {
    return observable.toFlowable(BackpressureStrategy.LATEST);
  }
  //2
  if (isSingle) {
    return observable.singleOrError();
  }
  if (isMaybe) {
    return observable.singleElement();
  }
  if (isCompletable) {
    return observable.ignoreElements();
  }
  return RxJavaPlugins.onAssembly(observable);
}
復制代碼

注釋 1:把 Call 包裝成一個 Observable 對象

注釋2:如果是 Single 則調用observable.singleOrError();方法

到目前為止,CallAdapter 怎么變成一個 RxJava2CallAdapter 以及它的具體調用,我們也就清楚了。

10.Retrofit 如何支持 Kotlin 協程的 suspend 掛起函數的?

整個流程中還有一點我們沒有分析 Retrofit 如何支持 Kotlin 協程的 suspend 掛起函數的?

首先寫一個 Demo 來看一下協程是怎么進行網絡請求的

10.1.Kotlin 協程請求網絡的 Demo

添加依賴

def kotlin_coroutines = '1.3.7'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines"

implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
復制代碼

定義請求接口,寫一個掛起函數

interface GitHubApiService {
    //使用 Kotlin 協程 ,定義一個掛起函數
    @GET("users/{user}/repos")
    suspend fun listReposKt(@Path("user") user: String?): List<Repo>
}
復制代碼

請求接口

//創建出GitHubApiService對象
val service = retrofit.create(GitHubApiService::class.java)
//lifecycle提供的協程的Scope,因為 suspend 函數需要運行在協程里面
lifecycleScope.launchWhenResumed {
    try {
        val repo = service.listReposKt("octocat")
        "response name = ${repo[0].name}".logE()
    } catch (e: Exception) {
        e.printStackTrace()
        //出錯邏輯
        //ignore
    }
}
復制代碼

以上就是一個,用 Kotlin 協程進行網絡請求的,Retrofit 是支持 Kotlin 協程的,接下來看下,Retrofit 是怎么支持的。

10.2.分析Kotlin 協程的掛起函數的準備工作

首先在開始之前,我們得先得從代碼角度知道,Kotlin 的 suspend 函數對應的 Java 類是什么樣子,不然,就一個 suspend 關鍵字根本就沒法進行分析。

我寫一個 suspend 的測試方法,然后轉換成 java 方法看一下,這個 suspend 函數是個啥。

寫一個 Top Level 的Suspend.kt文件(在文章最后我會給出源碼,一看就明白)

在文件中寫了一個測試的 suspend 函數

suspend fun test(name: String) {

}
復制代碼

我們通過 Android Studio 再帶的工具,如下圖:把 Kotlin 方法轉成 Java 方法

點這個按鈕


結果如下

public final class SuspendKt {
   @Nullable
   public static final Object test(@NotNull String name, @NotNull Continuation $completion) {
      return Unit.INSTANCE;
   }
}
復制代碼

看到了,我們的 suspend 的關鍵字,變成了 test 方法的一個Continuation參數,且為最后一個參數

看一下這個Continuation類記住這個類,下面在分析的時候會遇到

@SinceKotlin("1.3")
public interface Continuation<in T> {
    public val context: CoroutineContext
    public fun resumeWith(result: Result<T>)
}
復制代碼

好目前的準備工作都已經完成,開始分析 Retrofit 是怎么支持 Kotlin 協程的掛起函數的。

10.3.Retrofit 是怎么支持 Kotlin 協程的掛起函數的。

經過前面的源碼解讀,我們知道,最終會調用到 HttpServiceMethod 的 parseAnnotations 方法

10.3.1.我們再看下這個方法,這次只看有關協程的部分
//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
    //1 獲取 isKotlinSuspendFunction 的值,這個會在下面具體分析
  boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
  boolean continuationWantsResponse = false;
  boolean continuationBodyNullable = false;

  Annotation[] annotations = method.getAnnotations();
  Type adapterType;
  //2 如果是 Kotlin 掛起函數
  if (isKotlinSuspendFunction) {
    Type[] parameterTypes = method.getGenericParameterTypes();
    Type responseType =
        Utils.getParameterLowerBound(
            0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
    if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {

      responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
      //3 continuationWantsResponse 賦值為 true
      continuationWantsResponse = true;
    } else {

    }

    adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
    annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
  } else {
    adapterType = method.getGenericReturnType();
  }

  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

  } else if (continuationWantsResponse) {
    //4 返回 SuspendForResponse 它是 HttpServiceMethod的子類
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForResponse<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
  } else {

    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForBody<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
            continuationBodyNullable);
  }
}
復制代碼

注釋 1:獲取 isKotlinSuspendFunction 的值,這個會在下面具體分析

注釋 2:如果是 Kotlin 掛起函數,進入此代碼塊

注釋 3:把 continuationWantsResponse 賦值為 true

注釋 4:返回 SuspendForResponse 它是 HttpServiceMethod 的子類,然后看它的 adapt方法,這個會在下面具體分析

獲取 isKotlinSuspendFunction 的值的過程

10.3.2.看 requestFactory 的 isKotlinSuspendFunction 賦值

requestFactory 這個類,我們之前分析過,就是解析注解的,但是有一部分沒看,就是解析方法參數上的注解,這次就看下。

//RequestFactory.java
private @Nullable ParameterHandler<?> parseParameter(
    int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
  ParameterHandler<?> result = null;
  if (annotations != null) {
    for (Annotation annotation : annotations) {
      ParameterHandler<?> annotationAction =
        //1 遍歷解析參數的注解,就是 @Path @Query @Field 等注解,具體就不看了,不是協程的重點
          parseParameterAnnotation(p, parameterType, annotations, annotation);

      if (annotationAction == null) {
        continue;
      }

      if (result != null) {
        throw parameterError(
            method, p, "Multiple Retrofit annotations found, only one allowed.");
      }

      result = annotationAction;
    }
  }

  if (result == null) {
    //2 如果是協程 ,其實比的就是最后一個值
    if (allowContinuation) {
      try {
        //3 判斷參數類型是 Continuation,這個接口,前面在 10.2 小節寫 Demo 時提過
        if (Utils.getRawType(parameterType) == Continuation.class) {
          // 4 isKotlinSuspendFunction 賦值為 true
          isKotlinSuspendFunction = true;
          return null;
        }
      } catch (NoClassDefFoundError ignored) {
      }
    }
    throw parameterError(method, p, "No Retrofit annotation found.");
  }

  return result;
}
復制代碼

注釋 1:遍歷解析參數的注解,就是 @Path @Query @Field 等注解,具體就不看了,不是協程的重點

注釋 2:如果是協程 ,其實比的就是最后一個值

注釋 3:判斷參數類型是 Continuation,這個接口,前面在 10.2 小節寫 Demo 時提過

注釋 4:isKotlinSuspendFunction 賦值為 true

如果isKotlinSuspendFunction 為 true 時,返回就是 SuspendForResponse 類

接下來就要 SuspendForResponse 以及它的 adapt 方法了

10.3.3.看一下SuspendForResponse類
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
  private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;

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

  @Override
  protected Object adapt(Call<ResponseT> call, Object[] args) {
    //1
    call = callAdapter.adapt(call);

    //noinspection unchecked Checked by reflection inside RequestFactory.
    //2
    Continuation<Response<ResponseT>> continuation =
        (Continuation<Response<ResponseT>>) args[args.length - 1];

    // See SuspendForBody for explanation about this try/catch.
    try {
      //3
      return KotlinExtensions.awaitResponse(call, continuation);
    } catch (Exception e) {
      //4
      return KotlinExtensions.suspendAndThrow(e, continuation);
    }
  }
}
復制代碼

注釋 1:調用 callAdapter 代理 call 方法

注釋 2:取出最后一個參數,強轉成 Continuation 類型,想想我們寫的 Demo

注釋 3:Call 的擴展函數(Kotlin 的寫法)下面具體看下 awaitResponse

注釋 4:出現異常,拋出異常。所以我們要在代碼中,要主動 try catch,來處理錯誤

10.3.4.看一下Call的擴展函數
//KotlinExtensions.kt
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
        //調用 Call的enqueue方法
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        //成功回調
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        //失敗回調
        continuation.resumeWithException(t)
      }
    })
  }
}
復制代碼

到現在,整個用 Kotlin 協程的請求過程我們也就看完了。

11.總結

至此,整個 Retrofit 的整體流程就分析完了,具體細節還需要好好研究,我們再總結一下,回答開始的問題

11.1.什么是動態代理?

分兩點動態指的是在運行期,而代理指的是實現了某個接口的具體類,稱之為代理,會調用了 InvocationHandler 的 invoke方法。

Retrofit 中的動態代理:

  • 在代碼運行中,會動態創建 GitHubApiService 接口的實現類,作為代理對象,代理接口的方法
  • 在我們調用GitHubApiService 接口的實現類的 listRepos方法時,會調用了 InvocationHandler 的 invoke方法。
  • 本質上是在運行期,生成了 GitHubApiService 接口的實現類,調用了 InvocationHandler 的 invoke方法。

具體看第 6 節

11.2.整個請求的流程是怎樣的

  • 我們在調用 GitHubApiService 接口的 listRepos方法時,會調用 InvocationHandler 的 invoke方法
  • 然后執行 loadServiceMethod方法并返回一個 HttpServiceMethod 對象并調用它的 invoke方法
  • 然后執行 OkHttpCall的 enqueue方法
  • 本質執行的是 okhttp3.Call 的 enqueue方法
  • 當然這期間會解析方法上的注解,方法的參數注解,拼成 okhttp3.Call 需要的 okhttp3.Request 對象
  • 然后通過 Converter 來解析返回的響應數據,并回調 CallBack 接口

以上就是這個Retrofit 的請求流程

11.3.底層是如何用 OkHttp 請求的?

看下第 11.2小節的解釋吧

具體看第 8 節

11.4.方法上的注解是什么時候解析的,怎么解析的?

  • 在 ServiceMethod.parseAnnotations(this, method); 方法中開始的
  • 具體內容是在 RequestFactory 類中,進行解析注解的
  • 調用 RequestFactory.parseAnnotations(retrofit, method); 方法實現的

具體看第 8.2 小節

11.5.Converter 的轉換過程,怎么通過 Gson 轉成對應的數據模型的?

  • 通過成功回調的 parseResponse(rawResponse);方法開始
  • 通過 responseConverter 的 convert 方法
  • responseConverter 是通過 converterFactories 通過遍歷,根據返回值類型來使用對應的 Converter 解析

具體看第 8.4 小節

11.6.CallAdapter 的替換過程,怎么轉成 RxJava 進行操作的?

  • 通過配置 addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 在 callAdapterFactories 這個 list 中添加 RxJava2CallAdapterFactory
  • 如果不是 Kotlin 掛起函數最終調用的是 CallAdapted 的 adapt方法
  • callAdapter 的實例是通過 callAdapterFactories 這個 list 通過遍歷,根據返回值類型來選擇合適的CallAdapter

具體看第 9 節

11.7.如何支持 Kotlin 協程的 suspend 掛起函數的?

  • 通過 RequestFactory 解析方法上的參數值來判斷是不是一個掛起函數,并把 isKotlinSuspendFunction 變量置為 true
  • 根據 isKotlinSuspendFunction 這個變量來判斷響應類型是否是 Response 類型,然后把continuationWantsResponse 置為 true
  • 根據 continuationWantsResponse 這個變量,來返回 SuspendForResponse 對象
  • 并調用 SuspendForResponse 的 invoke 方法
  • 通過 Call 的擴展函數,來調用 Call 的 enqueue方法
  • 通過協程來返回

具體看第 10 節

到此為止,這篇文章算寫完了,當然還有很多具體細節沒有研究,但對 Retrofit 的各個方面都進行了閱讀。
Android Retrofit源碼解析 ——→視頻地址

作者:AboBack
鏈接:https://juejin.cn/post/6869584323079569415
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

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

推薦閱讀更多精彩內容