文章首发于个人我的博客:wildma的博客,这里有更好的阅读体验,欢迎关注。html
最近有个想法——就是把 Android 主流开源框架进行深刻分析,而后写成一系列文章,包括该框架的详细使用与源码解析。目的是经过鉴赏大神的源码来了解框架底层的原理,也就是作到不只要知其然,还要知其因此然。java
这里我说下本身阅读源码的经验,我通常都是按照平时使用某个框架或者某个系统源码的使用流程入手的,首先要知道怎么使用,而后再去深究每一步底层作了什么,用了哪些好的设计模式,为何要这么设计。android
系列文章:git
更多干货请关注 AndroidNotesgithub
(1)建立网络请求接口:json
public interface PostmanService {
@GET("get")
Call<PostmanGetBean> testGet();
}
复制代码
(2)建立 Retrofit 的实例:设计模式
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
复制代码
(3)建立网络请求接口的实例,并调用接口中的方法获取 Call 对象:数组
PostmanService service = retrofit.create(PostmanService.class);
Call<PostmanGetBean> call = service.testGet();
复制代码
(4)进行网络请求缓存
Response<PostmanGetBean> response = call.execute();
复制代码
同步请求与异步请求惟一不一样的就是第 (4) 步,前者使用同步方法 execute(),后者使用异步方法 enqueue()。异步请求的第(4)步以下:服务器
call.enqueue(new Callback<PostmanGetBean>() {
@Override
public void onResponse(Call<PostmanGetBean> call, Response<PostmanGetBean> response) {
}
@Override
public void onFailure(Call<PostmanGetBean> call, Throwable t) {
}
});
复制代码
更多 Retrofit 的使用方法能够看我以前写的文章 Retrofit 使用详解 接下来咱们就根据这 4 步进行源码阅读。
源码版本:2.5.0
public interface PostmanService {
@GET("get")
Call<PostmanGetBean> testGet();
}
复制代码
这一步比较简单,只是建立一个接口,接口中包含一个带注解的方法。这里没有什么源码好讲的,咱们放到后面结合第(3)步再一块儿讲。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
复制代码
首先咱们点击 Retrofit 对象进去有以下常量:
/*Retrofit*/
// ServiceMethod 缓存,用来存储网络请求相关的配置,例如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
// 网络请求器工厂
final okhttp3.Call.Factory callFactory;
// 网络请求的 url 地址
final HttpUrl baseUrl;
// 数据转换器工厂的集合
final List<Converter.Factory> converterFactories;
// 网络请求适配器工厂的集合
final List<CallAdapter.Factory> callAdapterFactories;
// 回调方法执行器
final @Nullable Executor callbackExecutor;
// 一个标志位,用来判断是否须要加载 ServiceMethod
final boolean validateEagerly;
复制代码
这些常量除了 serviceMethodCache,其他均可以经过建造者模式进行配置,例如 baseUrl 能够经过 baseUrl() 方法配置。
而后再看下 Builder() 方法:
/*Retrofit-Builder*/
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
复制代码
Builder() 方法中调用了 Platform 类的 get() 方法,get() 方法中又调用了 findPlatform() 方法,以下:
/*Platform*/
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
// Android 平台
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
// Java 平台
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
复制代码
能够看到,Builder() 方法主要是用来查找当前运行的平台,Retrofit 支持 Android 与 Java 平台。
最后再看看 build() 方法:
/*Retrofit*/
public Retrofit build() {
//(1)
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//(2)
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//(3)
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//(4)
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//(5)star
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// 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());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
//(5)end
//(6)
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
复制代码
源码中我标注了 6 个关注点,分别以下:
/*Platform*/
@Nullable Executor defaultCallbackExecutor() {
return null;
}
复制代码
因为运行在 Android 平台,因此跳转到 Platform 的实现类 Android 中的 defaultCallbackExecutor() 方法:
/*Platform-Android*/
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
复制代码
继续跟进到 MainThreadExecutor() :
/*Platform-Android*/
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
复制代码
能够看到,这里经过建立一个主线程的 Handler 来将线程从子线程切换到主线程,这样后面从服务器拿到数据就是在主线程了,就能够直接进行 UI 相关操做了。
小结: 这一步使用了建造者模式去建立 Retrofit 的实例,建立的过程当中主要配置了网络请求器工厂(callFactory)、网络请求的 url 地址(baseUrl)、数据转换器工厂的集合(converterFactories)、网络请求适配器工厂的集合(callAdapterFactories)、回调方法执行器(callbackExecutor)。这里使用建造者模式的好处是不须要知道 Retrofit 内部是怎么建立的,只须要传入对应的配置便可建立很是复杂的对象。
PostmanService service = retrofit.create(PostmanService.class);
Call<PostmanGetBean> call = service.testGet();
复制代码
首先咱们点击 create() 方法进去源码是这样的:
/*Retrofit*/
public <T> T create(final Class<T> service) {
// 验证传进来的 service(service 必须是一个接口,而且不能继承其余接口,不然抛出异常)
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//(1)Proxy.newProxyInstance()
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
//(2)invoke()
@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.
//(3)
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//(4)
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//(5)
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
复制代码
注意:其实关注点(1)中执行 Proxy 的 newProxyInstance() 方法就已经建立了网络请求接口的实例, create() 方法的调用并不会继续执行关注点(2)中的 invoke() 方法。调用网络请求接口中的方法(例如例子中 service.testGet())的时候才会执行 invoke() 方法。
咱们继续看例子中的第二行代码:
Call<PostmanGetBean> call = service.testGet();
复制代码
这行代码的意思就是调用接口中的方法获取 Call 对象,其实这里调用 testGet() 方法才是刚开始执行上面动态代理中的 invoke() 方法,因此咱们继续分析其余关注点吧!
咱们先点击 loadServiceMethod() 方法进去看看:
/*Retrofit*/
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
复制代码
首先会从 ServiceMethod 缓存集合中取出当前方法对应的 ServiceMethod,若是不为空,则直接返回。若是为空,则使用单例模式建立一个新的 ServiceMethod,即调用 parseAnnotations() 方法建立,而后再存到缓存集合中。
咱们点击 parseAnnotations() 方法进去看看:
/*ServiceMethod*/
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//(6)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//(7)
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
复制代码
/*RequestFactory*/
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
复制代码
这里使用了建造者模式,Builder 的构造函数只是一些简单的赋值,以下:
/*RequestFactory-Builder*/
Builder(Retrofit retrofit, Method method) {
// Retrofit 对象
this.retrofit = retrofit;
// 方法
this.method = method;
// 方法注解
this.methodAnnotations = method.getAnnotations();
// 参数类型
this.parameterTypes = method.getGenericParameterTypes();
// 参数注解数组
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
复制代码
继续看看 build() 方法:
/*RequestFactory-Builder*/
RequestFactory build() {
//(6.1)
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 省略部分判断...
//(6.2)
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}
// 省略部分判断...
//(6.3)
return new RequestFactory(this);
}
复制代码
能够看到,关注点(6.1)中的 for 循环是用来解析方法上的注解,例如 @GET、@HTTP、@Headers 等等注解。关注点(6.2)中的 for 循环是用来解析方法上的参数的。执行到关注点(6.3)说明网络请求接口中的注解已经解析出来了,而后建立 RequestFactory 对象并进行赋值后返回,以下:
/*RequestFactory*/
RequestFactory(Builder builder) {
// 方法,对应例子中是 testGet()
method = builder.method;
// baseUrl,对应例子中是 https://postman-echo.com/
baseUrl = builder.retrofit.baseUrl;
// http 方法,对应例子中是 GET 请求
httpMethod = builder.httpMethod;
// 相对路径,对应例子中是 get
relativeUrl = builder.relativeUrl;
// 请求头,没有设置,默认为 null
headers = builder.headers;
// contentType,没有设置,默认为 null
contentType = builder.contentType;
// hasBody,没有设置,默认为 false
hasBody = builder.hasBody;
// isFormEncoded,没有设置,默认为 false
isFormEncoded = builder.isFormEncoded;
// isMultipart,没有设置,默认为 false
isMultipart = builder.isMultipart;
// 参数数组,例子中没有传参数,因此为 null
parameterHandlers = builder.parameterHandlers;
}
复制代码
/*HttpServiceMethod*/
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 根据网络请求接口中的返回类型与注解获取相对应的网络请求适配器(CallAdapter)
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
// 获取响应类型,对应例子中是 PostmanGetBean
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
// 根据网络请求接口中的返回类型与注解获取相对应的数据转换器(Converter)
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
// 获取网络请求器工厂(okhttp3.Call.Factory)
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
复制代码
能够看到,该方法主要是用来获取相对应的网络请求适配器(CallAdapter)、数据转换器(Converter)与网络请求器工厂(okhttp3.Call.Factory),对应例子中分别是 ExecutorCallAdapterFactory、GsonConverterFactory 与 OkHttpClient。最后再经过这些来建立 HttpServiceMethod 对象进行返回,HttpServiceMethod 继承自 ServiceMethod,因此能够转成 ServiceMethod。
loadServiceMethod() 方法拿到 ServiceMethod 对象后继续回去看关注点(5)中剩下的:
/*Retrofit*/
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
复制代码
这里调用了 invoke() 方法,点击进去是调用了 ServiceMethod 的 invoke() 方法,而后在子类 HttpServiceMethod 中实现,具体以下:
/*ServiceMethod*/
abstract T invoke(Object[] args);
/*HttpServiceMethod*/
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
复制代码
能够看到,这里调用了 CallAdapter 的 adapt() 方法,参数是建立了一个 OkHttpCall 对象,OkHttpCall 对象的建立只是一些简单的赋值,就不贴代码了。上面已经说了,CallAdapter 对应例子中就是 ExecutorCallAdapterFactory,因此点击 adapt() 方法进去看看:
/*ExecutorCallAdapterFactory*/
@Nullable
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
} else {
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
public Type responseType() {
return responseType;
}
// 关注点
public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
}
};
}
}
复制代码
能够看到关注点中 adapt() 方法返回的是 ExecutorCallbackCall,而 ExecutorCallbackCall 实现了 Call 接口,这样就获取了 Call 对象了,就能够愉快的调用 execute() 与 enqueue() 方法进行网络请求了。
小结:
这里使用动态代理的好处是能够将网络请求接口的全部方法的调用都会集中转发到 InvocationHandler 接口的 invoke() 方法中,方便集中进行处理。
进行网络请求能够分为同步请求与异步请求,下面分别对这两种请求方式进行分析。
Response<PostmanGetBean> response = call.execute();
复制代码
上面已经知道了 call 为 ExecutorCallbackCall 类型的 Call 接口,点击 execute() 方法进去看看:
/*ExecutorCallAdapterFactory-ExecutorCallbackCall*/
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
复制代码
这里的 delegate 实际为 OkHttpCall,点击这里的 execute() 方法进去看看:
/*OkHttpCall*/
@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 if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
//(1)
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//(2)
return parseResponse(call.execute());
}
复制代码
/*OkHttpCall*/
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
复制代码
能够看到,这里经过 requestFactory.create(args) 构建一个 Request 对象,而后再经过 OkHttpClient 的 newCall() 方法去建立 call。关于 newCall() 怎么建立 call,这个在讲 Android 主流开源框架(三)OkHttp 源码解析 已经讲过了,这里就不展开来说了。
咱们继续看下 create() 方法:
/*RequestFactory*/
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
复制代码
能够看到,这里的 httpMethod(http 方法)、baseUrl、relativeUrl(相对路劲)、headers(请求头)等常量就是前面第(3)步中经过解析网络请求接口注解获得的,经过这些常量就能够构建一个 Request 了。
接下来就是解析响应回来的数据了,点击 parseResponse() 方法进去看看:
/*OkHttpCall*/
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) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// (2.1)
T body = responseConverter.convert(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;
}
}
复制代码
前面那些状态码的检查等就很少说了,咱们直接看下关注点(2.1),是的,这里就是经过咱们设置的 Converter 将响应的数据解析成相应的实体类返回的。咱们看下 convert() 方法:
/*GsonResponseBodyConverter*/
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
复制代码
很简单,就是经过 Gson 将响应数据解析成相应的实体类返回。
call.enqueue(new Callback<PostmanGetBean>() {
@Override
public void onResponse(Call<PostmanGetBean> call, Response<PostmanGetBean> response) {
}
@Override
public void onFailure(Call<PostmanGetBean> call, Throwable t) {
}
});
复制代码
点击 enqueue() 方法进去看看:
/*ExecutorCallAdapterFactory-ExecutorCallbackCall*/
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//(1)
delegate.enqueue(new Callback<T>() {
//(2)
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
//(3)
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
复制代码
/*OkHttpCall*/
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
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 {
//(1.1)
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//(1.2)
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//(1.3)
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
//(1.4)
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
//(1.5)
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
复制代码
小结: 这一步的同步与异步请求其实底层分别调用的是 OkHttp 的同步与异步请求方法,而后经过咱们设置的数据转换器(Converter)将响应的数据解析成相应的实体类返回。同步请求会直接返回,异步请求则会切换到主线程再进行返回。
参考资料: