1. 功能介紹
1.1 Retrofit
Retrofit 是 Github 上面 squre 組織開發的一個類型安全的 Http 客戶端,它可以在 Java 和 Android 上面使用。Retrofit 將描述請求的接口轉換為對象,然后再由該對象去請求后臺。Retrofit 將請求對象化了。目前已經發布了 2.0beta 版本。
1.2 特點
Retrofit 主要有以下功能特點
- 將 Http 請求對象化,函數化。讓接口的函數代表具體請求。
- 利用注解的方式標記參數,將 HTTP 的請求方法,請求頭,請求參數,請求體等等都用注解的方式標記,使用起來非常方便。
- 支持 Multipart,以及文件上傳(file upload)。
- 直接將 Http 的 Response 轉換成對象。用戶可以根據 Response 的具體內容,更換轉換器,或者自己新建轉化器。
- Retrofit 默認使用 OkHttp 開源庫請求后臺,用戶也可以使用自定義的具體請求方式。方便擴展。
- 自帶提供了異步處理 Http 請求的方式。
1.3 簡單 Demo
這是一個簡單的例子,訪問httpbin網站。也可以看完整的Retrofit Demo 首先聲明一個 java 接口
使用方式
使用 httpbinService 獲取一個 Call,用來請求 HTTP 服務器。
因為接口返回的應該是一個 Call,用來請求后臺 HTPP 服務器,所以我們在聲明接口的似乎,返回參數應該是 Call<?>。由于 httpbin 返回的是一個 json 格式的數據,我們想要返回直接的自定義的模型數據,但是 retrofit 默認只會返回 ResponseBody,所以我們需要自己添加一個 GsonConverter 第三方庫。在 build.graddle 中的 dependencies 添加:
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
2. 總體設計
Retrofit 可以分為注解解析(Request 生成),請求執行,請求回調(異步處理),響應體轉化幾個部分。其中請求執行與請求回調可以算作一個部分,并且請求回調也可以沒有,Call 有直接執行的接口 execute。
- 首先由解析部分(這部分也是 Request 生成部分),利用注解(Annotation)解析接口文件,將接口方法解析好,每個方法生成一個 Request。
- 然后利用 Call 部分執行 Request。Retrofit 使用的是 okHttp 來請求,程序中將 Retrofit Request 轉化為 OKHttp 開源庫的 Request,轉由 OkHttpClient 執行。
- 在 Request 執行完后,得到 Response,使用 Converter 轉化 Response 為用戶需要的對象。比如將 json 格式的數據,利用 gson 轉化為具體的 Object(也就是接口函數中的返回 Call 的模版參數的具體類型對象)
- 利用回調將第三步得到的對象,將對象傳回給 UI 線程,更新 UI。
這里面第三部與第四步是可以合在一起的,但是目前 Retrofit 提供的默認代碼中,會通過 Call,加入 Callback,用戶可以在 Callback 中處理結果。
注解(Annotation)是 Retrofit 預先定義的注解,包括 Http 的各個部分,比如 POST、GET、Query、QueryMap、Field 等等。
3. 流程圖
其中生成 Call 的部分可以看下面關于這個適配器的類圖。
4. 詳細設計
4.1 類圖
首先是整個項目的類圖對于 Retrofit 項目中 CallAdapter 用著適配器模式也挺巧的,通過適配器將 Callback 回調接口運行在 UI 線程。下面時有關 CallAdapter,Call,Callback 的類圖,其中也是連續用了兩次代理模式。
ExecutorCallback 代理的是用戶自定義的 Callback。通過這種方式讓 OkHttpCall 去執行 Call,讓 ExecutorCallback 將用戶自定義的 Callback 運行在指定線程上。
4.2 類功能詳細介紹
在 Retrofit 開源庫中,Retrofit 類是用戶最基礎的訪問入口。然后 Converter 部分是由用戶自己擴展的,而 Paraser 部分的相關類 RequestBuilder,RequestFactory 等則主要是負責解析接口并且生成 Request,而 Call,CallAdapter 等主要是負責底層的 Http 請求,以及請求后線程轉換。
4.2.1 Retrofit
Retrofit 類是包含了一個構造器 Retrofit.Builder,由 Builder 指定 Retrofit 的相關參數,創建一個新的 Retrofit。Retrofit 中包含了很多重要的成員變量,而這些成員變量都是可以自設置的。
Retrofit 包含以下成員變量:
- baseUrl: Http 請求的基礎 url,類型是 BaseUrl,包含了 url 函數返回 HttpUrl(OkHttp 的類),由 Retrofit.Builder.baseUrl 設置。
- client:OkHttp 庫的 OkHttpClient 類型。由 Builder 的 client 函數設置,默認為
OkHttpClient()
。 - methodHandlerCache:Map 類型,MethodHandler 的緩存,從接口中解析出來,放在這個 map 里面。
- converterFactories:List 類型,包含了很多 converter 的創建工廠,用戶可以通過 Builder 的 addConverterFactory 來添加。默認添加了 BuiltInConverters。
- callbackExecutor:回調函數的執行器,也就是回調函數執行的線程,Android 中默認為 MainThreadExecutor。
- adapterFactories:List 類型,包含了 CallAdapter.Factory,用戶可以通過 Builder 的 addCallAdapterFactory 來添加。Android 中默認添加了 ExecutorCallAdapterFactory。使用 callbackExecutor 作為 Executor。
- validateEagerly:這個是設置的在創建動態代理對象之前,是否提前解析接口 Method,創建 MethodHandler 并添加到 Cache 中。
Retrofit 重要方法:
- create(final Class service):T 這個是一個 public 模版方法,用戶可以通過這個方法,傳入接口 Class(T),獲得接口 Class Http 請求的動態代理對象。這是該開源庫的主入口,這個函數先驗證接口以及其方法,然后創建一個匿名 InvocationHandler,在匿名 InvocationHandler 的 invoke 中首先去掉 Object 以及 Platform 默認的方法,然后調用 loadMethodHandler 解析對應的方法(接口方法),創建 MethodHandler 加入到 methodHandlerCache 中,得到 MethodHandler,最后調用 MethodHandler 的 invoke 方法得到返回結果(接口方法的返回類型)。動態代理請見Java 動態代理
- loadMethodHandler(Method method):MethodHandler<?> 解析對應的方法(接口方法),創建 MethodHandler 加入到 methodHandlerCache 中,返回得到 MethodHandler。
- nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations):CallAdapter<?> 該方法主要是從 callAdapterFactories 中獲取新的 CallAdapter,它會跳過 skipPast,以及 skipPast 之前的 Factory,然后找到與 returnType 和 annotations 都匹配的 CallAdapterFactory。如果不匹配 CallAdapterFactory 的 get 會返回 null,所以搜索 Factories 的時候,直到搜索到返回非 null 就找到對應的了。
如果沒有找到對應的 CallAdapterFactories,得到 CallAdapter,則該方法會拋出一個 IllegalArgumentException 異常,異常里面的 message 會是"Could not locate call adapter for ",如果遇到這個異常,則去判斷對應的方法的返回類型是不是與 CallAdapterFactory 不匹配。
- requestConverter(Type type, Annotation[] annotations):Converter<T, RequestBody> 也是模版方法,該方法返回 Converter。利用 converterFactories 創建一個與 RequestBody 對應的 Converter 對象。 如果沒有找到對應的 ConverterFactory,得到 Converter,則該方法會拋出一個 IllegalArgumentException 異常,異常里面的 message 會是"Could not locate RequestBody converter for "。同樣,如果遇到這個異常,則去判斷對應的方法的返回類型是不是與 ConverterFactory 不匹配。
- responseConverter(Type type, Annotation[] annotations): Converter<ResponseBody, T> 與 requestConverter 類似,不過該方法對應的是 Response。
4.2.2 MethodHandler
MethodHandler 是 retrofit 中連接了解析部分,執行部分,轉換部分的一個關鍵的中間類。不過 MethodHandler 的代碼量很少。它可以說是連接各個部分的橋梁,也是接口方法的描述類。它有包含了 retrofit,requestFactory,callAdapter,responseConverter 成員變量。主要方法如下
- create(Retrofit retrofit, Method method):MethodHandler<?> 這是個靜態方法。MethodHandler 的創建方法,在這個方法里面通過創建 CallAdapter,responseConverter,requestFactory,最后創建 MethodHandler。
- createCallAdapter(Method method, Retrofit retrofit): CallAdapter<?> 這是個靜態方法。通過 retrofit 的 newCallAdapter 創建 CallAdapter
- createResponseConverter(Method method,Retrofit retrofit, Type responseType):Converter<ResponseBody, ?> 這是個靜態方法。通過 retrofit 的 responseConverter 方法得到 responseConverter
- invoke(Object... args):Object 通過 callAdapter 的 adapter 將 OkHttpCall 轉換成需要返回的 Call
4.2.3 Converter 與 Converter.Factory
這兩個類別都是在 Converter 文件下。Converter 是接口,Factory 抽象類,很簡短。
Factory 主要是負責生成兩種 Converter。Retrofit 實現了一個簡單的 BuiltInConverters。
4.2.4 Call
這是 Retrofit 的框架基礎接口。它是 Retrofit 的發送請求給服務器并且返回響應體的調用。每個 Call 都有自己的 HTTP 請求和相匹配的響應。 它有如下四個接口:
- execute 同步執行請求
Response<T> execute() throws IOException;
- enquene 異步執行請求,并且使用 Callback 作為請求結束后的回調。
void enqueue(Callback<T> callback);
- cancel 取消請求
void cancel();
- clone 復制請求,如果需要很多相同的 Call,可以通過 clone 復制。
Call<T> clone();
4.2.5 CallAdapter
這是 Retrofit 的框架基礎接口。CallAdapter 是將一個 Call 適配給另外一個 Call 的適配器接口。它有以下兩個接口:
- responseType 返回請求后,轉化的參數 Type 類型。
Type responseType();
- adapt 適配,將一個 Call 轉換成另外一個 Call。
<R> T adapt(Call<R> call);
4.2.6 Callback
請求結構的回調接口。在 Call 的 enquene 接口中使用 有如下兩個方法
- onResponse 返回響應體
void onResponse(Response<T> response, Retrofit retrofit);
- onFailure 請求失敗的時候,比如網絡或者一些難以預料的異常。
void onFailure(Throwable t);
4.2.7 OkHttpCall
實現了 Call 接口,但同樣是模版類。首先介紹一下 OkHttpCall 的主要函數:
- createRawCall
private com.squareup.okhttp.Call createRawCall()
根據由 requestFactory 根據 args 創建一個 Request,然后利用這個 Request 創建一個 okhttp.Call。
- parseResponse
private Response<T> parseResponse(com.squareup.okhttp.Response rawResponse) throws IOException
解析 okhttp.Response,
- 首先將 body 讀取出來作為 rawBody,然后用 OkHttpCall.NoContentResponseBody 作為新的 Body,創建新的 rawResponse。
- 判斷 Response.code(),如果不在 200 范圍內,讀取 rawBody 出來,返回一個錯誤的 retrofit 的 Response。如果 code 為 204 或 205(沒有返回內容),則返回一個 body 為空的 retrofit 的 Response。
- 如果 code 正常,則用 OkHttpCall.ExceptionCatchingRequestBody 包裝一下 rawBody, 然后使用 responseConverter 將包裝后的 catchingBody 轉化為具體的返回類型數據。
OkHttpCall 是將 Request 放入到 okhttp 的 Call 里面執行,執行完成后,又將 okhttp 的 Call 返回的 Response 轉化為 retrofit 的 Response,在此同時將 Body 里面的內容,通過 converter 轉化為對應的對象。這個 OkHttpCall
4.2.8 Response
這個類是包含了具體返回對象的響應體。里面包含了模版參數 T 類型的 body 對象,以及 okhttp 的 Response。
4.2.9 注解類
在 Retrofit 里面創建了 Body 注解,Filed 注解(Field,FieldMap),請求方法注解(DELETE,GET,PATCH,POST,PUT),請求頭注解(HEAD,Header,Headers),multipart 注解(Part,Multipart,PartMap),接口加碼(FormUrlEncoded),Url,Streaming,查詢(Query,QueryMap),參數路徑(Path),HTTP
4.2.10 RequestBuilderAction
這是一個抽象類,只有一個未實現的 perform 方法。
abstract void perform(RequestBuilder builder, Object value);
但是在 RequestBuilderAction 類里面有很多 RequestBuilderAction 的子類,分別對應注解類。Url,Header,Path,Query,QueryMap,Field,FieldMap,Part,PartMap,Body 都是在 RequestBuilderAction 的內部類,并且繼承了 RequestBuilderAction。RequestBuilder 就是將對應注解的值給 RequestBuilder。
4.2.11 RequestBuilder
這是一個 okhttp.Request 的創建類。負責設置 HTTP 請求的相關信息,創建 Request。它主要有以下方法:
- RequestBuilder
- setRelativeUrl
- addHeader
- addPathParam
- canonicalize static 方法
- canonicalize
- addQueryParam
- addFormField
- addPart
- setBody
- build
它的構造方法如下: RequestBuilder(String method, HttpUrl baseUrl, String relativeUrl, Headers headers, MediaType contentType, boolean hasBody, boolean isFormEncoded, boolean isMultipart)
RequestBuilder 就是創建請求。
4.2.12 RequestFactory
RequestFactory 是創建 Request,他有個 create 方法,
Request create(Object... args) {
參數是接口函數對應的參數值,cerate 是創建 RequestBuilder,遍歷 RequestFactory 的成員變量 requestBuilderActions,設置好 RequestBuilder,最后創建 Request 返回。
4.2.13 RequestFactoryParser
這個類主要是接口函數 Method 的每個注解。入口函數是 parse。
先解析方法注解(應用到方法上的注解),比如說 FormUrlEncoded,Headers。得到對應的值。
然后再解析方法參數注解(應用到方法參數上的注解),在解析方法參數注解的時候,會生成一個 requestBuilderActions 數組,對應到每個參數。每個 Action 都對應了每個函數參數的處理。等到具體函數調用的時候,跟函數具體的參數值對應。也就是 RequestFactory 與 Builder 的工作了,這部分是等到運行的時候才能夠確定的。
4.2.14 BuiltInConverters,OkHttpResponseBodyConverter,VoidConverter,OkHttpRequestBodyConverter
BuiltInConverters 繼承自 Converter.Factory,返回的 responseConverter 是 OkHttpResponseBodyConverter 或 VoidConverter,也就是接口方法返回的職能是 OkHttp 的 ResponseBody,或者 Void。 返回的 requestConverter 是 OkHttpRequestBodyConverter,接口方法的參數中如果使用 Body,那 Body 也只能是 OkHttp 的 RequestBody。
VoidConverter: 將 OkHttp 的 ResponseBody 轉化為 Void。 OkHttpResponseBodyConverter:將 OkHttp 的 ResponseBody 轉化為 OkHttp 的 ResponseBody。如果是 Streaming 標記的接口的話,利用 Utils.readBodyToBytesIfNecessary 緩沖整個 body。 OkHttpRequestBodyConverter:將 OkHttp 的 RequestBody 轉化為 OkHttp 的 RequestBody。
4.2.15 PlatForm.Android.MainThreadExecutor
一個 Executor,通過 android Handler 將 Runnable 執行在 UI 線程中。
4.2.16 Utils
這是 Retrofit 中的一個工具類,里面包含了很多范型的檢查、操作。另外以及一些基本的工具性的功能。下面是它里面的函數:
checkNotNull
<T> T checkNotNull(T object, String message)
檢查非空,如果是 null,則拋出 NullPointerException,內容提示為 message。closeQuietly
static void closeQuietly(Closeable closeable)
靜默地關閉 Closeable 對象。不會拋出異常isAnnotationPresent
static boolean isAnnotationPresent(Annotation[] annotations,Class<? extends Annotation> cls)
判斷 cls 是否是 annotations 里面的一個實例。如果在則返回 true。readBodyToBytesIfNecessary
static ResponseBody readBodyToBytesIfNecessary(final ResponseBody body) throws IOException
如果 body 非 null 的話,把整個 body 讀取出來(讀取到 buffer),返回再返回一個 ResponseBody。validateServiceInterface
static <T> void validateServiceInterface(Class<T> service)
驗證接口是否有效,這個接口就是用戶自定義的接口。如果不是接口,或者里面沒有任何函數,則拋出 IllegalArgumentException 異常。getSingleParameterUpperBound
public static Type getSingleParameterUpperBound(ParameterizedType type)
該函數獲取 type 的單個模版參數的上屆。如果 type 有多個類型,函數會拋出異常,如果模版參數不是 WildcardType,則直接返回模版參數類型hasUnresolvableType
public static boolean hasUnresolvableType(Type type)
判斷是否有不能分解的類型,比如有 TypeVariable,WildcardType 等getRawType
public static Class<?> getRawType(Type type)
這個方法是從 Gson 里面截取的,獲取 type 的實際類型。methodError
static RuntimeException methodError(Method method, String message, Object... args)
static RuntimeException methodError(Throwable cause, Method method, String message,Object... args)
兩個重載函數,拋出方法錯誤異常getCallResponseType
static Type getCallResponseType(Type returnType)
獲取返回 Call 的返回類型,必須是模版參數類型,并且 Call 的模版參數不能是 retrofit.Response.class。返回 getSingleParameterUpperBound(returnType)
4.3 擴展
Retrofit 是很適合擴展的,里面設計的 Call,以及 Converter 就是為了方便擴展使用。
4.3.1 Converter
Retrofit 提供的默認的 Converter 只會返回 ResponseBody,如果我們想要返回具體的 Object,我們可以使用另外的第三方包,并且在創建 Retrofit 的時候添加對應的 ConverterFactory。這里有 6 個序列化第三方庫:
- Gson: com.squareup.retrofit:converter-gson
- Jackson: com.squareup.retrofit:converter-jackson
- Moshi: com.squareup.retrofit:converter-moshi
- Protobuf: com.squareup.retrofit:converter-protobuf
- Wire: com.squareup.retrofit:converter-wire
- Simple XML: com.squareup.retrofit:converter-simplexml
4.3.2 Rxjava
retrofit 也可以與Rxjava聯合起來使用,之前的版本使用范例可以參考http://randomdotnext.com/retrofit-rxjava/
- adapter-Rxjava: com.squareup.retrofit:adapter-rxjava
正在開發中,主要是通過擴展 CallAdapter,將之前 Call,轉換為 rxjava 需要的 Observable<?>。
5 說明
這篇文章不是我寫的,本文補全了好多我之前對Retrofit的遺漏知識,所以復制粘貼下來當作筆記,如果其他同學看到,還請多看原作者的原文章:https://github.com/android-cn/android-open-project-analysis/tree/master/tool-lib/network/retrofit。