[TOC]
# Retrofit
> A type-safe HTTP client for Android and Java
開發Android App肯定會使用Http請求與服務器通信,上傳或下載數據等。目前開源的Http請求工具也有很多,比如Google開發的`Volley`,loopj的`Android Async Http`,Square開源的`OkHttp`或者`Retrofit`等。
我覺得Retrofit 無疑是這幾個當中最好用的一個,設計這個庫的思路很特別而且巧妙。Retrofit的代碼很少,花點時間讀它的源碼肯定會收獲很多。
本文的源碼分析基于Retrofit 2,和Retrofit 1.0的Api有較大的不同, 本文主要分為幾部分:`Retrofit 使用`,`Retrofit 源碼分析`
## Retroift 使用
### 官方使用簡介
> 官方使用簡介:(http://square.github.io/retrofit/)
### 引用依賴
```
// 最新版本 :2.5.0
implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
```
### 生成一個ApiService
```java
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
```
### 創建Retorfit
```java
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
```
### 發起請求
```java
Call<List<Repo>> repos = service.listRepos("octocat");
//異步請求
// 請求數據,并且處理response
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Response<List<Repo>> response) {
System.out.println(response);
}
@Override
public void onFailure(Throwable t) {
}
});
//同步請求
call.execute()
```
### ApiService 配置
#### Url配置
| 注解 | 描述 | 實例 |
| --- | --- | --- |
| @GET | get請求 | @GET("group/users") |
| @POST | post請求 | @POST("group/users") |
| @Uri | uri全連接配合 其他請求方法 | @Uri("http://xxxx/group/users") |
| @PATH | get/post 請求的動態路徑,用于方法參數注解 | @GET("group/{id}/users" ? ?Call<List<User>> groupList(@Path("id") int groupId); |
| @Headers | 請求的 HEADER 作用于方法 | @Headers("Cache-Control: max-age=640000") |
| @Header | 請求的 HEADER 作用于方法參數 | @Header("Authorization") String authorization |
| @Query & @QueryMap | 用于方法參數注解,只能配合@GET | Call<List<User>> groupList(@Path("id") int groupId,@Query("sort") String sort); |
| @Body | 用于方法參數注解 | @POST("users/new")Call<User> createUser(@Body User user); |
| @Field & @FieldMap | 用于方法參數注解,只能配合@POST | 類似@Query & @QueryMap |
| @Part & @PartMap | 用于POST文件上傳 |Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);|
### 其他高級用法
官方使用簡介:(http://square.github.io/retrofit/)
## Retrofit 源碼分析
> retrofit的最大特點就是解耦,要解耦就需要大量的設計模式,假如一點設計模式都不懂的人,可能很難看懂retrofit。
### 基本流程(組裝過程)
#### Retrofit#create
```java
ApiService service = retrofit.create(ApiService.class);
```
Retrofit是如何創建Api的,是通過`Retrofit#create()`的方法 ,通過[動態代理](https://www.cnblogs.com/gonjan-blog/p/6685611.html)方式。
關于動態代理 這里就不多講了,樓下有動態代理鏈接,至于為什么用動態代理,大家想一想???
```java
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//DefaultMethod 是 Java 8 的概念,是定義在 interface 當中的有實現的方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//每一個接口最終實例化成一個 ServiceMethod,并且會緩存
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//Retrofit 與 OkHttp 完全耦合
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//發起請求,并解析服務端返回的結果
return serviceMethod.adapt(okHttpCall);
}
});
}
```
提取在create方法中的關鍵幾行代碼 `Service Proxy`
當大家了解了動態代理之后, 都知道我們調用ApiService中的`method`都會自動調用 `InvocationHandler()`.
真真開始執行的是 `serviceMethod.adapt(okHttpCall)==> calladapter#adapt(okhttpCall);`
```java
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
```
一個 ServiceMethod 對象對應于一個 API interface 的一個方法,loadServiceMethod(method) 方法負責加載 ServiceMethod:
```java
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
```
這里實現了緩存邏輯,同一個 API 的同一個方法,只會創建一次。這里由于我們每次獲取 API 實例都是傳入的 class 對象,而 class 對象是進程內單例的,所以獲取到它的同一個方法 Method 實例也是單例的,所以這里的緩存是有效的。
`ServiceMethod`是什么呢???里面包含什么 ???
大致就是想這個方法的method轉化成 `ServiceMethod對象` 包含 各個注解(方法的注解,參數的注解,方法的返回值的東西),那我們來看下具體有什么東西
我們看看 `ServiceMethod` 的構造函數:
```java
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
```
這里用了buider 模式,這里很多參數,有的參數一看就明白 像baseUrl,headers ,contyentType等,講解主要關注四個成員:callFactory,callAdapter,responseConverter 和 parameterHandlers。
+ callFactory 負責創建 HTTP 請求,HTTP 請求被抽象為了 okhttp3.Call 類,它表示一個已經準備好,可以隨時執行的 HTTP 請求;
+ callAdapter 把 retrofit2.Call<T> 轉為 T(注意和 okhttp3.Call 區分開來,retrofit2.Call<T> 表示的是對一個 Retrofit 方法的調用),這個過程會發送一個 HTTP 請求,拿到服務器返回的數據(通過 okhttp3.Call 實現),并把數據轉換為聲明的 T 類型對象(通過 Converter<F, T> 實現);
+ responseConverter 是 Converter<ResponseBody, T> 類型,負責把服務器返回的數據(JSON、XML、二進制或者其他格式,由 ResponseBody 封裝)轉化為 T 類型的對象;
+ parameterHandlers 則負責解析 API 定義時每個方法的參數,并在構造 HTTP 請求時設置參數;
`retrofit2.ServiceMethod.Builder#build()`方法中生成了以上對象
```java
public ServiceMethod build() {
// 通過method 找到對應的retrofit2.CallAdapter
callAdapter = createCallAdapter();
//省略代碼...
// 通過method 找到對應的retrofit2.Converter
responseConverter = createResponseConverter();
//省略代碼...
for (Annotation annotation : methodAnnotations) {
//解析 請求的方法
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
//省略代碼...
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
...
//解析方法參數注解
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
//省略代碼...
return new ServiceMethod<>(this);
}
```
### CallAdapter
> retrofit2.Retrofit.Builder#addCallAdapterFactory(Factory)
默認 retrofit2.DefaultCallAdapterFactory 使用的是OkhttpCall
+ `retrofit2.ServiceMethod.Builder#createCallAdapter(...)`
+ `retrofit2.Retrofit#callAdapter(...)`
+ `retrofit2.Retrofit#nextCallAdapter(null,...)`
```java
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
// 調用retrofit2.CallAdapter.Factory#get
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//省略代碼
//throw new IllegalArgumentException(builder.toString());
}
```
上面知道如果注冊了多個`retrofit2.CallAdapter`,按照注冊的順序來執行,如果那個有返回值就會直接返回,不走for循環了
### Converter
> 通過Retrofit 添加ConverterFactory
`Retrofit.Builder#addConverterFactory(Factory)`
默認`retrofit2.BuiltInConverters`
#### ParameterHandlers or RequestConverter
+ `retrofit2.ServiceMethod.Builder#parseParameter(...)`
+ `retrofit2.ServiceMethod.Builder#parseParameterAnnotation(...)`
+ `retrofit2.Retrofit#stringConverter(...)`
+ `retrofit2.Converter.Factory#stringConverter(...)`
+ OR `retrofit2.Converter.Factory#requestBodyConverter(...)`
```java
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
//關鍵代碼
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
//省略代碼 ...
result = annotationAction;
}
//省略代碼 ...
return result;
}
private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) {
// 關鍵代碼
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
// or
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler;
}
```
【總結】: 當執行`retrofit2.Retrofit#create(final Class<T> service)`的時候就會找到對應的 `retrofit2.Converter`
#### responseConverter
+ `retrofit2.ServiceMethod.Builder#createResponseConverter(...)`
+ `retrofit2.Retrofit#responseBodyConverter(...)`
+ `retrofit2.Retrofit#nextResponseBodyConverter(null,...)`
```java
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
// 調用 retrofit2.Converter.Factory#responseBodyConverter
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
...
//省略代碼
// throw new IllegalArgumentException(...)
}
```
上面知道如果注冊了多個Converter 按照注冊的順序來執行,如果那個有返回值就會直接返回,不走for循環了
【總結】: 當執行`retrofit2.Retrofit#create(final Class<T> service)`的時候就會找到對應的 `retrofit2.Converter`
**以上都是初始化操作,將所有的請求相關的東西都封裝到`ServiceMethod`中**
### 執行過程
```java
serviceMethod.adapt(okHttpCall);
```
真正執行的開始點就是`serviceMethod.adapt` ,**ServiceMethod.class**執行過程中的 三個很重要,也是整個過程關鍵節點
```java
// 簡單粗俗的講:返回包裝okhttpCall后的對象
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
//retrofit2.OkHttpCall#createRawCall 調用
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
// 返回 okhttp.Call
}
//retrofit2.OkHttpCall 請求結果之后 會調用 responseBody convert
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
```
**通過`serviceMethod`上面三個方法,將 `OkhttpCall`,`CallAdapter` ,`Converter` 關聯起來**

為什么要用動態代理?
因為對接口的所有方法的調用都會集中轉發到 InvocationHandler#invoke函數中,我們可以集中進行處理,更方便了。你可能會想,我也可以手寫這樣的代理類,把所有接口的調用都轉發到 InvocationHandler#invoke,當然可以,但是可靠地自動生成豈不更方便,可以方便為什么不方便。
[Retrofit分析-漂亮的解耦套路](https://www.jianshu.com/p/45cb536be2f4)
[Java動態代理](http://a.codekk.com/detail/Android/Caij/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20Java%20%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86)
- 計算機基礎
- 簡答1
- 簡答2
- 專案
- 淺談0與1
- 淺談TCP_IP
- 淺談HTTP
- 淺談HTTPS
- 數據結構與算法
- 常見數據結構簡介
- 常用算法分析
- 常見排序算法
- Java數據結構類問題簡答
- 專案
- HashMap
- 淺談二叉樹
- 算法題
- 算法001_TopN問題
- 算法002_漢諾塔
- 編程思想
- 雜說
- 觀點_優秀程序設計的18大原則
- 設計模式_創建型
- 1_
- 2_
- 設計模式_結構型
- 1_
- 2_
- 設計模式_行為型
- 1_
- 2_
- Java相關
- 簡答1
- 簡答2
- 專案
- 淺談String
- 淺談Java泛型
- 淺談Java異常
- 淺談動態代理
- 淺談AOP編程
- 淺談ThreadLocal
- 淺談Volatile
- 淺談內存模型
- 淺談類加載
- 專案_數據結構
- 淺談SpareArray
- Android相關
- Android面試題
- 專案
- 推送原理解析
- Lint
- 自定義Lint
- Lint使用
- 優化案
- Apk體積優化
- Kotlin相關
- 簡答1
- 簡答2
- 三方框架相
- Okhttp3源碼分析
- ButterKnife源碼分析
- Glide4源碼分析
- Retrofit源碼分析
- RxJava源碼分析
- ARouter源碼分析
- LeakCanary源碼分析
- WMRouter源碼分析
- 跨平臺相關
- ReactNative
- Flutter
- Hybrid
- 優質源
- 資訊源
- 組件源
- 推薦