版權宣告:本文為博主原創文章,未經博主允許不得轉載
Github:github.com/Darkwh
若有錯誤或疑問歡迎小夥伴們留言評論
友情提示!!!
本人英文渣,文章中哪些單詞翻譯的不夠形象的話。。。。那你到是來打我呀O(∩_∩)O 另外本篇文章強烈建議開啟原始碼參考閱讀,否則造成強烈不適概不負責~
系列回顧
前言
上一篇為大家介紹了retrofit的使用和其中幾個比較重要的類,本篇將會順著retrofit的使用來詳細分析原始碼。本文為了節省篇幅,程式碼中都新增了中文註釋,這裡我就講一下我認為值得講解的地方,小夥伴們記得看註釋啊。那麼接下來讓我們正式開始吧!!
第一步:建立Retrofit物件
val retrofit: Retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://gank.io/api/")
.build()
複製程式碼
首先Retrofit採用建造者模式,這種模式大家應該都不陌生了,這裡就不多介紹了。
addConverterFactory和baseUrl方法均是為builder的引數成員賦值,賦值之前會有一些非空或URL格式的檢查,程式碼很簡單。讓我們直接聚焦到build方法中去:
/**
* Create the {@link Retrofit} instance using the configured values.
* <p>
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
*/
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
//如果未指定callFactory,則預設建立一個OkHttpClint來使用
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
//如果未指定callbackExecutor,則獲取預設的callbackExecutor
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//做一次深度拷貝
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//此處將預設的CallAdapter放到集合末尾
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//做一次深度拷貝
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
//此處將預設的Converter.Factory實現新增到集合首位置
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//返回Retrofit例項
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
複製程式碼
在build的時候,callFactory、callbackExecutor未做顯示指定的時候,都會採用預設的實現。而至於adapterFactories和converterFactories這兩個集合變數,則分別將內建的例項新增到末尾和首位置。
獲取預設實現的時候涉及到了Platform和BuiltInConverters這兩個類,我們來看一下這兩個類,首先來看Platform:
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
......
}
複製程式碼
看下findPlatform方法,Android平臺自然會返回Android這樣一個Platform的子類
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
複製程式碼
可以看到預設的CallbackExecutor為MainThreadExecutor,利用handler在回到主執行緒處理。預設的CallAdapterFactory為 ExecutorCallAdapterFactory
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
}
複製程式碼
ExecutorCallAdapterFactory提供一個匿名的CallAdapter實現,該匿名物件的adapt方法會返回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) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
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(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
......
@Override public Request request() {
return delegate.request();
}
}
複製程式碼
靜態代理模式,呼叫目標物件,即第一篇為大家介紹過的Call介面的內建實現OkHttpCall物件,並將通過介面將成功失敗結果回撥回來。
BuiltInConverters這個類我們放到後面去講解。
第二步:建立自定義介面的代理物件
val service: TestService = retrofit.create(TestService::class.java)
複製程式碼
create方法是整個Retrofit最精髓的一段程式碼,它的作用是通過Java的動態代理方式來返回一個你定義好的介面的動態代理物件,不明白動態代理的小夥伴們可以自行百度一下,網上有很多的講解。看一下這段程式碼:
public <T> T create(final Class<T> service) {
//檢查介面,如果目標類不是一個介面或繼承於其他的介面則丟擲異常
Utils.validateServiceInterface(service);
//是否提前將method物件轉換為ServiceMethod並快取
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//通過Java的動態代理返回代理物件
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, @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);
}
// Android平臺該if分支不會執行
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//將該方法對映為ServiceMethood
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//建立OkHttpCall物件
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//利用CallAdapter將okHttpCall轉換為指定的型別(預設為Call<Object>)
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
複製程式碼
讓我們將這段程式碼分開講解
1.檢查自定義的介面
Utils.validateServiceInterface(service);
對傳入的自定義介面進行檢查,如果該類並非一個介面或繼承於另一個介面,則丟擲異常。
2.是否提前將自定義介面中的方法都對映為ServiceMethod並快取
//是否提前將method物件轉換為ServiceMethod並快取
if (validateEagerly) {
eagerlyValidateMethods(service);
}
複製程式碼
可以通過Retrofit.Builder的validateEagerly方法來設定是否提前對映介面方法並快取
3.建立並返回動態代理物件
//通過Java的動態代理返回代理物件
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, @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);
}
// Android平臺該if分支不會執行
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//將該方法對映為ServiceMethood
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//建立OkHttpCall物件
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//利用CallAdapter將okHttpCall轉換為指定的型別(預設為Call<Object>)
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
複製程式碼
首先如果呼叫的方法屬於Object類的方法,例如notify,getClass等,則會直接呼叫。而第二個if在Android平臺不會執行,參考Platform中程式碼,其invokeDefaultMethod方法總會返回false,最後程式碼會執行到最下面三行。讓我們另起一個篇幅來看看這幾行程式碼到底做了神馬!!(第三步中講解)
第三步:通過動態代理物件呼叫介面方法返回Call物件
val call: Call<MsgBean> = service.getMsg()
複製程式碼
在我們呼叫自定義介面的方法後,程式碼會進入到retrofit.create方法中的那個匿名InvocationHandler物件中的invoke方法中,一般情況下都會跳過前面兩個if分支執行最下面的三行程式碼,並返回一個Call物件(上面說過了內建的Call物件為ExecutorCallbackCall)。來讓我們一行行開始看看這幾行程式碼到底做了什麼:
//將該方法對映為ServiceMethood
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
複製程式碼
呼叫loadServiceMethod方法並返回ServiceMethod物件,看下loadServiceMethod:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//首先從載入過的快取列表中去取
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
//如果快取過則直接返回
if (result != null) return result;
//雙重鎖,考慮到同步問題
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//通過ServiceMethod.Builder來建立ServiceMethod物件
result = new ServiceMethod.Builder<>(this, method).build();
//快取到集合中
serviceMethodCache.put(method, result);
}
}
return result;
}
複製程式碼
loadServiceMethod方法會做這麼幾件事,首先從快取列表中去獲取快取例項,如果未做快取(即為null)則通過ServiceMethod.Builder來建立ServiceMethod,然後快取並返回。serviceMethodCache的定義是這樣子:
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
複製程式碼
ConcurrentHashMap是一個執行緒安全且擁有很好的併發寫入能力的HashMap。
順著程式碼我們繼續分析ServiceMethod.Builder這個類,一下進入ServiceMethod分析
ServiceMethod
ServiceMethod.Builder
ServiceMethod.Builder擁有這麼些個屬性啊!! 再來看看構造方法: Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
複製程式碼
ServiceMethod.Builder接收從外部傳入的Retrofit(即第一步中你配置好的Retrofit物件)和Method(即你自定義介面中你說呼叫的那個方法的Method物件)兩個引數,並通過method的getAnnotations、getGenericParameterTypes、getParameterAnnotations來分別為其成員屬性初始化賦值。
繼續看build方法:
public ServiceMethod build() {
//這裡建立CallAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//這裡建立Converter
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
//解析校驗方法中的註解
parseMethodAnnotation(annotation);
}
......
return new ServiceMethod<>(this);
}
複製程式碼
build方法中會建立CallAdapter和Converter例項(通過Retrofit中指定的CallFactory和ConverterFactory),校驗方法上的註解和方法引數及引數註解。校驗邏輯這裡就跳過了,不難但是多,我們來重點看下CallAdapter和Converter的建立。
先看CallAdapter的建立
CallAdapter的建立
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
//返回值校驗
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
//返回值型別為Void丟擲異常
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//看這裡!!看這裡!!看這裡!!
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
複製程式碼
createCallAdapter中首先對方法的返回值進行校驗,首先校驗是否有無法處理的型別:
//檢查是否含有無法處理的型別
static boolean hasUnresolvableType(Type type) {
if (type instanceof Class<?>) {
return false;
}
//判斷返回值是否是泛型引數型別
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
//此處遞迴檢查
if (hasUnresolvableType(typeArgument)) {
return true;
}
}
return false;
}
if (type instanceof GenericArrayType) {
return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType());
}
//型別引數
if (type instanceof TypeVariable) {
return true;
}
//通配型別
if (type instanceof WildcardType) {
return true;
}
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <" + type + "> is of type " + className);
}
複製程式碼
校驗邏輯參考註釋,hasUnresolvableType是一個遞迴方法,用於泛型層次比較深的情況。
其次返回值為void(無返回值)時也會丟擲異常,經過以上兩個檢查後,最終呼叫retrofit.callAdapter(returnType, annotations),跟一下:
繼續跟: public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
//呼叫到這裡時skipPast為null,因此start的值為0
int start = adapterFactories.indexOf(skipPast) + 1;
//遍歷adapterFactories集合並呼叫get方法,如果不為null則返回
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
......
throw new IllegalArgumentException(builder.toString());
}
複製程式碼
nextCallAdapter會從adapterFactories的首位開始遍歷並呼叫get方法,當找到能夠處理當前呼叫方法的CallAdapter後便停止遍歷並返回該CallAdapter,如果未找到合適的CallAdapter(包括內建的CallAdapter),則丟擲異常。
再看Converter的建立
Converter的建立
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
//看這裡!!看這裡!!看這裡!!
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
複製程式碼
直接看註釋那裡,繼續跟!:
別停!再跟!: public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//skipPast此時也為null,start的值為0
int start = converterFactories.indexOf(skipPast) + 1;
//遍歷converterFactories,找到合適的(不為null)則返回
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;
}
}
......
throw new IllegalArgumentException(builder.toString());
}
複製程式碼
和nextCallAdapter方法很相似,從converterFactories中遍歷尋找合適的Converter,一旦找到則終止迴圈並返回,如果找不到合適的Converter則丟擲異常。在Retrofit.Builder的build方法中有提到build的時候converterFactories會被新增一個內建的Converter到首位置。這個Converter是BuiltInConverters,現在讓我們來看一下BuiltInConverters這個類的定義:
final class BuiltInConverters extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
//如果返回結果型別泛型引數為ResponseBody
if (type == ResponseBody.class) {
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
//如果返回結果型別泛型引數為Void
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
......
}
複製程式碼
這裡只給大家貼出了responseBodyConverter這個方法的程式碼,可以看到當自定義介面中的方法的返回值泛型引數型別為ResponseBody時,如果有Streaming註解修飾則返回StreamingResponseBodyConverter,否則返回BufferingResponseBodyConverter;如果返回值泛型引數型別為Void,則返回VoidResponseBodyConverter;上面都不滿足則返回null。
上面是對
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); 複製程式碼
這一行程式碼的跟蹤和分析,現在回到invoke方法中最下面的部分繼續看剩餘兩行程式碼:
//建立OkHttpCall物件
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
複製程式碼
建立OkHttpCall物件
//利用CallAdapter將okHttpCall轉換為指定的型別(預設為Call<Object>)
return serviceMethod.callAdapter.adapt(okHttpCall);
複製程式碼
利用serviceMethod中的callAdapter的adapt方法將內建的OkHttpCall轉換為指定的型別
第四步:通過Call物件發起請求
call.enqueue(object : Callback<MsgBean> {
override fun onFailure(call: Call<MsgBean>?, t: Throwable?) {
Log.i("wh", "onFailure")
}
override fun onResponse(call: Call<MsgBean>?, response: Response<MsgBean>?) {
Log.i("wh", "onResponse")
}
})
複製程式碼
使用內建的Call物件(ExecutorCallbackCall)發起請求,前面有將,這裡就不在複述了。