預習
本文主要對retrofit的原始碼進行學習,瞭解,學習其設計模式,與實現方式。
retrofit 的基本用法:
- Retrofit turns your HTTP API into a Java interface.
(將HTTP API轉換為Java介面。)
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
複製程式碼
- The Retrofit class generates an implementation of the GitHubService interface.
(Retrofit類生成GitHubService介面的實現。)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
複製程式碼
- Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.
(建立的GitHubService的每個呼叫都可以向遠端web伺服器發出同步或非同步的HTTP請求。)
Call<List<Repo>> repos = service.listRepos("octocat");
複製程式碼
A : service介面的構建
- 首先建立一個service的介面類。
- 指定請求方式 常見的有GET,POST,PUT,DELETE...,注意大小寫。
- 配置請求地址,注意path的配置規則(見retrofit 使用教程的7.2)
- 如果你在註解中提供的url是完整的url,則url將作為請求的url。
- 如果你在註解中提供的url是不完整的url,且不以 / 開頭,則請求的url為baseUrl+註解中提供的值
- 如果你在註解中提供的url是不完整的url,且以 / 開頭,則請求的url為baseUrl的主機部分+註解中提供的值
- 指定請求的回撥物件,預設返回retrofit的Call<T>物件,這裡我們可以
- 通過實現retrofit的CallAdapter<R, T> 介面,來自定義我們的返回物件。
- 再繼承CallAdapter.Factory生成我們自己的Factory,在get()方法返回我們自定義的CallAdapter。
- 最後呼叫Retrofit.Builder的addCallAdapterFactory(Factory)
- 指定請求結束後我們要接收的型別,如:okHttp返回預設的是ResponseBody,通過Retrofit的Converter可以轉換為我們需要的 string 或 反序列化為java Bean物件等。
- 定義一個MyConvert類實現retrofit的Converter介面。
- 定義一個MyConvertFactory繼承retrofit的Converter.Factory,實現responseBodyConverter()返回我們自定義的MyConvert類。
- 使用Retrofit.Builder.addConverterFactory(new MyConvertFactory())新增我們自定義的Factory.
- 定義我們請求的方法名字。
- 請求引數的註解
見(見retrofit 使用教程的第三類:引數類)
- 請求引數的名字
- 引數型別
- 引數名稱
B : retrofit的構建,原始碼分析
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
複製程式碼
我們可以看到retrofit的構建使用了builder模式。
1. 看一下Retrofit.Builder類:
/**
* Build a new {@link Retrofit}.
* <p>
* Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods
* are optional.
*/
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
...
}
複製程式碼
從原始碼可以看到:
- 從註釋看到baseUrl()必須在build()之前呼叫,其它可以隨意。
- platform 指定呼叫的平臺,這裡我們使用的是Android.
- callFactory okhttp3的Call.Factory
- baseUrl 請求的root地址
- converterFactories 儲存我們自定義的和系統預設提供的convertFactory見上面的A.5
- adapterFactories 儲存我們自定義的和系統預設提供的adapterFactory 見上面的A.4
- callbackExecutor 執行緒呼叫類
- validateEagerly 為true時做一些預處理操作
2. 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.
*/
//通過配置引數建立一個Retrofit的例項,如果沒有配置HttpClient也沒有配置CallFactory將採用預設的OkHttpClient
public Retrofit build() {
if (baseUrl == null) {
// baseUrl不能為空
throw new IllegalStateException("Base URL required.");
}
//配置HttpClient,可以看出retrofit預設採用OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//指定callback回撥方法的執行器,這裡的platform是Android平臺,可以看出預設下面的Android--Platform的MainThreadExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//將我們自定義的adapterFactory新增到集合中
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//將我們自定義的convertFactory新增到集合中
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
// 返回Retrofit
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
複製程式碼
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);
}
}
}
複製程式碼
經過build()操作後,我們配置好了一個我們想要的retrofit,接下來我們來看看這些配置是如何生效的,我們通過
GitHubService service = retrofit.create(GitHubService.class);
複製程式碼
來生成我們service介面的實現類。我們來看create()方法。
3. retrofit.create()
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, @Nullable 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);
}
});
}
複製程式碼
- validateEagerly 為true時會走 eagerlyValidateMethods(service)
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 = 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;
}
複製程式碼
這裡我們看到,是對ServiceMethod做的快取處理。如果快取中存在直接返回。
- 接下來我們看見採用了動態代理的模式來建立service介面的實現類。
- 如果是platform的方法直接return
- 如果是我們service介面內的方法,我們看到通過上面的loadServiceMethod(method)來建立了一個ServiceMethod類,我們來看ServiceMethod類做了那些處理。
4. ServiceMethod
我們看到ServiceMethod也是採用Builder模式來構建。
/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod<R, T> {
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
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);
final okhttp3.Call.Factory callFactory;//okhttp3.Call.Factory
final CallAdapter<R, T> callAdapter;//返回物件介面卡
private final HttpUrl baseUrl;//根地址
private final Converter<ResponseBody, R> responseConverter;//reponseBody轉換類
private final String httpMethod;//請求方式,PUT,POST...
private final String relativeUrl;//相對地址
private final Headers headers;//請求頭
private final MediaType contentType;//請求的Content-Type
private final boolean hasBody;//是否有請求訊息體
private final boolean isFormEncoded;//是否進行引數編碼
private final boolean isMultipart;// 上傳時使用
private final ParameterHandler<?>[] parameterHandlers;//請求引數註解的封裝物件
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
...
}
複製程式碼
接著來看 build() 方法
public ServiceMethod build() {
// [1] 建立CallAdapter,並得到返回的物件
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
//[2] 建立ResponseConverte,對返回的資料進行處理
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];
...
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
...
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
複製程式碼
上面的ServiceMethod.build()方法大概進行了如下操作:
- [1] 建立CallAdapter,並得到返回的物件
- [2] 建立ResponseConverte,對返回的資料進行處理
- [3] 遍歷方法註解,獲取具體的配置引數
- [4] 方法中引數註解的處理
接下來我們具體看看是如何實現的
[1] createCallAdapter()
private CallAdapter<T, R> createCallAdapter() {
//獲取方法的完整資訊的返回值
Type returnType = method.getGenericReturnType();
...
//獲得註解
Annotation[] annotations = method.getAnnotations();
...
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
...
}
複製程式碼
可以看到實際上是呼叫了retrofit.callAdapter(returnType, annotations)方法
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
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;
}
}
...
}
複製程式碼
從上面最終呼叫的nextCallAdapter方法,
adapterFactories.get(i).get(returnType, annotations, this)
看到,最終返回我們新增到adapterFactories的CallAdapterFactory.get()物件就是我們自定義的CallAdapter,注意這裡是有排序概念的,排在前面的優先匹配。
再通過responseType = callAdapter.responseType();將我們自己定義的call物件,或Obserable物件,或其他需要型別返回,見上面圖A.④。
[2] 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);
}
}
複製程式碼
再看retrofit.responseBodyConverter(responseType, annotations)
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
...
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;
}
}
...
}
複製程式碼
這裡我們最終看到通過converterFactories.get(i).responseBodyConverter(type, annotations, this)方法,返回我們自定義的泛型物件見上面圖A.⑤,通常是我們反序列化操作轉換後的物件,或根據需要過濾一些資料,返回有用的資料。
[3] parseMethodAnnotation(annotation)
在這裡處理方法上面的註解,獲取到請求方式見上面圖A.②,並對不同的請求方式做相應處理。
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.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
複製程式碼
接下來看一下 parseHttpMethodAndPath()
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
...
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
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);
if (queryParamMatcher.find()) {
throw methodError("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
複製程式碼
我們看到這裡將獲取到的請求方式httpMethod,是否有hasBody,還有地址路徑,headers,還有地址中含有的請求引數,等等,都賦值給ServiceMethod.Builder的相應屬性。
[4] parameterHandlers[]的賦值操作
在ServiceMethod.Build(Retrofit retrofit, Method method)時我們看一下
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
複製程式碼
- methodAnnotations 獲得method上的所有註解
- parameterTypes 獲得所有的引數型別,String ,int ...
- parameterAnnotationsArray 獲得引數的註解集合
再看
int parameterCount = parameterAnnotationsArray.length;
//構建一個ParameterHandler集合,
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
//獲取第p個引數型別
Type parameterType = parameterTypes[p];
...
//獲取第p個引數註解集合
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
...
//構建一個ParameterHandler物件
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
複製程式碼
看看 parseParameter(p, parameterType, parameterAnnotations)
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations,annotation);
}
...
return result;
}
複製程式碼
接著往下看parseParameterAnnotation(p, parameterType, annotations,annotation)
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
if (gotUrl) {
throw parameterError(p, "Multiple @Url method annotations found.");
}
if (gotPath) {
throw parameterError(p, "@Path parameters may not be used with @Url.");
}
if (gotQuery) {
throw parameterError(p, "A @Url parameter must not come after a @Query");
}
if (relativeUrl != null) {
throw parameterError(p, "@Url cannot be used with @%s URL", httpMethod);
}
gotUrl = true;
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl();
} else {
throw parameterError(p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
} else if (annotation instanceof Path) {
if (gotQuery) {
throw parameterError(p, "A @Path parameter must not come after a @Query.");
}
if (gotUrl) {
throw parameterError(p, "@Path parameters may not be used with @Url.");
}
if (relativeUrl == null) {
throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod);
}
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(name, converter, path.encoded());
} else if (annotation instanceof Query) {
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);
gotQuery = true;
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;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryName) {
QueryName query = (QueryName) annotation;
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);
gotQuery = true;
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;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.QueryName<>(converter, encoded);
}
} else if (annotation instanceof QueryMap) {
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@QueryMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, "Map must include generic types (e.g., Map<String, String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@QueryMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded());
} else if (annotation instanceof Header) {
Header header = (Header) annotation;
String name = header.value();
Class<?> rawParameterType = Utils.getRawType(type);
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;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Header<>(name, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Header<>(name, converter).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Header<>(name, converter);
}
} else if (annotation instanceof HeaderMap) {
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@HeaderMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, "Map must include generic types (e.g., Map<String, String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@HeaderMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.HeaderMap<>(valueConverter);
} else if (annotation instanceof Field) {
if (!isFormEncoded) {
throw parameterError(p, "@Field parameters can only be used with form encoding.");
}
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();
gotField = true;
Class<?> rawParameterType = Utils.getRawType(type);
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;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
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);
}
} else if (annotation instanceof FieldMap) {
if (!isFormEncoded) {
throw parameterError(p, "@FieldMap parameters can only be used with form encoding.");
}
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@FieldMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p,
"Map must include generic types (e.g., Map<String, String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@FieldMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
gotField = true;
return new ParameterHandler.FieldMap<>(valueConverter, ((FieldMap) annotation).encoded());
} else if (annotation instanceof Part) {
if (!isMultipart) {
throw parameterError(p, "@Part parameters can only be used with multipart encoding.");
}
Part part = (Part) annotation;
gotPart = true;
String partName = part.value();
Class<?> rawParameterType = Utils.getRawType(type);
if (partName.isEmpty()) {
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;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = rawParameterType.getComponentType();
if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
return ParameterHandler.RawPart.INSTANCE;
} else {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
} else {
Headers headers =
Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
"Content-Transfer-Encoding", part.encoding());
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;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
}
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
}
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
} else {
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter);
}
}
} else if (annotation instanceof PartMap) {
if (!isMultipart) {
throw parameterError(p, "@PartMap parameters can only be used with multipart encoding.");
}
gotPart = true;
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@PartMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, "Map must include generic types (e.g., Map<String, String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@PartMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(valueType))) {
throw parameterError(p, "@PartMap values cannot be MultipartBody.Part. "
+ "Use @Part List<Part> or a different value type instead.");
}
Converter<?, RequestBody> valueConverter =
retrofit.requestBodyConverter(valueType, annotations, methodAnnotations);
PartMap partMap = (PartMap) annotation;
return new ParameterHandler.PartMap<>(valueConverter, partMap.encoding());
} else if (annotation instanceof Body) {
if (isFormEncoded || isMultipart) {
throw parameterError(p,
"@Body parameters cannot be used with form or multi-part encoding.");
}
if (gotBody) {
throw parameterError(p, "Multiple @Body method annotations found.");
}
Converter<?, RequestBody> converter;
try {
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
} catch (RuntimeException e) {
// Wide exception range because factories are user code.
throw parameterError(e, p, "Unable to create @Body converter for %s", type);
}
gotBody = true;
return new ParameterHandler.Body<>(converter);
}
return null; // Not a Retrofit annotation.
}
複製程式碼
這麼超長的程式碼,將我們方法引數的註解,引數型別,引數值都拿到,封裝為 ParameterHandler 並儲存到ParameterHandler<?>[] parameterHandlers集合。
至此,我們將我們建立的service介面所呼叫方法中的請求方式,請求路徑,返回值,請求引數等都獲取到了,並儲存到一個ServiceMethod物件中。
接下來我們再回到 retrofit.Create() 中
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, @Nullable Object[] args)
throws Throwable {
...
//這裡最終返回到Retrofit中的ServiceMethod<Object, Object>,來儲存我們構建的serviceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//再看OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
複製程式碼
5. OkHttpCall<Object>
將我們上面構建的serviceMethod 與引數傳進來
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
複製程式碼
最後通過serviceMethod.callAdapter.adapt(okHttpCall)就建立好了我們service的一個實現類。
再看看**callAdapter.adapt(okHttpCall)**這裡的callAdapter是們自定義的callAdapter物件,Android預設的是Call<>;若設定了RxJavaCallAdapterFactory,返回的則是Observable<>,這裡我們看看後一種情況下的實現方式。
RxJavaCallAdapterFactory-->RxJava2CallAdapter 這裡我們看RxJava2CallAdapter的adapt()方法。
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
複製程式碼
我們看到但isAsync是非同步情況下時,new CallEnqueueObservable<>(call),建立了一個CallEnqueueObservable 物件,並將retrofit的okhttpCall繼續傳進來.
我們知道在RxJava,Observable的subscribe()觸發了程式碼執行的操作。來看:
@SchedulerSupport(SchedulerSupport.NONE)
@Override
public final void subscribe(Observer<? super T> observer) {
...
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//這裡建立一個okhttp3.Call的call物件
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 {
//這裡看到通過createRawCall() 建立返回了一個call
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//實際上就是通過okhttp3.call來請求
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 void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
private void callFailure(Throwable e) {
callback.onFailure(OkHttpCall.this, e);
}
private void callSuccess(Response<T> response) {
callback.onResponse(OkHttpCall.this, response);
...
}
}
複製程式碼
createRawCall()
private okhttp3.Call createRawCall() throws IOException {
[1] 建立一個request 請求物件
Request request = serviceMethod.toRequest(args);
[2]呼叫newCall(request)返回一個okhttp3.Call
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
複製程式碼
serviceMethod.toRequest(args)
Request toRequest(@Nullable Object... args) throws IOException {
//這裡new了一個requestBuilder 將我們獲取到的請求的相關資訊傳進去
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
//引數值解析
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
//這裡呼叫build()
return requestBuilder.build();
}
複製程式碼
下面看一下requestBuilder.build() 是如何建立一個request物件的
Request build() {
HttpUrl url;
HttpUrl.Builder urlBuilder = this.urlBuilder;
if (urlBuilder != null) {
url = urlBuilder.build();
} else {
// No query parameters triggered builder creation, just combine the relative URL and base URL.
//noinspection ConstantConditions Non-null if urlBuilder is null.
url = baseUrl.resolve(relativeUrl);
if (url == null) {
throw new IllegalArgumentException(
"Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
}
}
RequestBody body = this.body;
if (body == null) {
// Try to pull from one of the builders.
if (formBuilder != null) {
body = formBuilder.build();
} else if (multipartBuilder != null) {
body = multipartBuilder.build();
} else if (hasBody) {
// Body is absent, make an empty body.
body = RequestBody.create(null, new byte[0]);
}
}
MediaType contentType = this.contentType;
if (contentType != null) {
if (body != null) {
body = new ContentTypeOverridingRequestBody(body, contentType);
} else {
requestBuilder.addHeader("Content-Type", contentType.toString());
}
}
return requestBuilder
.url(url)
.method(method, body)
.build();
}
複製程式碼
接著看看call.enqueue()
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
複製程式碼
看client.dispatcher().enqueue(new AsyncCall(responseCallback));
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
//可以看到這裡執行了網路請求,並通過call完成返回請求結果的回撥。
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
複製程式碼
從上面可以看到,這裡最終是通過建立一個okHttp3.Call物件,構建出一個網路請求的Request,傳送網路請求,並呼叫了call.enqueue()最後將請求到的結果,返回到Retrofit的Callback物件。
package retrofit2;
public interface Callback<T> {
void onResponse(Call<T> call, Response<T> response);
void onFailure(Call<T> call, Throwable t);
複製程式碼
到這裡一個請求就結束了。
總結
梳理一下整個過程:
- 書寫我們的service請求介面,配置好請求路徑,請求方式,引數配置等。
- 構建我們自定義的convert ,convertAdapter 。
- 構建retrofit物件,並新增我們的convertFactory,converAdapterFactory等。
- 通過retrofit的create()動態代理實現service介面的實現類
- 解析 網路請求介面的註解 配置 網路請求引數
- 通過 網路請求介面卡 將 網路請求物件 進行平臺適配
- 通過 網路請求執行器 傳送網路請求
- 通過 資料轉換器 解析伺服器返回的資料
- 通過 回撥執行器 切換執行緒(子執行緒 ->>主執行緒)
- 最後使用者在主執行緒處理返回結果
參考文章
(參考使用了下面文章的部分內容與資源)