在Android客戶端的項目網絡請求實踐中,對retrofit進行了實踐和源碼的閱讀。從retrofit的用法入手,對retrofit進行解析。 首先看一下retrofit的基本用法: 第一步建立retrofit對象:java
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.build();
複製代碼
第二步建立一個service接口,接口的組成以下設計模式
public interface NetWorkService {
@FormUrlEncoded
@Post("/reativePath")
Call<ResponseBody> getResponse(@Field("param") String param);
}
複製代碼
第三進行網絡請求緩存
NetWorkService service = retrofit.create(NetWorkService.class);
Call<ResponseBody> call = service.getResponse(param);
複製代碼
查看Retrofit的類結構,使用了經典的Builder設計模式,經過Builder的方法咱們一般能夠設置OkHttpClient、HttpUrl、ConverterFactory、CallAdapterFactory等。 查看Retrofit的create方法bash
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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
複製代碼
這裏使用了Java的動態代理模式,關於代理模式和動態代理,能夠查看這裏。 在create中,建立了一個最終暴露給咱們的代理類A,類型爲T,也就是xxService,內部的委託類B爲service,也是咱們的類xxService。其中起到2個類的橋接做用的是一個實現了InvocationHandler接口的匿名類C,C爲A的委託類,爲B的代理類。最終A在外部對接口方法的調用會傳遞到C中,C再將調用傳遞給B。 在匿名類中網絡
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
複製代碼
這一段代碼就是在代理類中進行的調用。咱們進入這幾個方法能夠看到retrofit對於xxService的整個處理。 查看loadService的代碼ide
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);
}
}
複製代碼
在Retrofit類中維護了一個Map用來存放ServiceMethod,若是method對象已經存在就會使用已經存在的緩存對象,避免每次對象在代理類裏面運行的開銷。 進入ServiceMethod的build方法,咱們能夠看到retrofit對service的處理。我將service接口的處理過程梳理了一下post
接下來咱們對每個步驟進行解析ui
###CallAdapter service的build中會調用retrofit的callAdapter方法,繼而調用nextCallAdapter方法。this
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
複製代碼
咱們會取出retrofit的存放adapter的list中第一個不爲空的adapter做爲最後使用的adapter,而且根據returntype去除CallAdapter,結合動態代理部分能夠看出,retrofit會把Call根據咱們的CallAdapter轉換爲想要的類型。例如retrofit+rxjava使用的時候把Call轉化爲一個Observable。編碼
接下來會執行createResponseConverter方法,這個主要是解析返回的數據。在裏面會調用retrofit的responseBodyConverter方法,相似callAdapter,接下來會調用nextResponseBodyConverter方法
int start = converterFactories.indexOf(skipPast) + 1;
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;
}
}
複製代碼
咱們會拿到retrofit中存放converter的list中第一個獲取到ConVerter對象不爲空的做爲方法的返回值。例如GsonResponseBodyConverter中就會把返回的response數據利用Gson解析爲對應的實體類對象。 並且在retrofit的Build類的build方法中,在存adapter的list裏面加入了默認的對象
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
複製代碼
默認添加的是一個DefaultCallAdapterFactory對象 而converter的list則會默認添加一個BuiltInConverters對象
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());
}
複製代碼
接下來會對retrofit的xxService接口進行方法註解的解析 截取一小段代碼進行分析:
if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
}
複製代碼
其中最後一個參數的true和false是methodService中的hasBody變量 根據源碼咱們能夠將方法註解分類以下:
建立ParamterHandler對象,這個對象是用來處理參數的。在後面的request構建會使用到。其中,每個method的註解都有它對應的ParamterHandler對象。
在serviceMethod對象build前的最後一步是解析method的參數註解,會將讀取到的數據傳入ParamterHandler對象中,最終拼成http請求的參數
最後,在Retrofit的create中,咱們會返回一個Call對象,這個對象實際在默認狀況下是一個ExecutorCallbackCall對象,ExecutorCallbackCall對象內部包裹了一個OkHttpCall對象。
OkHttpCall對象是實際上執行網絡請求的類,這個對象實際是包裝了OkHttp裏面的Call對象。最終在enqueue等方法中會調用OkHttp的對應的方法。
陸陸續續看了一段時間的retrofit源碼,雖然這個庫的代碼很少,可是設計思路很是的牛逼。咱們應該多吸取這種優秀三方庫的思想到咱們本身的代碼中