好的代码是自解释的,Retrofit 可以算是好的代码了。
Retrofit 的依赖图
一、无中生有:从接口方法到Request实例
ServiceMethod.java
将 API接口 中定义的方法方法转化为
HTTP
请求。接口中描述的方法是没有方法体的,所以最终执行的时候需要根据接口信息去组织特定的方法和对象,以产生可以执行的代码。
@Headers({
"X-Foo: Bar",
"X-Ping: Pong"
})
@POST("/abc")
Call<ResponseBody> getSomething(@Body String body);
ServiceMethod
虽然没有继承自 java.lang.reflect.Method
,但是同样提供了执行方法的途径。由内部类 Builder
中的 parseMethodAnnotation(Annotation annotation)
/*参见 Retrofit源码分析:方法注解*/ , parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody)
, parseHeaders(String[] headers)
, parseParameter(...)
, parseParameterAnnotation(...)
等方法来转换成一个“有血有肉”的 OkHttp 请求。
一段很有意思的代码:
- @Path 注解表示的 URL 不能和参数化查询混淆(形如
/{name}/address?type=home
)#294 ~ #303
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); //REGEX: {([a-zA-Z][a-zA-Z0-9_-])*}
if (queryParamMatcher.find()) {
throw methodError("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
RequestBuilder.java
负责构建
Request
对象的具体实现。分离职责
ServiceMethod
中有个 “根据方法参数构建 HTTP 请求” 的方法,就是把从接口方法中解析到的数据传到这里来创建请求的。目前只有构建 Request 实例的过程中用到了这个类。主要有下面这些方法,这些方法都是
ParameterHandler
在用。使用 IntelliJ / Android Studio 快捷键
alt+f7
可以快速查找依赖 (要把 作用域Scope 设置为 Project and Libraries )
ParameterHandler.java
负责处理参数,是具体实现。分离职责
里面有一些内部类:
RelativeUrl
,Header
,Path
,Query
,QueryName
,QueryMap
,HeaderMap
,Field
,FieldMap
,Part
,RawPart
,PartMap
和Body
等内部类。这些内部类都继承自
ParameterHandler
, 并重写了apply()
(也是唯一一个可供重写的方法)。这些类的实例供ServiceMethod
使用。目前只有构建 Request 实例的过程中用到了这个类。
二、 天堑变通途,Request 和 Response
Call.java
每次调用 Retrofit 方法会向服务器发起请求并得到一个响应。
在 Retrofit 中,仅有一个实现类:
OkHttpCall
。Retrofit 通过动态代理使用的也有一个类,即所有的 Retrofit中的所有接口方法使用的都是OkHttpCall
。见 Retrofit 中的public <T> T create(final Class<T> service)
方法。接口共有七个方法,
Response<T> execute()
、void enqueue(Callback<T> callback)
分别同步、异步发出请求;void cancle()
用来取消请求;boolean isExecuted()
、boolean isCanceled()
用来获取当前请求的状态;Retrofit 中每个请求只能执行一次,当需要轮询或者失败重传的时候,可以使用Call.clone()
来产生同样的请求;Request request()
可以获取生成的Request
对象(并没有执行request
,而是一个getter
方法,retrofit
中好多(可能是所有)getter
方法都是这种风格的,方法名不以get
开头)。
OkHttpCall.java
Call
的唯一实现类
execute
和 enqueue
的代码片段(一个 Call 只能执行一次):
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
execute
和 enqueue
函数的结构很相似,拿 enqueue
来说(移除了错误处理代码,并 inline
了部分函数):
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
call = rawCall; // rawCall 是全局变量
if (canceled) { call.cancel(); }
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse throws IOException {
Response<T> response = parseResponse(rawResponse);
}
callback.onResponse(OkHttpCall.this, response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
}
可以看到这个方法中进行了一次复制,使用原来的 call
并间接调用了 callback
。为什么要这样多此一举呢?这跟 Retrofit 请求道路的曲折性是分不开的。当 通过 OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args)
这个构造方法创建对象后,得到的 call 对象就是个简单的对象而已,无法完成网络请求,需要在内部通过callFactory
创建。
createRawCall
根据构造函数中传入的 args
, 创建新的 request
,并根据 request
创建 Call
(代码中出现的 callFactory
默认情况下是 Retrofit 创建的 ,真正的实例是 OkHttpClient
,这个类实现了 Call.Factory
接口 。OkHttpClient
中的实现是 return RealCall.newRealCall(this, request, false /* for web socket */)
。很明显,真正进行请求的是RealCall
,代码中的 rawCall
的类型一般情况就是 RealCall
啦!这也就说通了为什么会有这么一层包装,因为 OkHttpCall
就是个中间层!):
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;
}
解析响应 response
, 所有的分支都是 return Response.success/error(...)
的形式, Response
类中 success
和 error
的几个静态重载方法会返回带有泛型的 Response
。
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
// 不是所有的响应 body 都有意义,这里先把它拿掉
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) { // “非成功”状态码
try { //
ResponseBody bufferedBody = Utils.buffer(rawBody); // wtf…
return Response.error(bufferedBody, rawResponse); // 返回出错响应
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) { // 服务器成功处理了请求,没有返回任何内容。
rawBody.close();
return Response.success(null, rawResponse); // 返回成功响应,body 为 null
}
// 2xx but 204 205, 用到了之前取出的 body
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse); // 我们最关心的一行
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
Callback.java
对于绝大多数 Android开发者来说,这个接口是相当熟悉的。
onResponse
&onFailure
分别对应请求成功和失败
Response.java
对
okhttp3.Response
的一个简单封装包含一些
getter
方法(delegate)和几个用来创建Response
的静态方法(success
和error
的重载方法)。
三、Factory、Adapter、Converter
Converter.java
此接口包含了一个方法:
T convert(F value)
和一个抽象内部类Factory
。Factory
产生特定的Converter
。
Factory
有三个可供重写的方法:
responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit)
requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit)
返回处理 HTTP Request 的
Converter
,某种类型(在接口方法的声明中一般被Part
、Body
、PartMap
修饰)的对象 –> HTTP Request BodystringConverter(Type type, Annotation[] annotations, Retrofit retrofit)
返回将某种类型转化为
String
的Converter
,某种类型(在接口方法的声明中一般被Field/FieldMap
、Header/HeaderMap
、Query/QueryMap
、Path
修饰) –> String 。因为HTTP 1.1
的 URL / Body / Header 是建立在字符串上的
对于不能/不想处理的数据类型,直接返回 null 就可以了(这也是这些方法的默认实现)。Retrofit 将继续查找适用的
Converter
或者采用一个默认实现。
BuiltInConverters.java
- VoidResponseBodyConverter.class
- RequestBodyConverter.class
- StreamingResponseBodyConverter.class
- BufferingResponseBodyConverter.class
- ToStringConverter.class
CallAdapter.java
比如我们本来只能写返回
Call<Foo>
这样的方法,但是在CallAdapter
(RxJava2CallAdapterFactory
,'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
)的帮助下,我们可以写返回Observable<UsersResponse>
这种的方法。同样有个名为
Factory
的内部类
T adapt(Call<R> call); /* Call<R> --> Foo<R> */
返回一个真正执行(delegate,代理)这个 Call
的实例。比如:
@Override
public <R> Async<R> adapt(final Call<R> call) {
return Async.create(new Callable<Response<R>>() {
@Override
public Response<R> call() throws Exception {
return call.execute();
}
});
}
Type responseType();
举个简单的例子,如果接口声明的是 Call<Foo>
,那么这里应该返回 Foo
Retrofit 内置的两个
CallAdapter
,都有这样的代码:
if (getRawType(returnType) != Call.class) {
return null;
}
意味着默认情况下仅仅能处理 Call<Foo>
这种返回值的接口方法
DefaultCallAdapterFactory.java
创建那种
Adapter
,就是 I/O 和 Callback 执行在同一个线程上那种由于是这里的 I/O 几乎等于网络请求,所以 Android 一般情况下是不会用到这个的。
ExecutorCallAdapterFactory.java
这个类的
adapt(...)
方法将 call 外包给自己的内部类:ExecutorCallbackCall
看到这个
Executor
,em……, 没错,就是java.util.concurrent.Executor
!
四、Retrofit、Platform
##Retrofit.java
Retrofit , Retrofit, Retrofit
一切的入口,Retrofit 家的门面
- 构造函数
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly);
public Builder newBuilder()
em……
new Retrofit.Builder().build()
就是Retrofit
了 。public <T> T create(final Class<T> service)
根据接口信息使用反射生成对应的对象,要求
service.isInterface()
并且不能继承其他接口。
private void eagerlyValidateMethods(Class<?> service)
如果
validateEagerly
为true
,Retrofit将在反射之前来验证并加载接口中的方法。ServiceMethod<?, ?> loadServiceMethod(Method method)
将
java.lang.reflect.Method
加载为retrofit2.ServiceMethod
。callAdapter 相关
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations); public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations);
converter 相关
// a naive getter public List<Converter.Factory> converterFactories(); // 根据参数查找一个合适的 Converter public <T> Converter<T, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations); public <T> Converter<T, RequestBody> nextRequestBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations); public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations); public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations); public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations);
getters 相关
public HttpUrl baseUrl(); public okhttp3.Call.Factory callFactory(); public List<CallAdapter.Factory> callAdapterFactories(); public List<Converter.Factory> converterFactories(); public @Nullable Executor callbackExecutor();
简单看下
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)) { // 默认为 false,Android 下为 fasle
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 根据接口方法信息构建等价的 ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
// 根据 ServiceMethod 构建响应的 Call
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall); // 这里是个 Object, 如果接口方法返回值类型为Call<Foo>,则此返回值的类型为 Foo
}
});
}
Platform.java
不同的平台有不同的行为,上面提到的
adapter
和converter
等细节方面也是存在差异的。比如 Android 平台在系统层面上限制在 UI 线程上进行网络请求。这个类有两个内部类:
Java8 extends Platform
和Android extends Platform
对于 Java8,跟 callback 有关的是默认实现:
@Nullable Executor defaultCallbackExecutor() {
return null; // 没有回调 Executor
}
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) { // false
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE; // 所以使用的是 DefaultCallAdapterFactory
}
而对于 Android,对应的实现则是这样的:
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor(); // 有回调 Executor
}
@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) {
// Callback 在 UI 线程上执行 ,
// 不然可能就 android.view.ViewRoot$CalledFromWrongThreadException:
// Only the original thread that created a view hierarchy can touch its views.
handler.post(r);
}
}
对着代码中嵌入的文档,和胡猜各种命名,终于把这个项目捋下来了。
可能是市面上相当详细全面的一篇了,当然很多地方还是不够详细。因为代码实在是不少,贴进来肯定是一篇“巨作”。但是结构还算清晰,如果你也感兴趣,打开你的 Android Studio / IntelliJ Idea 也来看看吧!
Ref:
via boileryao
Happy coding :)