從 ServiceMethod 開始理解 retrofit

導讀:

本文將帶着你,從請求執行的角度,以 interface 中咱們定義的方法爲起始,解讀 retrofit 的執行流程。目的是想讓咱們對 retrofit 的執行流程有一個框架性的瞭解,同時也是爲了面試的時候,能夠跟面試官「有的聊」。java

ServiceMethod

retrofit的核心思想是將 http 請求過程抽象成了一個對象 ServiceMethod。 這個對象的構造的時候,會經過 java 反射的方式傳入一個 method 對象,而這個對象就是咱們在 interface 中定義的請求方法。經過對 method 對象 find usage ,咱們能夠發現,一共有兩處使用了這個 method 對象:面試

  • ServiceMethod.createCallAdapter()編程

    • getGenericReturnType()
    • getAnnotations()
  • ServiceMethod.createResponseConverter()json

    • getAnnotations()

能夠看到,裏面使用了 method 對象的兩個關鍵信息:註解和返回類型。而其中涉及的兩個方法則同時出如今了 ServiceMethod.build() 中。服務器

public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseConverter = createResponseConverter();
    }

至此,咱們已經找到了 retrofit 的精妙所在:網絡

  1. 經過 method 的 returnType 構造出 createCallAdapter 和 responseConverter,而後自動的完成從服務器的返回結果,到程序用的 model 類實例的轉換。
  2. 經過 annotation 定義網絡請求相關的參數。

annotation 的解析是一個簡單但繁瑣的工做,須要對每個註解逐個判斷。所以咱們把重點放在 callAdapter 和 responseConverter 的分析上。而我在閱讀相關代碼的過程當中,發現其中的泛型部分對咱們理解整個框架形成了很大的阻礙。所以,想理解 retrofit,必需要弄懂其各個泛型類的意義,否則看一看就本身把本身繞暈了。框架

從類型系統的角度看 retrofit

  • Service<R, T>
  • CallAdapter<R, T>
  • Tadapt(Call<R> call)
  • Response<R> parseResponse(okhttp3.Response rawResponse)

抽象的太複雜,不如咱們舉個例子。好比,咱們想從服務器請求電臺相關的數據,那麼,咱們的請求方法定義就多是下面這樣函數

@GET("/albums")
RadioCall<RadioAlbumModel> getAlbums():

其中返回類型中涉及兩個自定義的部分:RadioCall 和 RadioAlbumModel。其中,RadioAlbumModel 是咱們定義的model 類,通常用 gson 解析服務器的數據並建立實例;RadioCall extends Call,並將請求等委託給實際的 call 對象。ui

往咱們的泛型中套用一下,代理

  • T就是 RadioCall<RadioAlbumModel>
  • R就是 RadioAlbumModel
  • adapt 的做用是把 retrofit2.Call<RadioAlbumModel> 轉化爲 RadioCall<RadioAlbumModel>

繼續把上面四個泛型類具化:

  • Service<RadioAlbumModel, RadioCall<RadioAlbumModel>>
  • CallAdapter<RadioAlbumModel, RadioCall<RadioAlbumModel>>
  • RadioCall<RadioAlbumModel> adapter(Call<RadioAlbumModel> call)
  • Response<RadioAlbumModel> parseResponse(okhttp3.Response rawResponse)

這樣,請求的執行流程就呼之欲出了:

首先,調用端的調用代碼應該是這樣的:

RadioCall<RadioAlbumModel> radioCall = retrofitClient.getAlbums();
radioCall.execute()

其中,getAlbums() 就是咱們的 method 方法。根據這個 method 方法, 生成 ServiceMethod 對象,返回的結果是 serviceMethod.callAdapter.adapt(okHttpCall); 。而咱們知道,咱們在 interface 中定義的 getAlbums() 的返回類型剛好是 RadioCall<RadioAlbumModel>,兩個類型就這麼對上了。

在radioCall.execute() 的內部,咱們會把調用 delegates.execute() 來實際執行網絡請求。這個 delegates 的類型就是 retrofit.OkHttpCall。而後,發起請求,等待服務器返回結果,並對結果進行處理。注意,此時的結果仍是 rawResponse,即都是 json 字符串,還不是能夠直接使用的 java model 對象。這個時候,咱們就須要 responseConverter 來幫咱們進行轉換了。

在獲取到結果以後,咱們會調用 Response<T> retrofit2.OkHttpCall.parseResponse(okhttp3.Response rawResponse) 中,進而調用以下代碼

//------ in OkHttpCall.java
  Response<R> parseResponse(okhttp3.Response rawResponse) throws IOException {
      R body = serviceMethod.toResponse(cachingBody);
      return Response.success(body, rawResponse);
  }


//------ in ServiceMethod.java
  /** Builds a method return value from an HTTP response body. */
  R ServiceMethod.toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

正如咱們上文所說,RadioCall 通常會把一個 okHttpCall 做爲構造函數的參數,而後把實際請求委託給 okHttpCall,而後再 onResposne 回調中就能獲得上面代碼中的 Response<R>,將咱們的類帶入,就是 Response<RadioAlbumModel>。而這個,就是 execute() 的執行結果。而後咱們就能夠獲得 Response<RadioAlbumModel> 中的 model 對象了。

至此,retrofit 的請求執行流程就分析完畢。最後咱們再從宏觀的角度,從面試的角度,來闡述一下整個執行過程。

面向面試編程:

問:請簡述 retrofit 中,一個方法的執行流程。

答:

首先咱們經過咱們 create 出來的 retrofit 實例來調用接口方法。全部的 interface 方法都會在 java 動態代理機制的做用下,調用一個匿名類 new InvocationHandler 中的 invoke。在 invoke 中,會根據咱們想調用的方法 method 構造出一個 serviceMethod,而後調用 serviceMethod.callAdapter.adapt(okHttpCall) 做爲返回結果。

構造 serviceMethod 的時候,會根據 interface 中 method 的的返回類型,構造出 converter 和 callAdapter。其中, converter 通常使用 gson converter。gson converter 能夠自動將服務器返回的 json 數據轉化成 java 中的 model 類的實例。callAdapter 絕大多數的實現方式是在構造函數中接收一個 okHttpCall 實例,而後將 enqueue 和 execute 委託給這個 okHttpCall 實例來執行。okHttpCall 在獲取到服務器數據以後,會利用 serviceMethod.toResponse(body) 來對數據進行轉化。其中,轉化的時候便利用了 converter。數據轉化完成後,封裝成 Response<R> ,傳遞給調用方。其中 R 就是咱們的數據類。

補充:返回類型知識點複習

關於返回類型getGenericReturnType(),會調用到下面的方法:

Type getCallResponseType(Type return)  {
    getParameterUpperBound(0, returnType)    
}

這個方法的做用就是獲取實際類型。好比,若是一個方法以下:

List<String> get() {
    return ArrayList()
}

其返回類型是List<String>,那麼,getCallResponseType(method.genericReturnType) 獲得的結果就是 String 。其中,method.returnType 爲 java.util.List,mehod.genericReturnType 爲 java.util.List<String>。

相關文章
相關標籤/搜索