知其然方能知其所以然。。。。。。。。。。。。。。。
尊重他人的勞動成果,轉載請標明出處:http://blog.csdn.net/gengqiquan/article/details/52778522, 本文出自:【gengqiquan的博客】
對於Retrofit,還不會用的可以看這篇文章Retrofit使用教程(二)
對Retrofit做封裝以便更方便的使用可以看這篇文章淺談Retrofit封裝-讓框架更加簡潔易用,
既然是好的框架,我們當然要拿來用,但同時也應該去了解框架的優點和好的設計思想。本篇博客就帶大家來一起走進Retrofit源碼的世界。
Retrofit 獨樹一幟的把請求採用了接口,方法和註解參數(parameter annotations)來聲明式定義一個請求應該如何被創建的方式。 如果你已經使用過它了,你應該記得他的實例創建是這樣的
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(StringConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(OkhttpProvidede.okHttpClient(mAppliactionContext))
.build();
RetrofitHttpService Service =
retrofit.create(RetrofitHttpService.class);
2.0版本適配器並沒有打包進retrofit裏,需要用戶自己去額外引用。
也就是需要額外添加這兩個依賴
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
上面一個是gson 解析的,下面一個是RXJava的。根據需要添加
首先我們來看retrofit的構建過程
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
builder()方法進行了一些簡單的檢查,構建了默認的請求工廠,檢查了適配器工廠和轉換器工廠,
retrofit.create(RetrofitHttpService.class);方法,採用方法註解定義請求的類型。
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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
傳入的是請求方法接口,類似於這樣的
public interface RetrofitHttpService {
@GET()
Call<String> get(@Url String url, @QueryMap Map<String, String> params, @Header("Cache-Time") String time);
@FormUrlEncoded
@POST()
Call<String> post(@Url String url, @FieldMap Map<String, String> params, @Header("Cache-Time") String time);
}
一步步看create方法
首先是 Utils.validateServiceInterface(service);
對接口類進行了檢查
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
// Prevent API interfaces from extending other interfaces. This not only avoids a bug in
// Android (http://b.android.com/58753) but it forces composition of API declarations which is
// the recommended pattern.
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
確保了service類必須爲接口且不能繼承於其他接口
validateEagerly是用戶在構建retrofit是自己配置的,是否需要預加載接口內的非默認方法,如果需要就進行預加載到
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
第一道菜來了
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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall); }
});
}
返回的是一個動態代理類,也就是說我們調用的那些自定義的接口,比如上面我定義的get(),和post(),都是通過這個動態代理單例去進行的,這樣的好處是用戶不需要去關注請求發起時需要做哪些事,所有的一些都交由動態代理類去完成。而代理內部是如和調用請求的呢?
判斷是否屬於延遲執行方法,是則直接執行。
判斷是否屬於接口默認方法,是則執行
如果不滿足上述條件。則確定爲retrofit所採用的註解方法
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
看loadServiceMethod的構建
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
再次builder,在builder類實例化的時候獲取之前我們在service裏定義的各種類型的註解
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
看build()方法,很長的一段代碼
public ServiceMethod build() {
//創建請求適配器
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?");
}
//創建響應體轉換器
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);//解析方法註解,下面單獨看
}
//省略一系列判斷代碼
int parameterCount = parameterAnnotationsArray.length;
//參數註解類,下面我們單獨看
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
//省略一大堆參數註解的解析判斷代碼
}
return new ServiceMethod<>(this);
}
先看parseMethodAnnotation()方法,解析接口方法的註解,告訴retrofit改方法是哪種請求方式
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
//下面省略的代碼和上面相同類型
}
}
再看ParameterHandler類
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, T value) throws IOException;
final ParameterHandler<Iterable<T>> iterable() {
}
final ParameterHandler<Object> array() {
}
static final class RelativeUrl extends ParameterHandler<Object> {
@Override void apply(RequestBuilder builder, Object value) {
builder.setRelativeUrl(value);
}
}
static final class Header<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
Header(String name, Converter<T, String> valueConverter) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
}
@Override void apply(RequestBuilder builder, T value) throws IOException {
if (value == null) return; // Skip null values.
builder.addHeader(name, valueConverter.convert(value));
}
}
static final class Path<T> extends ParameterHandler<T> {
//省略類裏面代碼,免得大家看的頭疼,下同
}
static final class Query<T> extends ParameterHandler<T> {
}
static final class QueryMap<T> extends ParameterHandler<Map<String, T>> {
}
//省略一系列參數註解對應的類
}
雖然只貼出來一部分,大家也能看出來這個類就是我們再service裏定義的接口方法的那些參數註解,每個註解靜態類都實現了一個構造函數外加一個apply方法。這個apply後面會遇到。
接下來交由ServiceMethod的callAdapter 去進行層層解析,然後交由OkHttpCall 去執行具體的請求
這個callAdapter 是可以設置的,比如上面的例子我們設置的就是addCallAdapterFactory(RxJavaCallAdapterFactory.create())
如果不設置的話,retrofit會默認創建一個
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
return 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);
}
}
callAdapter 處理過程我們後面再看,先看OkHttpCall
先看發送請求
@Override public synchronized Request request() {
okhttp3.Call call = rawCall;
if (call != null) {
return call.request();
}
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw new RuntimeException("Unable to create request.", creationFailure);
} else {
throw (RuntimeException) creationFailure;
}
}
try {
return (rawCall = createRawCall()).request();
} catch (RuntimeException e) {
creationFailure = e;
throw e;
} catch (IOException e) {
creationFailure = e;
throw new RuntimeException("Unable to create request.", e);
}
}
裏面有
return (rawCall = createRawCall()).request();
這一句,我們看看他裏面做了什麼
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
裏面再次調用了serviceMethod的toRequest(args);方法,看方法內部
/** Builds an HTTP request from method arguments. */
Request toRequest(Object... args) throws IOException {
//省略代碼
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 + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
可以看到調用了handlers的apply方法,這個就是之前的註解類裏所實現的apply。
再看OkHttpCall相應請求的代碼
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
okhttp3.Call call;
Throwable failure;
//這裏省略代碼
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
//這裏省略代碼
}
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
分爲同步和異步執行請求,可以看到,只要獲得相應了就直接走 parseResponse();方法,我們來看看這個方法
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) {
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(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;
}
}
可以看到方法內部直接對Response.code()值進行了判斷,把非OK的狀態的情況全部調用了Response.error()方法,再來看這個Response.error()方法
public static <T> Response<T> error(ResponseBody body, okhttp3.Response rawResponse) {
if (body == null) throw new NullPointerException("body == null");
if (rawResponse == null) throw new NullPointerException("rawResponse == null");
if (rawResponse.isSuccessful()) {
throw new IllegalArgumentException("rawResponse should not be successful response");
}
return new Response<>(rawResponse, null, body);
private Response(okhttp3.Response rawResponse, T body, ResponseBody errorBody) {
this.rawResponse = rawResponse;
this.body = body;
this.errorBody = errorBody;
}
再次構建了一個出錯的Response作爲返回,而不是如一般網絡框架那樣返回一堆錯誤信息或者直接拋出異常
有點頭疼,今天先寫到這裏,下篇我們再一起看看CallAdapter是怎麼處理註解接口方法
我建了一個QQ羣(羣號:121606151),用於大家討論交流Android技術問題,有興趣的可以加下,大家一起進步。