前言
前一篇分析了OkHttp的源码和流程,这一篇依然从Retrofit的使用角度并结合源码来分析,当然Retrofit是基于OkHttp的,所以OkHttp源码-流程-拦截器分析还是有必要了解的,而且Retrofit中使用了很多的设计模式,需要提前预览。
-
在开始流程前需要先看一下整体的流程图以及设计模式,这里就用了之前的Stay的Retrofit源码流程图,虽然更新了很多版本,但主要部分还是没变化的,看完这图,结合代码,最后再看图,再自己看源码总结,会更好理解的。
Retrofit流程图
基本使用流程
1.定义一个请求接口,包含请求方法
interface Api {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user:String):Call<List<Repo>>
}
2.使用retrofit请求
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
val api = retrofit.create(Api::class.java)
val call = api.listRepos("")
call.execute()
call.enqueue(object :retrofit2.Callback<List<Repo>> {
override fun onFailure(call: retrofit2.Call<List<Repo>>, t: Throwable) {}
override fun onResponse(call: retrofit2.Call<List<Repo>>, response: retrofit2.Response<List<Repo>>) {}
})
一、构建Retrofit实例
先来看看Retrofit中的成员变量
//解析接口注解后相关信息的存储
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
//请求工厂、默认为OkHttpClient
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
//数据转换器工厂的集合,例如Gson转换
final List<Converter.Factory> converterFactories;
//网络请求适配器的集合
final List<CallAdapter.Factory> callAdapterFactories;
//回调执行器,在Android平台上就是通过Handler切换线程
final @Nullable Executor callbackExecutor;
//用来判断是否立即对我们的请求方法进行解析
final boolean validateEagerly;
1.Builder()方法
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
1.1.Platform.get() 获取当前平台,一般是Android,当然也支持其他平台比如Java8等
class Platform {
private static final Platform PLATFORM = findPlatform();
//通过findPlatfrom()获取平台信息
static Platform get() {
return PLATFORM;
}
//比较SDK版本 不空就返回Android平台
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
return new Platform(true);
}
...
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//通过Handler切换到主线程
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
2.baseUrl() 将String类型的URL转换为请求用的URL
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
3.addConverterFactory(GsonConverterFactory.create()) 添加转换器
//主要就是创建带Gson对象的转换工厂
GsonConverterFactory.create()
//将带有Gson的转换器工厂添加到集合中
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
4.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
添加一个请求的适配器工厂最后添加到Builde中的变量中,通过设计模式,像现在支持Kotlin的协程,也只需要切换工厂即可
5.build() 完成创建Retrofit实例
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//一般不设置的话 就是默认OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//这里其实就是MainThreadExecutor()
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
....
//创建了Retrfit 为前面的变量赋值
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
二、创建接口实例
val api = retrofit.create(Api::class.java)
这部分用了动态代理、外观模式创建了接口实例,以下是源码
public <T> T create(final Class<T> service) {
//1.主要做了一些验证比如是否接口以及是否需要提前缓存ServiceMethod对象
validateServiceInterface(service);
//2.代理接口中的方法
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable 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);
}
//3.关键方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
ServiceMethod<?> loadServiceMethod(Method 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 = ServiceMethod.parseAnnotations(this, method);
//将解析出的信息添加到ConcurrentHashMap中供之后用
serviceMethodCache.put(method, result);
}
}
return result;
}
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析接口中的方法
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
// ...中间做了些验证 省略了
//将接口方法的调用调整为HTTP请求
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
- 具体的解析 RequestFactory parseAnnotations(Retrofit retrofit, Method method)
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//获取注解
this.methodAnnotations = method.getAnnotations();
//获取参数类型
this.parameterTypes = method.getGenericParameterTypes();
//获取注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
//循环解析注解
parseMethodAnnotation(annotation);
}
...
return new RequestFactory(this);
}
- static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory)
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
//1.从Retrofit.java中的callAdapterFactories集合中获取对应的请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
...
//2.从Retrofit.java中的converterFactories集合中获取对应的数据转换器
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//检查是否kotlin协程中挂起的函数
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
...
}
- 最终还是转接到OkHttp的Call
// loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
三、同/异步请求数据
同步请求call.execute()
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
...
call = rawCall;
if (call == null) {
try {
//1.这里创建了OkHttp的call
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.解析OkHttp请求回来的数据
return parseResponse(call.execute());
}
//callFactory就是OkHttpClient
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;
}
//将OkHttp请求回的Response做解析
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
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 {
// 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 {
//通过之前的赋值的转换器 将数据转为具体类型
T body = responseConverter.convert(catchingBody);
//封装到Response中返回
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
异步请求call.enqueue(Callback<T> callback)
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(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 {
//依旧是使用了OkHttp的Call
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//依旧是使用了OkHttp的同步请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
看到这里基本上的整体流程也就差不多了 再结合开头的图会比较清晰一点,如果自己能看一遍源码,那你的理解会更深一个层次。
总结
总的来说,Retrofit是基于OkHttp的二次封装,通过动态代理将数据请求转接于OkHttp请求并通过使用设计模式做到了低耦合,高扩展性,使用方便的网络请求框架,它其中很多的点值得我们去揣摩,学习,并且运用到我们自己的项目中。
最后
- 如果文中如果有什么纰漏欢迎讨论与指出。
- 参考
Retrofit分析-漂亮的解耦套路
Android主流三方库源码分析(二、深入理解Retrofit源码)
网友评论