带你认识Retrofit是如何封装Okhttp的
主题
我们本次讨论的主题如下:
- retrofit使得okhttp的使用更加便利。
- retrofit如何封装okhttp。
背景
- Retrofit是什么?
Retrofit 是一个RESTful 的HTTP 网络请求框架的封装。网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装。

上图说明了如下几点:
- App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息(稍后会解释),之后由 OkHttp 完成后续的请求操作。
- 在服务端返回数据之后,Okhttp将原始的结果交给 Retrofit, Retrofit根据用户的需求对结果进行解析。
- okhttp的用法和retrofit的用法
okhttp的用法可以参考下面这篇博客,里面列举了一个简单的例子:Android开源框架之okhttp
retrofit的用法可以参考下面这篇博客,里面列举了一个简单的例子:
Android开源框架之Retrofit
二者的构建流程可参考下图

现在我们知道了上述的背景知识之后,我们就可以进入本文的主题了。
疑问
- okhttp有什么不足之处?
okhttp已经很强大了,为什么Android的大神们还要设计出retrofit这个框架呢?通过上述okhttp的使用案例,我们可以知道,okhttp虽然强大,但是还是有几个使用上的不便利之处的:
- okhttp只是拿到了服务器返回来的数据,一般都是json,但是我们在写代码的时候一般都是Gson来解析json字符串并将其映射到一个bean映射中,而okhttp并没有做到这一点,需要我们拿到数据之后手动映射;而retrofit则不然,在构建retrofit实例的时候传入一个gson适配器即可对所有的请求进行json解析与映射。
- 使用okhttp进行同步请求的时候必须要开子线程的,异步请求就不需要,因为异步请求里面使用了线程池。而客户端一般拿到服务端返回的数据之后大都会更新ui,这就意味着我们需要进行线程间的切换,使用上不是很便利,而retrofit内部就已经进行了线程间的切换,我们拿到数据之后就已经是在主线程了。
- 这一点是我从其他资料上查找到,Retrofit 接口层封装请求参数、Header、Url 等信息。retrofit只需要把请求的参数写入接口中,不需要向okhttp那样把请求的参数传入post方法中。但是,我个人觉得这点其实优化的不是很明显,用起来感觉都是差不多便利的。
基于上述这三点,我们可以清楚得知道retrofit使得okhttp的使用更加的便利。
接下来,我们进入第下一个主题:retrofit如何封装okhttp。
首先,我先看下构建Retrofit对象的代码:很简单,就是一个建造者模式,通过builder为retrofit配置各种需要的数据。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())//配置Gson转换器
.build();
我们进入build方法看下做了什么事情?
public Retrofit build() {
if (this.baseUrl == null) {
throw new IllegalStateException("Base URL required.");
} else {
Factory callFactory = this.callFactory;
//如果在构建时没有设置callFactory,默认是使用OkHttpClient
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//如果在构建时没有设置callbackExecutor,会使用默认的callbackExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = this.platform.defaultCallbackExecutor();
}
List<retrofit2.CallAdapter.Factory> callAdapterFactories = new ArrayList(this.callAdapterFactories);
callAdapterFactories.addAll(this.platform.defaultCallAdapterFactories(callbackExecutor));
List<retrofit2.Converter.Factory> converterFactories = new ArrayList(1 + this.converterFactories.size() + this.platform.defaultConverterFactoriesSize());
//先加入BuiltInConverters到转换器工厂中,然后再加入我们设置的,最后再加入默认的转换器
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(this.platform.defaultConverterFactories());
return new Retrofit((Factory)callFactory, this.baseUrl, Collections.unmodifiableList(converterFactories), Collections.unmodifiableList(callAdapterFactories), callbackExecutor, this.validateEagerly);
}
}
从上述代码可以看到,我们在构建retrofit对象时可以不用设置callFactory、callbackExecutor、callAdapterFactories和converterFactories,因为源码中会帮助我们初始化一个默认的,但是我们一般都会添加一个gson转换器进行json解析。至此,build方法的源码分析完毕。
我们重点看下builder里面的各种成员变量分别是什么意思
public static final class Builder {
private final Platform platform;
@Nullable
private Factory callFactory;
@Nullable
private HttpUrl baseUrl;
private final List<retrofit2.Converter.Factory> converterFactories;
private final List<retrofit2.CallAdapter.Factory> callAdapterFactories;
@Nullable
private Executor callbackExecutor;
private boolean validateEagerly;
}
重要的就是下面这几个
- callFactory:网络请求工厂,一般我们如果要添加拦截器可以在这个添加
- baseUrl:服务器域名,这个需要我们在创建时配置上去
- converterFactories:数据转换器工厂的集合
- callAdapterFactories:网络请求适配器工厂的集合,如果不想使用retrofit提供的call,想要自定义自己的call则要继承CallAdapter.Factory类才行。
- callbackExecutor:回调方法执行器。笔者都是使用默认的没自定义过
接下来,我们看下retrofit中一个十分重要的方法——create方法。
public <T> T create(final Class<T> service) {
this.validateServiceInterface(service);
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
} else {
args = args != null ? args : this.emptyArgs;
//是否是平台默认的方法,是的话就使用平台默认的方法,否则就执行loadServiceMethod方法
return this.platform.isDefaultMethod(method) ? this.platform.invokeDefaultMethod(method, service, proxy, args) : Retrofit.this.loadServiceMethod(method).invoke(args);
}
}
});
}
这个方法接收一个class类型的参数,然后通过动态代理返回该class的一个代理类。而当我们通过该代理类执行相关的方法时,就会回调到invoke方法中。
例如:
public interface GitHubService {
//配置GET请求和URL路径
@GET("users/{user}/repos")
//返回为Call<T>对象,泛型T表示网络解析后结果的类型
//@Path("user")注解表示参数user会替换URL路径中的{user}
Call<List<Repo>> listRepos(@Path("user") String user);//返回值必须声明成Retrofit中内置的Call类型,并通过泛型来指定服务器响应的数据应该装换成什么对象。
}
//使用Retrofit对象返回一个GitHubService的实现
GitHubService gitHubService = retrofit.create(GitHubService.class);
//在oncreate方法中添加下述代码
Call<List<Repo>> octocat = gitHubService.listRepos("octocat");//回调到invoke方法中
而invoke方法中看名字似乎返回了一个与method相关的对象。我们看下loadServiceMethod方法究竟做了什么事情。
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = (ServiceMethod)this.serviceMethodCache.get(method);
if (result != null) {
return result;
} else {
synchronized(this.serviceMethodCache) {
result = (ServiceMethod)this.serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
this.serviceMethodCache.put(method, result);
}
return result;
}
}
}
这段代码大体就是如果cache中有该方法就从cache中拿,否则就进入parseAnnotations方法,我们看下parseAnnotations方法做了什么事情。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});
} else if (returnType == Void.TYPE) {
throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);
} else {
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
}
首先,它会调用RequestFactory类的parseAnnotations方法,解析我们在接口定义中使用到的注解。RequestFactory类里面是对一些注解进行解析,我个人认为不需要太多关注,最后会将RequestFactory.parseAnnotations方法返回值传入HttpServiceMethod.parseAnnotations方法中。我们看下HttpServiceMethod.parseAnnotations方法做了什么事情。
注意:方法的入参数以及返回值。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Object adapterType;
Type responseType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
responseType = Utils.getParameterLowerBound(0, (ParameterizedType)parameterTypes[parameterTypes.length - 1]);
if (Utils.getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
responseType = Utils.getParameterUpperBound(0, (ParameterizedType)responseType);
continuationWantsResponse = true;
}
adapterType = new ParameterizedTypeImpl((Type)null, Call.class, new Type[]{responseType});
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//上面的代码个人觉得基本可以忽略不看,我们应该重点关注requestFactory, callFactory, responseConverter, callAdapter这四个参数,应该它们与返回值有关系。
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, (Type)adapterType, annotations);
responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw Utils.methodError(method, "'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?", new Object[0]);
} else if (responseType == Response.class) {
throw Utils.methodError(method, "Response must include generic type (e.g., Response<String>)", new Object[0]);
} else if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw Utils.methodError(method, "HEAD method must use Void as response type.", new Object[0]);
} else {
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new HttpServiceMethod.CallAdapted(requestFactory, callFactory, responseConverter, callAdapter);
} else {
return (HttpServiceMethod)(continuationWantsResponse ? new HttpServiceMethod.SuspendForResponse(requestFactory, callFactory, responseConverter, callAdapter) : new HttpServiceMethod.SuspendForBody(requestFactory, callFactory, responseConverter, callAdapter, continuationBodyNullable));
}
}
}
上面的源码中有下面2个方法需要注意一下:
- createCallAdapter方法
该方法最终会迭代callAdapterFactories,如果有一个callAdapter就返回,否则会抛出异常。 - createResponseConverter方法
该方法最终会迭代converterFactories,如果有一个converter就返回,否则会抛出异常。
我们接着进入CallAdapted方法一探究竟。
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return this.callAdapter.adapt(call);
}
}
里面有点价值的就是adapt方法。但是别忘记了在Retrofit类的create方法的最后面是调用了invoke方法
Retrofit.this.loadServiceMethod(method).invoke(args);
而CallAdapted类是继承HttpServiceMethod类,HttpServiceMethod类中刚好有个invoke方法,里面调用了adapt方法。我们接着进入adapt方法看下。

发现是一个接口,我们很自然找到它的实现类,那我们应该找哪个实现类呢?记不记得我们在构建Retrofit类时会默认添加一个callAdapter到callAdapterFactories工厂中,这个就是DefaultCallAdapterFactory。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package retrofit2;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
import okhttp3.Request;
import okio.Timeout;
import retrofit2.CallAdapter.Factory;
//如果想要自定义call,可以参考该类
final class DefaultCallAdapterFactory extends Factory {
@Nullable
private final Executor callbackExecutor;
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
//在迭代callAdapterFactory时,会调用到get方法,而get方法就调用跑了adapt方法
@Nullable
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//必须要先判断是否是想要的call类型
if (getRawType(returnType) != Call.class) {
return null;
} else if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
} else {
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
//判断是否使用了SkipCallbackExecutor注解,如果使用了就将executor赋值为null,否则就使用this.callbackExecutor
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
public Type responseType() {
return responseType;
}
public Call<Object> adapt(Call<Object> call) {
//只要没有使用SkipCallbackExecutor注解,就执行默认的executor
return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
//至此,我们可以知道动态代理返回的是一个ExecutorCallbackCall对象,当我们调用enqueue方法或execute方法时,调用的是ExecutorCallbackCall对象的对象方法
}
};
}
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
this.delegate.enqueue(new Callback<T>() {
public void onResponse(Call<T> call, Response<T> response) {
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
if (ExecutorCallbackCall.this.delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
public void onFailure(Call<T> call, Throwable t) {
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
callback.onFailure(ExecutorCallbackCall.this, t);
});
}
});
}
public boolean isExecuted() {
return this.delegate.isExecuted();
}
public Response<T> execute() throws IOException {
return this.delegate.execute();
}
public void cancel() {
this.delegate.cancel();
}
public boolean isCanceled() {
return this.delegate.isCanceled();
}
public Call<T> clone() {
return new DefaultCallAdapterFactory.ExecutorCallbackCall(this.callbackExecutor, this.delegate.clone());
}
public Request request() {
return this.delegate.request();
}
public Timeout timeout() {
return this.delegate.timeout();
}
}
}
上述中,我们知道了动态代理最终返回了ExecutorCallbackCall对象给我们,那么ExecutorCallbackCall对象时什么呢?记不记得,我们在构建retrofit对象时,有一个callbackExecutor方法,ExecutorCallbackCall对象就是在这个被赋值的。我们具体看下里面是怎么实现的


呃,怎么是个null呢?这样的话按照我们上面的分析,它是不会使用ExecutorCallbackCall对象的。别急,我们看下它的子类是怎么实现的就知道了。
static final class Android extends Platform {
Android() {
super(VERSION.SDK_INT >= 24);
}
public Executor defaultCallbackExecutor() {
return new Platform.Android.MainThreadExecutor();
}
@Nullable
Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
if (VERSION.SDK_INT < 26) {
throw new UnsupportedOperationException("Calling default methods on API 24 and 25 is not supported");
} else {
return super.invokeDefaultMethod(method, declaringClass, object, args);
}
}
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
MainThreadExecutor() {
}
public void execute(Runnable r) {
this.handler.post(r);
}
}
}
哦!原来,retrofit底层也是通过handler进行线程间的切换的。这样,我们拿到服务端返回值之后就自动切换到主线程了。
最后
本文中使用的retrofit的版本是2.9.0,如果使用其他版本,可能有些地方会不一致但是思想大体都是一样的。
感谢各位,看到最后!!!
更多推荐
所有评论(0)