一,前言
Retrofit其實是將OKhttp封裝起來,和volley一樣。那解析Retrofit其實就是解析它如何封裝使用OKhttp,那我直接從其使用上來跟蹤源碼。
總體上可以分為四步:
- 創建Retrofit對象
- 通過Retrofit獲取接口對象
- 通過接口對象獲取請求服務的Call對象
- 最后通過Call的異步enqueue或同步execute來執行網絡請求并回調結果。
下面也是通過這四步來解析源碼
二,創建Retrofit對象
先占時不考慮RxJava的使用
Retrofit retrofit = new Retrofit.Builder() //1
.baseUrl(baseUrl) //2
.addConverterFactory(GsonConverterFactory.create()) //3
.build(); //4
Retrofit是通過建造者模式來構建對象的,那很明顯,這里只是配置了請求網絡的參數而已,而這些配置在后面的網絡請求和結果轉換用到了。
第二步是為了配置請求服務的地址;第三部是配置返回結果的轉換器,使結果為對象。
2.1 Builder()
public static final class Builder {
private final Platform platform;
// 網絡請求器的工廠
private @Nullable okhttp3.Call.Factory callFactory;
// 網絡請求的url地址
private HttpUrl baseUrl;
// 數據轉換器工廠的集合,生產數據轉換器(converter)
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 網絡請求適配器工廠的集合,生產網絡請求適配器(CallAdapter)
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//// 請求結束后回調方法的執行Executor
private @Nullable Executor callbackExecutor;
// 是否提前對業務接口中的注解進行驗證轉換的標志位
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
...
}
Builder里存儲的參數都會在Retrofit創建時賦值給它,后面的build()再介紹。
在創建Builder()對象時,其實只賦值了兩個屬性:platform 和converterFactories。可以知道默認的請求結果轉換器為BuiltInConverters,我們開發中一般使用GsonConverterFactory.create()。
2.1.1 Platform
Platform是單例模式,通過Platform.get()來獲取對象。
class Platform {
//單例對象是通過findPlatform()創建的
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
//如果是安卓系統,就返回Android()
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
// Java8()
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
static class Android extends Platform {
//請求結果回調使用的Executor,如果Builder沒有賦值給callbackExecutor,就會調用這個方法賦值
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//Builder里的CallAdapter.Factory,最后會在build()里賦值給adapterFactories,作為默認的網絡請求適配器
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
//那可以看出默認的網絡適配器是ExecutorCallAdapterFactory實現的
return new ExecutorCallAdapterFactory(callbackExecutor);
}
//調用handler使回調在主線程執行
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
最為安卓平臺,Platform最終賦值的對象是靜態內部類Android,這個對象作為默認配置,會在Builder的build()方法中調用賦值。
defaultCallbackExecutor是返回回調執行的Executor,返回的MainThreadExecutor是使用handler讓回調操作在主線程執行。如果在Builder中沒有指定回調的Executor,會調用defaultCallbackExecutor指定異步網絡請求的回調在主線程執行。
defaultCallAdapterFactory則是指定默認網絡適配器工廠為ExecutorCallAdapterFactory,調用接口方法返回的Call,就是這個類創建的。具體等后面使用其功能再介紹。
2.2 其它配置
2.2.1 baseUrl
就是將String類型的url,經過合格性檢測,拆分存儲,再轉換成HttpUrl賦值給baseUrl。
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
//將String的轉為HttpUrl
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
//如果路徑結尾不是以"/"結尾,會拋出異常
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
值得注意的是,路徑必須以"/"結尾
2.2.2 addConverterFactory
//將轉換工廠保存到converterFactories中,在構造器中,已經add了一個BuiltInConverters
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
上面的例子是添加GsonConverterFactory,下面來看看它是如何轉換的。
2.2.2.1 GsonConverterFactory
public final class GsonConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//返回對應的Converter對象
return new GsonResponseBodyConverter<>(gson, adapter);
}
}
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
//將ResponseBody轉為泛型對象
return adapter.read(jsonReader);
} finally {
value.close();
}
}
通過convert轉換的類型,是在調用responseBodyConverter創建對象時傳入的請求接口的返回類的泛型。也就是例子中的HttpResult。
如果要自定義Converter來實現請求結果轉化,按上面那樣就可以了,使用工廠方法模式。
- 繼承Converter,在convert方法中返回轉換后的結果,比如GsonRequestBodyConverter中是把ResponseBody轉成自己需要轉的類型。
- 繼承Converter.Factory,在responseBodyConverter中將相應的Converter對象返回。
- 在Retrofit的創造器中調用addConverterFactory添加相應的Converter.Factory。
2.3 build()
這部將根據先前的配置生成Retrofit,其實Builder中的配置屬性幾乎都賦值給了Retrofit。
public Retrofit build() {
//callFactory是類okhttp3.Call.Factory的對象,如果自己沒有設置了OkHttp對象,則會自己創建一個。
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//回調方法執行器
Executor callbackExecutor = this.callbackExecutor;
//沒有指定的話,就用構造器中賦值的platform中的,也就是將回調放在主線程
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 將配置的網絡適配器進行保護性拷貝
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//添加默認的網絡適配器,也就是ExecutorCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 與網絡適配器的排序不同,默認的BuiltInConverters放在第一位,后面才是添加的
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
對于網絡適配器隊列存儲順序和數據轉化器的隊列順序不同,其實是在后面給ServiceMethod賦值相應屬性時,采取了不同的取值策略。網絡適配器優先獲取隊列前面的;數據轉化器雖然也是從隊列前面開始適配,但默認的BuiltInConverters要接口返回類型為ResponseBody或Void才會返回Converter對象,返回類型為其它時,會繼續遍歷后面的數據轉化器,所以在設定返回值為對象時,GsonConverterFactory會起作用。具體后面ServiceMethod創建時會介紹。
2.4 總結
在最后build()中,可以發現創建Retrofit時,傳入了6個參數。
- OKHttp對象。比如設置連接超時時間的OKHttp
- 服務器地址。必填
- 請求結果的數據轉換器。對于請求結果的返回類型進行轉換
- 網絡適配器。默認為ExecutorCallAdapterFactory,通常設置為RxJava2CallAdapterFactory.create()。
- 回調方法執行器。默認回調在主線程執行。
- 是否提前對業務接口中的注解進行驗證轉換的標志位。在create中有用到。
比較重要的類有設置默認回調方法執行器和默認網絡適配器的Platform;默認的數據轉換器BuiltInConverters。
三 通過Retrofit獲取接口對象
MovieService movieService = retrofit.create(MovieService.class);
public interface MovieService {
//get請求
@GET("top250")
//網絡請求數據的方法,@Query配置請求參數
Call<HttpResult<List<Subject>>> getTopMovie(@Query("start")int start, @Query("count")int count);
}
MovieService是個接口,里面定義了一個方法,通過注解上面配置了請求接口的參數配置,retrofit通過方法的參數創建接口對象。
那來看看如何通過接口來獲取對象。
3.1 create
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
//是否提前通過注解加驗證加載請求接口,會將接口中的方法都解析成ServiceMethod,并加入serviceMethodCache緩存中
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//創建動態代理對象,用來代理接口
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() { //將代理類的實現交給 InvocationHandler類作為具體的實現
private final Platform platform = Platform.get();
//被代理執行的方法,是通過在InvocationHandler中的invoke方法調用的
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// Object的方法直接調用原方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//android默認為false,不走
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//這里才是被代理方法真正執行的地方
//通過接口方法的注解來獲取ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//如果是默認網絡適配器,就生成Call對象;RxJava則生成Observable對象
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
代理模式的動態代理是實現接口方法調用的關鍵,動態代理也只能代理接口,invoke方法是接口方法正在實現的地方,生成的代理對象在運行時存在內存中。
這樣
那接下來看接口方法的調用。
四 通過接口對象獲取請求服務的Call對象
Call<HttpResult<List<Subject>>> call = movieService.getTopMovie(0, 10);
這里的getTopMovie方法調用,是在上面invoke方法中實現的,主要是這幾行代碼
//通過方法注解配置,獲取ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//根據ServiceMethod創建OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//創建Call
return serviceMethod.callAdapter.adapt(okHttpCall);
4.1 loadServiceMethod
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//從緩存中獲取,如果先前創建過久直接用
//create中的eagerlyValidateMethods方法會提前創建對象并緩存
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;
}
對象的創建是通過new ServiceMethod.Builder<>(this, method).build()實現的。
4.1.1 new ServiceMethod.Builder<>(this, method)
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//獲取方法里的注解
this.methodAnnotations = method.getAnnotations();
//獲取方法的參數類型
this.parameterTypes = method.getGenericParameterTypes();
//獲取方法參數里的注解
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
就是賦值。
4.1.2 build()
public ServiceMethod build() {
//1.根據接口的返回類型和注解,從retrofit中獲取網絡適配器
callAdapter = createCallAdapter();
//方法返回值泛型的類型,也就是網絡請求的返回值類型
responseType = callAdapter.responseType();
//2.根據方法的返回類型和注解,網絡數據轉換器
responseConverter = createResponseConverter();
//3.獲取方法上的注解
for (Annotation annotation : methodAnnotations) {
//根據注解獲取配置
parseMethodAnnotation(annotation);
}
//4.獲取方法參數里的注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
//根據注解獲取配置參數
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
重點關注下網絡適配器和數據轉換器是如何獲得的,根據前面的Builder可知,retrofit里它們都是以數組保存的,那獲取規則又如何呢。
4.1.2.1 createCallAdapter
先看網絡適配器如何獲取的。
private CallAdapter<T, R> createCallAdapter() {
//返回值類型
Type returnType = method.getGenericReturnType();
//方法注解
Annotation[] annotations = method.getAnnotations();
try {
//通過retrofit的callAdapter方法返回的
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);
}
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
//從0開始
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
//在分析的例子中,沒有配置網絡適配器,所以用的默認的ExecutorCallAdapterFactory
//使用RxJava會配置了RxJava2CallAdapterFactory
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
因為例子沒有配置網絡適配器
這里是使用默認的網絡適配器ExecutorCallAdapterFactory,如果配置了RxJava2CallAdapterFactory,它會在默認網絡適配器的前面,那時就會使用RxJava2CallAdapterFactory了。ExecutorCallAdapterFactory這個到后面通過網絡適配器返回的Call調用enqueue時再介紹。
4.1.2.2 createResponseConverter
解析的例子中,是配置了GsonConverterFactory數據轉換器。和上面的網絡適配器一樣,數據轉換器也是從retrofit保存的配置信息中獲取的
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
//從0開始
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
//默認的數據轉換器BuiltInConverters,如果接口方法返回值類型不是ResponseBody和Void的話,返回null
//分析的這個例子中,接口方法返回值的泛型是HttpResult,所以會循環到下個GsonConverterFactor對象
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
}
數據轉換器把默認的BuiltInConverters放在了第一位,但還是根據接口方法返回值泛型會過濾選擇。所以在自定義轉換器時,要過濾要轉換的類型。
4.2 ExecutorCallAdapterFactory
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
serviceMethod.callAdapter.adapt(okHttpCall)
又回到Retrofit中create的動態代理中來,到invoke中最后一步,返回Call。(如果是RxJava,則返回Observable)
根據上面的分析,可以知道serviceMethod.callAdapter對象是默認的ExecutorCallAdapterFactory。callAdapter和Converter都采用了工廠方法模式來實現,理解這個更有助于自定義它們。
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) {
//返回值類型判斷,要是Call才行
if (getRawType(returnType) != Call.class) {
return null;
}
//返回值泛型的類型,如例子中的HttpResult
final Type responseType = Utils.getCallResponseType(returnType);
//返回CallAdapter
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
//相應的call對象
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
}
CallAdapter和它的工廠CallAdapter.Factory,是自定義CallAdapter的關鍵。
- CallAdapter的adapt方法返回接口方法的返回值,上面是返回Call對象。如果是RxJava,則返回Observable對象。
- CallAdapter.Factory則是創建CallAdapter的工廠,它的get方法返回CallAdapter對象
- CallAdapter的adapt方法的返回對象,是實現后續網絡請求的關鍵,自定義要在返回對象中將自己封裝的網絡請求放在里面。
4.3 總結
到這里,如何通過接口對象調用方法獲取Call已經很明了了。就是通過動態代理對象里的InvocationHandler里的invoke方法實現,調用接口對象方法實際上是調用invoke方法。
在invoke中,首先根據接口方法的注解和Retrofit里的配置通過建造者模式生成ServiceMethod對象,再生成實現網絡請求的對象OkHttpCall,通過ServiceMethod中的CallAdapter來生成封裝了OkHttpCall的Call對象(RxJava則是Observable)。
自定義CallAdapter的關鍵是實現CallAdapter和CallAdapter.Factory。
五 請求網絡
請求網絡時通過調用call.enqueue,那來看看默認的Call對象相應方法的實現,也就是ExecutorCallAdapterFactory里的ExecutorCallbackCall
static final class ExecutorCallbackCall<T> implements Call<T> {
//回調方法執行器
final Executor callbackExecutor;
//OkHttpCall對象,是生成ExecutorCallbackCall時傳入的
final Call<T> delegate;
//在CallAdapter的adapt方法中被創建賦值
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//代理模式,最終還是OkHttpCall實現
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()) {
//失敗回調
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);
}
});
}
});
}
}
ExecutorCallbackCall用的代理模式,最終實現的對象的OkHttpCall。
OkHttp的使用就分四步
- 創建okHttpClient對象
- 創建一個Request
- new call
- 請求加入調度
真正實現網絡請求的就是OKHttp,我們可以從上面四步了解網絡請求的實現。第一步在創建retrofit對象時就已經完成了。
5.1 OkHttpCall
OkHttpCall是retrofit2中封裝的一個類,內部調用還是通過ServiceMethod獲取網絡請求配置并生成okhttp3.Call來實現。
@Override public void enqueue(final Callback<T> callback) {
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 {
//1.生成okhttp3.Call對象,默認是OkHttpClient的newCall創建,為RealCall對象
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
//2.發送異步網絡請求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//3.通過存在serviceMethod的Converter轉換數據類型
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
//4.回調接口
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
可以看出實現網絡請求的是OKhttp,那只要關注okhttp3.Call是如何創建和網絡請求結果如何轉換就好了。
5.1.1 createRawCall()
okhttp3.Call的創建就完成了OkHttp使用的前三步了,下面來看看前三部是怎么實現的吧。
所有的網絡配置信息都在ServiceMethod中,很明顯,它們的生成也都在ServiceMethod中,通過默認的OkHttpClient的newCall創建,為RealCall對象,這些還是后面看OKHttp的解析了解吧。
private okhttp3.Call createRawCall() throws IOException {
//創建Request對象,將請求網絡的信息都封裝在里面
Request request = serviceMethod.toRequest(args);
//callFactory是okhttp3.Call.Factory,在創建Retrofit時默認的OkHttpClient
//正常OKhttp生成Call的流程
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
創建Request,再創建okhttp3.Call,這是正常的OkHttp請求的第二三步。這里只關心Retrofit的封裝,就看toRequest方法了。
5.1.1.1 serviceMethod.toRequest
Request toRequest(@Nullable Object... args) throws IOException {
//創造者模式構建對象
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
//接口方法的參數的注解結合
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
//校驗接口方法的參數的注解數量和接口方法參數的數量是否一致
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
//對接口方法參數,會在apply中轉換參數類型,并添加到requestBuilder中。
//數據轉換默認使用BuiltInConverters.ToStringConverter.INSTANCE,也就是直接將參數值toString()
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
//里面通過參數,用普通的OKhttp的建造器生成Request
return requestBuilder.build();
}
//例子中,添加的請求參數是Query,所以上面handlers[p].apply的實現是
static final class Query<T> extends ParameterHandler<T> {
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
//這里就是把value.toString()了
String queryValue = valueConverter.convert(value);
if (queryValue == null) return; // Skip converted but null values
//添加到請求url里去
builder.addQueryParam(name, queryValue, encoded);
}
}
對于接口方法注解的解析,我就不做太多介紹了。handlers[p].apply是將方法參數的配置信息添加到requestBuilder中去,將參數配置都添加后,在build中,用OKhttp的Request.Builder生成Request對象。
RequestBuilder將baseUrl和請求接口方法里的注解配置信息組合起來,將配置信息添加入Request.Builder中,創建Request。
5.2 parseResponse
call.enqueue這個方法是okhttp3.Call的方法,就不分析了,主要分析請求服務結束后,將數據類型轉換為回調接口需要的類型。
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// 移除Response中的響應正文,在此基礎上創建一個新的Response
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) {
rawBody.close();
return Response.success(null, rawResponse);
}
//將響應正文封裝一層
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//調用數據轉換器進行類型轉換
T body = serviceMethod.toResponse(catchingBody);
//將轉換后內容和空body的Response再組合成Retrofit里的Response
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;
}
}
這里將okhttp3.Response,將響應正文通過數據轉換器轉換,再和空響應正文的okhttp3.Response組合成Retrofit里的Response,用于回調使用。
callback.onResponse是回調了默認網絡適配器里的ExecutorCallbackCall里的Callback,然后ExecutorCallbackCall里再使用默認的Executor在主線程回調例子里的Callback。
六 總結
- Converter和CallAdapter都是用工廠方法模式實現的,自定義時要分別實現產品類和工廠類,在工廠類中創建產品。
- Retrofit是通過建造者模式創建的,Retrofit.Builder()主要配置:網絡請求工廠(okhttp3.Call.Factory),網絡請求地址(HttpUrl),數據轉換器(List<Converter.Factory>),網絡適配器(List<CallAdapter.Factory>),回調執行方法(Executor),是否提前對業務接口中的注解進行驗證轉換的標志位(validateEagerly)
- 接口方法里通過注解配置了網絡請求的配置,通過Retrofit的create方法,動態代理實現了接口方法。接口方法的返回值是網絡適配器返回對象,類型要和接口方法的返回值一致。
- 動態代理的invoke方法里,通過Retrofit的配置和接口方法的注解配置生成ServiceMethod對象,這個對象保存了網絡請求的所有配置。大部分方法和解析注解生成配置有關,主要關注兩個方法:一個toRequest通過RequestBuilder生成OKhttp的Request,toResponse可以利用數據轉換器將ResponseBody轉為請求接口方法返回值泛型。這兩個方法都是給OkHttpCall使用。
- 再通過ServiceMethod創建了OkHttpCall,里面有請求網絡的方法,實際上是根據ServiceMethod的配置網絡信息生成的Request再生成okhttp3.Call,將請求結果通過ServiceMethod的配置轉換器進行數據轉換,最終回調給調用它的類(默認ExecutorCallbackCall)。
- ExecutorCallAdapterFactory是默認的網絡適配器工廠,在動態代理的invoke方法里,創建ServiceMethod時用get方法生成適配器后,再通過適配器的adapt生成ExecutorCallbackCall返回值,ExecutorCallbackCall中用靜態代理模式實現,被代理對象是OkHttpCall。
- GsonConverterFactory的具體轉換結果類型,是在創建ServiceMethod時,用解析的接口方法中的返回值泛型確定的。
- 隨后再列下關鍵的幾個類:
- Retrofit:用創建者模式存儲網絡配置。
- ServiceMethod:通過接口方法注解的配置和Retrofit里的配置,生成ServiceMethod。toReques和toResponse方法供給OkHttpCall使用。
- ServiceMethod中利用RequestBuilder,生成Request請求。Request利用Retrofit配置的網絡參數,和ServiceMethod里解析接口方法里的注解配置,生成Request請。
- OkHttpCall:網絡請求的封裝類,內部結合ServiceMethod的toReques生成OKHttp實現網絡請求,再用ServiceMethod的toResponse轉換結果回調給調用它的對象,這個對象是網絡適配器adapt生成。