本文介绍 Retrofit 网络框架,包含简单的使用和源码解析。本文内容基于 Retrofit 2.4.0 版本。
Type-safe HTTP client for Android and Java by Square, Inc. http://square.github.io/retrofit/
前面介绍过 OkHttp ,Retrofit 是对 OkHttp 网络请求框架的封装,前者专注于接口的封装,后者专注于真正的网络请求。
应用程序通过 Retrofit 请求网络,实际上是由 Retrofit 接口层封装请求参数、Header、Url 等信息,由 OkHttp 完成实际的请求操作;在服务端返回数据后,OkHttp 将原始的结果交给 Retrofit,Retrofit 根据用户的需求对结果进行解析。
Retrofit 的简单使用
参考官网的介绍:
1、创建 HTTP API 接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
2、创建 Retrofit 实例,并实现接口实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
3、创建请求实例
Call<List<Repo>> call = service.listRepos("wshunli");
4、发送网络请求
// 同步请求
call.execute();
// 异步请求
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
Log.d(TAG, "onFailure: ");
}
});
和 OkHttp 流程差不多,特别是发送请求方法名字都没有变。
Retrofit 的源码分析
Retrofit 网络请求完整的流程图如下:
下面详细介绍。
创建 Retrofit 实例
Retrofit 实例化,也是使用的建造者模式。
我们先看 Builder 成员变量的含义:
// Retrofit#Builder
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> callAdapterFactories = new ArrayList<>();
// 回调方法执行器
private @Nullable Executor callbackExecutor;
// 标志位
private boolean validateEagerly;
1、首先构造函数中通过 Platform.get()
初始化了平台参数
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
Builder(Retrofit retrofit) {
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
converterFactories.addAll(retrofit.converterFactories);
// Remove the default BuiltInConverters instance added by build().
converterFactories.remove(0);
callAdapterFactories.addAll(retrofit.callAdapterFactories);
// Remove the default, platform-aware call adapter added by build().
callAdapterFactories.remove(callAdapterFactories.size() - 1);
callbackExecutor = retrofit.callbackExecutor;
validateEagerly = retrofit.validateEagerly;
}
我们可以看下判断方法:
// Platform
class 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) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
/* 省略部分无关代码 */
}
后面如果有需要,我们也可以直接拷贝。
2、然后设置 Retrofit 所需的参数即可
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(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;
}
/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
3、最后是 build() 方法
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// 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);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
创建 API 实例
获取 API 实例使用 Retrofit 的 create()
方法
// 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.adapt(okHttpCall);
}
});
}
创建 API 实例使用的是 动态代理 设计模式。
创建请求实例
创建请求实例,跟钱买你的动态代理有关。
// Retrofit#create()
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
1、loadServiceMethod()
方法
一个 ServiceMethod
对应于一个 API 接口的一个方法,loadServiceMethod()
方法负责加载 ServiceMethod
// Retrofit#loadServiceMethod()
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;
}
2、OkHttpCall
类
OkHttpCall
实现了 retrofit2.Call
,我们通常会使用它的 execute()
和 enqueue()
接口。
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
构造方法也没有什么好看的。
发送网络请求
发送网络请求其实也就是 OkHttpCall
类中的方法。
1、同步请求 使用 execute()
方法
// OkHttpCall#execute()
@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 {
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();
}
return parseResponse(call.execute());
}
这里就是 Retrofit 和 OkHttp 交互的核心了,分为三步:
(1)创建 okhttp3.Call
,包括构造参数
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
(2)执行网络请求,也就是 OkHttp 的同步网络请求
call.execute()
(3)解析返回的结果
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);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(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、异步请求 使用 enqueue()
方法
@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 {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
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) {
callFailure(e);
return;
}
try {
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 {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
我们可以看到和同步请求是一致的,实际请求交给了 okhttp3.Call#enqueue(Callback responseCallback)
来实现,并在它的 callback
中调用 parseResponse()
解析响应数据,并转发给传入的 callback
。
Retrofit 源码就先介绍到这里了,后面有机会再详细介绍。
参考资料
1、Retrofit分析-漂亮的解耦套路 - 简书
https://www.jianshu.com/p/45cb536be2f4
2、Android:手把手带你 深入读懂 Retrofit 2.0 源码 - 简书
https://www.jianshu.com/p/0c055ad46b6c
3、Retrofit源码分析(超详细) - 简书
https://www.jianshu.com/p/097947afddaf
4、拆轮子系列:拆 Retrofit - Piasy的博客 | Piasy Blog
https://blog.piasy.com/2016/06/25/Understand-Retrofit/
5、Retrofit源码解析 | mundane的幻想空间
https://mundane799699.github.io/2018/03/13/retrofit-analysis/
6、Retrofit源码解析 - 掘金
https://juejin.im/post/5acee62c6fb9a028df22ffee
7、Retrofit源码解析 | 俞其荣的博客 | Qirong Yu's Blog
https://yuqirong.me/2017/08/03/Retrofit源码解析/
8、android-cn/android-open-project-analysis
https://github.com/android-cn/android-open-project-analysis/tree/master/tool-lib/network/retrofit
9、【Android】Retrofit源码分析 - CSDN博客
https://blog.csdn.net/u010983881/article/details/79933220
评论