在流程梳理篇,我們介紹了ServiceMethod是其retrofit的核心部分,這篇我們就着重分析retrofit的ServiceMethod這個處理類
build建造者部分
對於ServiceMethod這部分的build,其構造如下:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
這裏傳入了retrofit本身和目標的方法method
從method的getAnnotations/getGenericParameterTypes/getParameterAnnotations
這些方法中,可以看出retrofit這部分就是想方設法從method上獲取到所有的信息
從上面的構造入手,一下子就想到在使用的時候我們的一些做法,舉例:
@FormUrlEncoded
@POST("openapi.do")
public abstract Call<TranslateBean> hello(@Field("keyfrom") String keyfrom,
@Field("key") String key);
衆所周知,一個request的組成基本上參數部分都是key-vale形式組成,那就不難理解爲什麼retrofit要求我們從通過方法註解/參數註解這些方式傳入對應的關係了
理解了參數部分,我們看看build建造者最關鍵的方法build方法:
build方法較多,我們先摺疊起來,看前半部分:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();
...省略部分代碼
return new ServiceMethod<>(this);
}
build方法上首先創建了一個callAdapter,提起callAdapter不免立馬想到我們使用時傳入的RxJavaCallAdapterFactory部分,我們順着createCallAdapter看看跟我們RxJavaCallAdapterFactory有沒有關係,
private CallAdapter<T, R> createCallAdapter() {
/**
* 首先通過method獲取返回值類型,緊跟着對返回值類型合法性驗證
*/
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.");
}
/**
* 接着獲取方法上的註解,根據返回值類型和方法上的註解,調用retrofit的callAdapter
*/
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
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);
}
}
而對於retrofit的callAdapter方法其上註解是這樣描述的:
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
即返回這種返回值類型的callDApter從callAdapterFactories中,那就很顯然了,那就跟我們預想的一樣,RxJavaCallAdapterFactory中返回目標返回值類型的callAdapter
對於callAdapter這部分是retrofit的高明之處,通過這個callAdapter大大增加了其語言的擴展性
CallAdapter部分
在callAdapter這裏呢,只有兩個方法,一個是
Type responseType();
,另一個是T adapt(Call<R> call);
這個方法是返回在請求響應時我們接收的bean的值類型對象 Type responseType(); 而最後這個方法是返回一個okhttp執行請求的call代理對象 T adapt(Call<R> call);
順着上面的思路繼續,在build方法中,緊跟着從callAdapter的responseType中獲取返回值類型,根據這個返回值類型,調用createResponseConverter這個方法:
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);
}
}
這個方法就與callAdapter很相似了,也是通過獲取method方法上的參數,根據返回值類型和註解,調用retrofit的responseBodyConverter
對於responseBodyConverter這部分處理與callAdapter極其的相似
ResponseBodyConverter部分
一提到相似,我們也就能反應過來,我們傳入的GsonConverterFactory,也是根據我們的要求返回我們所要的ResponseBodyConverter
/** * Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available * {@linkplain #converterFactories() factories} except {@code skipPast}. * * @throws IllegalArgumentException if no converter available for {@code type}. */ public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast, Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { /** * 通過converterFactory找到我們要的converter來進行轉換 */ Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } } ...省略部分代碼... }
既然通過createCallAdater和createResponseConverter這兩個方法,把耦合的入口和出口都處理好了,下面就是進入參數處理的階段了:
/**
* 通過method的註解遍歷,對method的註解進行處理
*/
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...省略部分代碼...
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);
}
...省略部分代碼...
剩餘的方法主要就是parseMethodAnnotation和parseParameter這兩個方法了
parseMethodAnnotation
這裏只剪輯parseMethodAnnotation不過殊途同歸,最終處理都是在parseHttpMethodAndPath中,對於parseHttpMethodAndPath
parseHttpMethodAndPath
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { ...省略部分代碼... int question = value.indexOf('?'); /** * 對參數註解和參數值進行拼接 */ if (question != -1 && question < value.length() - 1) { // Ensure the query string does not have any named parameters. String queryParams = value.substring(question + 1); Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams); ...省略部分代碼... } this.relativeUrl = value; this.relativeUrlParamNames = parsePathParameters(value); } static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*"; static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}"); static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM); /** * 完成對url的處理 */ static Set<String> parsePathParameters(String path) { Matcher m = PARAM_URL_REGEX.matcher(path); Set<String> patterns = new LinkedHashSet<>(); while (m.find()) { patterns.add(m.group(1)); } return patterns; } 最終我們得到目標方法的請求路徑
由於parseParameterAnnotation情況分類比較多,這裏僅拿field來進行講解說明
...省略部分代碼... /** * 首先獲取字段名稱 */ Field field = (Field) annotation; String name = field.value(); boolean encoded = field.encoded(); gotField = true; /** * 首先獲取值類型 */ Class<?> rawParameterType = Utils.getRawType(type); /** * 如果值類型是Iterable的子類 */ if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + "<String>)"); } ParameterizedType parameterizedType = (ParameterizedType) type; /** * 如果值類型是Iterable的子類,通過getParameterUpperBound獲取實際類型的類型 */ Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); /** * 通過type和註解找到轉換的converter */ Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations); /** * 將轉換器/字段名稱和字段是否encode處理存放在ParameterHandler的Field中 */ return new ParameterHandler.Field<>(name, converter, encoded).iterable(); } else if (rawParameterType.isArray()) { Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Field<>(name, converter, encoded).array(); } else { Converter<?, String> converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Field<>(name, converter, encoded); }
將所有paramterHandler存放在builder的parameterHandlers中
ParameterHandler
ParameterHandlerd的實現不同實現有很多,有Body/RawPart/FieldMap/Field等等,這裏用Field舉例:
static final class Field<T> extends ParameterHandler<T> { private final String name; private final Converter<T, String> valueConverter; private final boolean encoded; Field(String name, Converter<T, String> valueConverter, boolean encoded) { this.name = checkNotNull(name, "name == null"); this.valueConverter = valueConverter; this.encoded = encoded; } @Override void apply(RequestBuilder builder, T value) throws IOException { if (value == null) return; // Skip null values. builder.addFormField(name, valueConverter.convert(value), encoded); } } 所有實現最關鍵的apply方法,向RequestBuilder中addFormField操作 構建請求數據
到這裏Builder相關的方法就結束了
toRequest
toRequest方法是ServiceMethod其中的一個方法,從上面我們片面的瞭解parameterHandler幫我們構建form請求數據,這個方法就是ServiceMethod幫助我們統一進行對Request的創建
Request toRequest(Object... args) throws IOException {
/**
* 根據目標方法/baseUrl等創建RequestBuilder
*/
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
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 + ")");
}
/**
* 將之前構建的所有paramterhandler進行request處理
*/
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
至此retrofit部分的request處理就到這結束了,由於reqeustBuilder內容相對清晰,容易分析,這裏就不加大篇幅來闡述這裏的內容