Retrofit官網:https://square.github.io/retrofit/
Github地址:https://github.com/square/retrofit
前言
Retrofit是Square公司開發的一款Android網絡請求庫,Retrofit僅負責網絡請求接口的封裝,它使用運行時注解的方式提供請求參數的配置功能,底層基于OkHttp實現真正的網絡請求。
如果還不了解OkHttp框架,強烈建議先閱讀Android 網絡請求庫OkHttp基本原理與實現再來閱讀本篇文章,會更加酣暢淋漓哦~
本文所提及的網絡請求如無特殊說明,都是異步網絡請求
為什么選擇Retrofit(與其他主流框架對比)
現在市場上比較主流的網絡請求框架有:
- android-async-http(作者停止維護、不推薦使用)
- Volley(谷歌)
- OkHttp(Square)
- Retrofit(Square)
一圖讓你了解全部的網絡請求庫和他們之間的區別!
Retrofit基本用法
1. 導入庫
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類型的數據
默認情況下,Retrofit只能將數據反序列化為OkHttp的ResponseBody類型,并且它只能接受@Body注解的RequestBody類型。
除了默認情況,我們也可以添加轉換器以支持其他類型。
-
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注解分為三大類,分別是請求方法注解、標記類注解和參數類注解。
請求方法注解有8種:GET/POST/PUT/DELETE/HEAD/PATCH/OPTIONS/HTTP,前7種與HTTP請求方法是對應的,最后的HTTP可以替換前面七種,也可以擴展請求方法。
標記類注解有3種:FormUrlEncoded、Multipart、Streaming。
參數類注解有Header、Headers、Body、Path、Field、FieldMap、Query、QueryMap、Part、PartMap等。
3. GET網絡請求
首先編寫請求網絡接口
open interface ApiService {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String?): Call<List<Repo?>?>?
}
@GET
注解指定當前網絡請求方式,注解參數是訪問地址,方法返回Call<List<Repo?>?>類型的數據。@Path
注解用來動態配置Url地址,@Path("user")
對應@GET
注解中的{user}
,即使用傳入的 user: String?
值動態替換{user}
接下來創建Retrofit對象,創建接口類(動態代理)調用網絡請求方法,得到Call并發起異步請求,回調的Callback運行在UI線程。
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) //數據轉換器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) {
}
})
請求的Url是由baseUrl和@GET
注解參數拼接出來的:https://api.github.com/users/octocat/repos
一般情況下為了更準確地去查找網絡數據,我們需要在Url中添加查詢參數,這種情況可以使用Query指定查詢條件。例如根據id查找數據,我們修改代碼如下:
@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)
這樣請求Url變為:https://api.github.com/users/octocat/repos?id=132935648
如果有多個查詢參數使用@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網絡請求
POST請求最常見的情況是傳輸鍵值對的數據類型,使用@Field注解就可以為POST請求添加鍵值對
@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表明這是一個表單請求,使用@Field注解標注對應的鍵值對。
POST請求除了傳輸鍵值對,還可以傳輸JSON字符串,對應注解@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())
上傳單個文件
* @param photo 上傳的文件
* @param desc 文件描述(簡單的鍵值對)
*/
@Multipart //表示允許多個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)
上傳多個文件
與上傳單個文件類似,使用Map封裝上傳的文件,用@PartMap注解標注
更多用法可參考Carson帶你學Android:網絡請求庫Retrofit使用教程(含實例講解)
Retrofit原理解析
Retrofit最終的目的是通過使用大量的設計模式進行功能模塊的解耦,使得網絡請求過程變得更加簡單流暢。
下圖可以直觀對比出一般網絡請求流程與Retrofit請求的區別
詳細步驟如下:
- 通過解析網絡請求接口的注解配置網絡請求參數
- 通過動態代理生成網絡請求對象
- 通過網絡請求適配器將網絡請求對象進行平臺適配(平臺包括:Android、Rxjava、Guava和java8)
- 通過網絡請求執行器發送網絡請求
- 通過數據轉換器解析服務器返回的數據
- 通過回調執行器切換線程(子線程 ->>主線程)
- 用戶在主線程處理返回結果
源碼分析(基于Retrofit 2.9.0)
我們從Retrofit最基本的使用方式作為切入口,一步步深入源碼探索Retrofit實現原理。
Retrofit使用主要分為以下幾步:
- 創建Retrofit對象(建造者模式)
- 實例化接口類并調用請求方法(動態代理)
- 使用第2步返回的Call發起網絡請求,Callback回調會運行在UI線程
接下來展開分析:
1. Retrofit.Builder()
因為Retrofit可配置的參數較多,所以采用建造者模式創建Retrofit實例。
Builder類主要代碼如下:
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private @Nullable HttpUrl baseUrl; //網絡請求基本地址
private final List<Converter.Factory> converterFactories = new ArrayList<>(); //用于創建Converter.Factory
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); //用于創建CallAdapter.Factory
private @Nullable Executor callbackExecutor; //切換線程執行回調任務(默認是主線程)
private boolean validateEagerly;
//指定OkHttpClient
public Builder client(OkHttpClient client) {
return callFactory(Objects.requireNonNull(client, "client == null"));
}
//設置baseUrl
public Builder baseUrl(URL baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl.toString()));
}
/** 添加自定義的Converter Factory:用于創建數據轉換器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:用于創建網絡請求適配器CallAdapter
*/
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
//指定執行回調任務的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.");
}
//設置默認OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//android平臺默認使用MainThreadExecutor,用于切換到主線程執行任務
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//添加平臺默認CallAdapter.Factory到CallAdapterFactories
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//添加平臺默認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);
}
}
如果未配置參數,build()方法會為我們提供大多數的默認配置,例如callAdapterFactories(創建網絡請求適配器)、converterFactories(創建數據轉換器)、callbackExecutor(執行回調任務)等待。
2. retrofit.create(ApiService::class.java).listRepos("octocat")
第一步:采取動態代理的方式創建請求接口的實現類
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的成員函數,直接使用反射調用方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
//platform.isDefaultMethod(method)返回true表示方法是公共的非抽象實例方法
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args); //接口方法會執行到此處
}
});
}
ApiService.kt是一個接口類,當我們調用接口內的方法時會執行代碼: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;
}
代碼很簡單,調用ServiceMethod.parseAnnotations(this, method)
解析接口中的注解方法并封裝成ServiceMethod。并且利用serviceMethodCache緩存解析結果,這樣可以防止重復解析,使用緩存是因為解析的過程用到了比較耗費性能的反射機制。
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//注釋2.1:解析方法注解和參數注解,把注解中的網絡請求參數封裝到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:調用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默認為false,進入else語句獲取adapterType
if (isKotlinSuspendFunction) {
……
} else {
adapterType = method.getGenericReturnType();
}
//注釋2.3.1:從callAdapterFactories列表中取出CallAdapter.Factory創建CallAdapter
//我們可以使用Retrofit.Builder#addCallAdapterFactory(Factory)添加CallAdapter.Factory到列表callAdapterFactories
//CallAdapter負責執行網絡請求Call的適配工作
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
……
//注釋2.3.2:從converterFactories列表中取出Converter.Factory創建Converter
//我們可以使用Retrofit.Builder#addConverterFactory(Factory)添加Converter .Factory到converterFactories列表
//Converter負責將服務端返回的數據轉換成對象實例
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//注釋2.3.3:把requestFactory, callFactory, responseConverter, callAdapter封裝進最終的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創建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);
}
}
調用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來創建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來創建我們需要的網絡請求適配器CallAdapter,在構建Retrofit時已經添加Android平臺默認的platform.defaultCallAdapterFactories到callAdapterFactories
//Retrofit.Builder#build()
//添加默認Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
除了使用默認的CallAdapterFactory,我們也可以使用Retrofit.Builder#addCallAdapterFactory(Factory)主動添加CallAdapter.Factory到列表callAdapterFactories
CallAdapter主要負責執行網絡請求Call的適配工作,注釋2.3.2會詳細分析
注釋2.3.2:從converterFactories列表中取出Converter.Factory創建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);
}
}
調用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來創建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來創建我們需要的Converter,在構建Retrofit時已經添加Android平臺默認的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());
除了使用默認的ConverterFactory,我們也可以使用Retrofit.Builder#addConverterFactory(Factory)添加Converter .Factory到converterFactories列表;Converter負責將服務端返回的數據轉換成對象實例
注釋2.3.3:把requestFactory, callFactory, responseConverter, callAdapter封裝進最終的HttpServiceMethod
如果未使用Kotlin的Suspend功能,注釋2.3.3處會直接執行if語句,即創建一個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主要是為了實現HttpServiceMethod的抽象方法ReturnT adapt(Call<ResponseT> call, Object[] args)
,而具體工作交由callAdapter.adapt(call)方法執行。
我們再回到retrofit.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);
}
});
}
第二步:當我們調用接口ApiService中的listRepos("octocat")方法,動態代理機制會調用InvocationHandler內的invoke(Object proxy, Method method, @Nullable Object[] args)
方法,然后會執行loadServiceMethod(method).invoke(args)
。
通過前面的分析我們知道,loadServiceMethod(method)方法返回的是一個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中實現:
//HttpServiceMethod.java
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
創建一個OkHttpCall對象作為adapt(call, args)方法的參數,前面已經分析過CallAdapted中實現了adapt(call, args)方法,call最終傳遞給callAdapter.adapt(call)方法適配出新call。(適配器模式)
如果沒有手動指定callAdapter,默認使用DefaultCallAdapterFactory創建callAdapter:
//精簡后的代碼
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));
}
});
}
}
}
默認的網絡請求適配器主要做了兩件事:
- 在CallAdapter#adapt(Call<Object> call) 方法中將OkHttpCall適配成ExecutorCallbackCall來執行網絡請求(適配器模式),真正的網絡請求依然由OkHttpCall自己發起(代理模式)
- 請求完成后將Callback回調方法切換到callbackExecutor中執行,Retrofit提供的默認callbackExecutor負責將任務提交到主線程
3. OkHttpCall發起網絡請求
我們已經知道真正的網絡請求由OkHttpCall發起,那還等什么快去看看吧
@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創建okhttp3.Call
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//注釋3.2:使用創建好的okhttp3.Call發起異步請求
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse); //注釋3.3:解析服務端返回的數據
} 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創建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:使用創建好的okhttp3.Call發起異步請求
注釋3.3:處理服務端返回的數據
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) { //網絡請求出現異常
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開始轉換網絡數據
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;
}
}
執行responseConverter.convert(catchingBody)方法轉換Response數據,那么responseConverter具體類型是什么呢?
我們在初始化Retrofit時調用了Retrofit.Builder()#addConverterFactory(GsonConverterFactory.create())方法
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) //添加Gson轉換器
.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);
}
}
通過注釋2.3.2可知,我們要尋找的responseConverter就是GsonResponseBodyConverter,重新回到注釋3.3中的Response轉換過程responseConverter.convert
,本質上是執行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)方法負責把ResponseBody轉換成指定的數據類型
到此為止,還剩最后一個任務:異步請求任務完成之后會以回調的方式通知發起方請求已經結束,為了方便將請求結果展示到UI上,需要把回調操作切換到主線程執行,這個任務由ExecutorCallbackCall負責完成
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()
回調方法丟到callbackExecutor執行,可以在Retrofit中使用方法callbackExecutor(Executor executor)
配置callbackExecutor。
如果未配置callbackExecutor,Retrofit會提供默認callbackExecutor,默認配置相關的實現依然是在Retrofit.Builder#build()方法中
//Retrofit.Builder#build()
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//Android平臺
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默認是MainThreadExecutor,MainThreadExecutor負責將任務提交到主線程執行
源碼分析結束!
Retrofit源碼真是太牛逼了,本人水平有限,如有錯誤希望大家批評指正!
參考資料