Retrofit是一个基于AOP思想,对RestfulApi注解进行动态代理的网络框架;
一.基本用法
1.定义接口
public interface INetApiService {
@GET("/demobiz/api.php")
Call<BizEntity> getBizInfo(@Query("id") String id);
}
在这个接口定义中,用注解@GET("/demobiz/api.php")声明了url路径,用注解@Query("id") 声明了请求参数;
最重要的是,用Call声明了返回值是一个Retrofit的Call对象,并且声明了这个对象处理的数据类型为BizEntity,BizEntity是我们自定义的数据模型;
2.依次获得Retrofit对象、接口实例对象、网络工作对象
//新建一个Retrofit对象
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(Config.DOMAIN)//要访问的网络地址域名,如http://www.zhihu.com
.addConverterFactory(GsonConverterFactory.create())
.build();
...
//用retrofit加工出对应的接口实例对象
INetApiService netApiService= retrofit.create(INetApiService.class);
//可以继续加工出其他接口实例对象
IOtherService otherService= retrofit.create(IOtherService.class);
···
//调用接口函数,获得网络工作对象
Call<BizEntity> callWorker= netApiService.getBizInfo("id001");
这个复杂的过程下来,最终得到的callWorker对象,才可以执行网络访问。
3.访问网络
用上一步获取的worker对象,执行网络请求
callWorker.enqueue(new Callback<BizEntity>() {
@Override
public void onResponse(Call<BizEntity> call, Response<BizEntity> response) {...}
@Override
public void onFailure(Call<BizEntity> call, Throwable t) {...}
});
在回调函数里,取得我们需要的BizEntity数据对象
二、原理浅析
1.retrofit.create(interface)
Retrofit对象的构建就是简单的builder模式,直接看create
//Retrofit.java
public <T> T create(final Class<T> service) {
//验证
validateServiceInterface(service);
return (T)
//动态代理
Proxy.newProxyInstance(
service.getClassLoader(), //类加载器
new Class<?>[] {service}, //一组接口
new InvocationHandler() {
//判断android和jvm平台及其版本
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object[] args){
//如果该方法是Object的方法,直接执行不用管
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//isDefaultMethod:检查是否是java8开始支持的接口默认方法
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args); //我们关注这里
}
});
}
Proxy.newProxyInstance动态代理,运行期会生成一个类(字节码)如$ProxyN,实现传入的接口即WanApi,重写接口方法然后转发给InvocationHandler的invoke
class $ProxyN extends Proxy implements WanApi{
Call<WanArticleBean> articleList(@Path("page") int page){
//转发给invocationHandler
invocationHandler.invoke(this,method,args);
}
}
1.1.validateServiceInterface验证逻辑
//Retrofit.java
private void validateServiceInterface(Class<?> service) {
//检查:WanApi不是接口就抛异常...
//检查:WanApi不能有泛型参数,不能实现其他接口...
if (validateEagerly) { //是否进行严格检查,默认关闭
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) { //遍历WanApi方法
//不是默认方法,并且不是静态方法
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
//把方法提前加载进来(检查下有没有问题)
loadServiceMethod(method);
}
}
}
}
如果开了validateEagerly,会一次性把接口WanApi的所有方法都检查一遍并加载进来,可以在debug模式下开启,提前发现错误写法,比如在@GET请求设置了@Body这种错误就会抛出异常:
java.lang.IllegalArgumentException: Non-body HTTP method cannot contain @Body.
1.2 loadServiceMethod
loadServiceMethod(Method method)
方法的作用是解析我们传进来的服务中的方法,这里是WanApi中的方法,并将解析之后的结果包装成一个ServiceMethod
对象,放进一个缓存中。即缓存服务方法对应的请求信息,这样下次我们就不需要再次解析了。
//Retrofit.java
//缓存,用了线程安全ConcurrentHashMap
final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
//WanApi的articleList方法已缓存,直接返回
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析articleList的注解,创建ServiceMethod并缓存起来
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
#ServiceMethod.java
public ServiceMethod build() {
// 创建合适的适配器
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();
//解析方法注解如GET
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//省略各种检查...
//解析参数注解如Path
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
//省略各种检查...
return new ServiceMethod<>(this);
}
1.3 createCallAdapter
//ServiceMethod.java
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
//调用retrofit的callAdapter方法
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
//Retrofit.java
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
...
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
//调用nextCallAdapter
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
...
//遍历 callAdapterFactories
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
//是具体CallAdapterFactory的 get 方法
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
CallAdapter是根据returnType和annotations的类型,从callAdapterFactories工厂中进行查找,从而返回所对应的网络请求适配器,这里returnType指的是网络请求接口里方法的返回值类型,如Call、Observable等。annotations则指代的是注解类型,如@GET、@POST等。
callAdapterFactories中存放的是CallAdapter.Factory,调用factory.get(returnType,annotations,retrofit)
来获取到CallAdapter;Factory是个抽象类,get()是其抽象方法,那么它的实现类是谁?
1.4 ExecutorCallAdapterFactory
回到Retrofit.Builder
//Retrofit.Builder.java
public Retrofit build() {
Executor callbackExecutor = this.callbackExecutor;
//如果没设置线程池,则给android平台设置一个默认的MainThreadExecutor(用Handler将回调切回主线程)
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//添加平台默认的CallAdapterFactory
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
}
platform.defaultCallAdapterFactories 指的是Android平台的一个默认的适配器工厂,当我们不使用自定义适配器工厂时,则添加的就是这默认的工厂。这里提到了自定义适配器工厂,其实我们在使用Retrofit的时候,有时候会和RxJava结合,例如在创建Retrofit时,也会addCallAdapterFactory,将RxJava2CallAdapterFactory添加到callAdapterFactories中。
添加调用适配器工厂的目的就是支持Call以外的服务方法返回类型,如支持Observable,Single返回类型等。
# Android
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@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) {
handler.post(r);
}
}
}
ExecutorCallAdapterFactory这个工厂创建具体的CallAdapter实例。在callAdapterFactories集合器添加一个默认适配器工厂时,也附带传进去了一个参数callbackExecutor,callbackExecutor是Java8或者Android平台的一个默认线程调度器,它的作用涉及到一个线程切换的问题。
//ExecutorCallAdapterFactory.java
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
回到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);
}
});
}
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
创建好了ServiceMethod,也创建好了CallAdapter,接着就创建了OkHttpCall对象,然后调用了callAdapter的适配方法adapter(call)。
OKHttpCall
OkHttpCall其实是对OkHttp中的realCall进行了一层包装, 在Retrofit里,OkHttpCall紧密连接OkHttp,它的内部同样可以调用同步execute、 异步execute方法进行网络请求,其实真正调用的也就是OkHttp的execute和execute方法。在此同时,Retrofit中会对请求响应也做了解析。
可以看到callAdapter.adapt(call)
会使⽤⼀个 CallAdapter 对象来把 OkHttpCall 对象进⾏转换,⽣成⼀个新的对象,默认情况下,该方法返回的是⼀个 ExecutorCallbackCall
对象 ,它的主要作⽤是把操作切回主线程后再交给 Callback 。
//ExecutorCallbackCall.java
void enqueue(final Callback<T> callback) {
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
//将回调切回主线程
callbackExecutor.execute(
() -> {
callback.onResponse(ExecutorCallbackCall.this, response);
});
//...
}
@Override
public void onFailure(Call<T> call, final Throwable t) {}
});
}
小结一下
retrofit.create()的主要作用就在于将网络请求方法中的信息进行初步的处理,解析api service具体的接口方法的注解、参数等,解析接口后又生成了一个ServiceMethod对象,并且利用这个ServiceMethod对象创建了一个CallAdapter和OkHttpCall。
2.请求入队->call.enqueue(callback)
准备好了OKHttpCall对象,接下来就是调用OKHttpCall的同步方法execute
或者异步方法enqueue
请求入队,以enqueue方法为例:
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
synchronized (this) {
...
if (call == null && failure == null) {
try {
// focus1-创建一个okhttp3.Call 对象,也即创建一个HTTP请求
call = rawCall = createRawCall();
}
}
...
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//解析请求返回值
response = parseResponse(rawResponse);
}
...
try {
callback.onResponse(OkHttpCall.this, response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
}
}
});
}
注意focus1处的代码创建了一个okhttp3.Call对象
okhttp3.Call是如何创建的?
先来看看createRawCall方法的代码:
# OKHttpCall.java
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
#ServiceMethod.java
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
// ...
return callFactory.newCall(requestBuilder.build());
}
可以看到okhttp3.Call最终是 通过callFactory创建,我们知道OkHttp3的call的创建如下代码所示: okHttpClient.newCall(request)
;request参数我们通过RequestBuilder
来构建,那么callFactory
对象是从何而来的呢?
okhttp3.Call.Factory来自于Retrofit,在Retrofit中的构建者模式中可以找到:
public Retrofit build() {
// ...
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// ...
}
真相大白了!原来Retrofit用来创建OkHttp3的Call的工厂就是
OkHttp3的OkHttpClient:callFactory = new OkHttpClient();
回到OKHttpCall的enqueue方法,总结一下它的流程:
1.内部首先调用了一个createRawCall()方法,创建rawCall,这个rawCall其实指代的就是Okhttp3的call,也就是OkHttp进行网络请求调用的一个调度器;
2.创建好OkHttp的call后,就开始调用enqueue进行异步请求,发现在异步请求内响应的回调属于okhttp3.Callback,所返回来的结果,也都是okhttp3.Response,到这里就可以大概知道了,retrofit的网络请求其实还是由OkHttp来实现。
3.okhttp3.Response这个响应不方便开发者直接使用,所以retrofit在收到结果后,又对响应结果进行新一轮的解析 response = parseResponse(rawResponse),以Response对象的形式返回给开发者。
3.如何解析返回结果
查看OkHttpCall的parseResponse方法:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
...
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
}
}
可以看到,网络请求的结果最终会被一个返回结果转换器进行转换之后再返回,不难猜测,这个responseConverter
转换器的功能,就是将网络返回的不易看懂的数据转换为我们需要的自定义的Object接收对象,如UserBean、XXListBean等。现在我们已经有了原始的返回对象,接下只需要知道这个responseConverter
对象是什么以及它的convert()方法即可。
responseConverter
responseConverter
是在ServiceMethod的build中创建的:
# ServiceMethod.java
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
很容易又继续追到retrofit.responseBodyConverter(responseType, annotations)方法:
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
继续追到Retrofit里的nextResponseBodyConverter(null, type, annotations);:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(...) {
...
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
...
}
由converterFactories.get(i).responseBodyConverter(type, annotations, this);
可以看到,这个返回结果转换器responseConverter
来自于converterFactories,在Retrofit中寻找converterFactories
,在Retrofit的建造者Builder的build()方法中我们找到:
public Retrofit build() {
...
// ensures correct behavior when using converters that consume all types.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
...
}
第一行被add的converter不是我们自定义的,暂不去看,去寻找第二行addAll(this.converterFactories)
中的converterFactories
,看它是哪里被赋值构建的,我们于是又在Retrofit中找到了addConverterFactory()
方法:
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
这个方法是不是很眼熟,回忆一下我们平时是怎么使用Retrofit的:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(gsonConvertFactory)
.build();
这不就是我们在一开始在创建Retrofit时常用的添加Gson转换器的地方嘛!原来这个Gson转化器在Retrofit里是最终被用到OkHttpCall的parseResponse()
中的responseConverter.convert(catchingBody);
啊!原来Retrofit内部的网络结果转换器是这样工作的!
线程切换原理
相比OkHttp3,Retrofit在使用时一个很明显的方便之处就是在 Call.execute() 或者 Call.enqueue() 来发起请求后的返回结果事件中,不需要再切换线程,因为此刻,它已经在安卓的UI主线程当中了。
在执行retrofit2.Call的enqueue()方法时,我们需要注意,这个Call对象我们刚刚是在Retrofit中的create()方法创建的OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
但是这个OkHttpCall会经过adapt转为真正进行请求的另一个类ExecutorCallbackCall,它里面会持有OkHttpCall并在执行enqueue方法时去执行OkHttpCall的enqueue方法。
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
// 执行callAdapter的adapt方法时,将Call包装为了ExecutorCallbackCall对象
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
// ...
@Override public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
}
前面已经提到过,这个ExecutorCallbackCall的作用就是为了线程切换,具体的工作是交给了callbackExecutor这个线程调度器来做的,而默认callbackExecutor的创建在Retrofit的初始化中,callbackExecutor = platform.defaultCallbackExecutor();
static final class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
}
platform是一个Android平台,defaultCallbackExecutor 内部其实调用的是 new MainThreadExecutor() ,很清楚的看到, handler.post(r) 内部使用Handler将响应抛到了主线程。
小结一下
由上面的分析可知,ExecutorCallbackCall中的delegate就是 adapt()传过去的OkHttpCall,callbackExecutor就是我们刚刚看到的MainThreadExecutor,ExecutorCallbackCall在处理返回结果时,使用的是MainThreadExecutor,而MainThreadExecutor又将这个线程切换到了UI主线程中,至此,完成了网络请求过程子线程个UI主线程的切换。
延伸一下:
CallAdapterFactory的作用?
扩展的是对网络工作对象callWorker的自动转换,把Retrofit中执行网络请求的Call对象,转换为接口中定义的Call对象;
Retrofit本身用一个OkHttpCall的类负责处理网络请求,而我们在接口中定义需要定义很多种Call,接口里的Call和Retrofit里的OkHttpCall并不一致,所以我们需要用一个CallAdapter去做一个适配转换;
ConverterFactory的作用?
扩展的是对返回的数据类型的自动转换,把一种数据对象转换为另一种数据对象;