一.Retrofit是什么
Retrofit是square开源的一个Restful的http网络请求框架的封装。
网络请求的工作本质是okhttp完成,而Retrofit仅负责网络请求接口的封装。开发者只需要定义接口就可以了,Retrofit提供了注解可以表示该接口请求的请求方式、参数、url等。定义好了接口以后,在调用该远程接口的时候直接使用该接口就好像通过RPC方式使用本地类一样方便。
App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url等信息,然后有OkHttp完成后续的请求操作。
在服务端返回数据之后,OkHttp将原始的数据结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。
Retrofit的设计任务如下:
请求前 | 结果返回 |
---|---|
1.统一配置网络请求头 2.一致适配请求request |
1.线程切换 2.数据适配 |
下面通过一个实例来看一下使用Retrofit的工作流程及分析一下其工作原理:
二.具体实例
a.定义接口
public interface RetrofitApi {
@GET("weather_mini")
Call getWeatherInfo(@Query("city") String city);
@GET("HPImageArchive.aspx")
Observable getImage(@Query("format") String format, @Query("idx") int idx, @Query("n") int n);
}
b.Retrofit创建
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://cn.bing.com/")
//设置使用Gson解析(可将得到的Json串转换为与其结构相符的对应ImageBean类)
.addConverterFactory(GsonConverterFactory.create())
//支持RxJava2[可以不设置该参数,则使用默认的]
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
c.创建接口对象
RetrofitApi request = retrofit.create(RetrofitApi.class);
d.方法调用
//1.默认Call调用
Call call = request.getWeatherInfo("北京");
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
Log.e("Seven", "use call to get weather info is: " + response.body().toString());
}
@Override
public void onFailure(Call call, Throwable t) {
}
});
//2.结合RxJava2调用[即设置了addCallAdapterFactory(RxJava2CallAdapterFactory.create())]
Observable observable = request.getImage("js", step, 1);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
......
@Override
public void onNext(ImageBean imageBean) {
List imagesBeans = imageBean.getImages();
ImageBean.ImagesBean imagesBean = imagesBeans.get(0);
String url = ImageBean.ImagesBean.BASE_URL + imagesBean.getUrl();
String des = imagesBean.getCopyright();
imageUrl.setValue(url);
imageDescription.setValue(des);
}
......
});
三.原理分析
通过上面的实例可以看到,先是创建了Retrofit并对其进行配置,采用了建造者模式,然后通过Retrofit去创建接口对象,最后通过接口对象来调用方法,那么下面就一步一步来分析其工作原理。
a.Retrofit创建
Retrofit创建采用的是建造者模式,这里直接跳到最后build()方法:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//创建callFactory,就是一个okhttp3.OkHttpClient实例
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//创建callbackExecutor,最终返回的是Android Platform的MainThreadExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//创建默认的CallAdapter.Factory
List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//获取到Converter.Factory,addConverterFactory(GsonConverterFactory.create())已经执行了
List converterFactories = new ArrayList<>(this.converterFactories);
//最后将各个参数放在一起创建了一个Retrofit实例
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
从上述方法可以看到,主要工作如下:
baseUrl:网络请求的url地址;
callFactory:网络请求工厂,此处创建一个OkHttpClient()实例,后面进行网络请求会用到该实例,网络请求逻辑是在okhttp里面;
callbackExecutor:回调方法执行器,用来线程切换;
adapterFactories:网络请求适配器工厂的集合,会创建默认的CallAdapter.Factory,供Call方式来使用,若配置了addCallAdapterFactory(RxJava2CallAdapterFactory.create()),优先使用Observable;
converterFactories:数据转换器工厂的集合,配置了addConverterFactory(GsonConverterFactory.create()),使用Gson进行解析数据;
b.通过Retrofit创建接口对象
接口对象是通过Retrofit.create(xx.class) 来创建的,一起看一下源码:
public T create(final Class service) {
......
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
.....
//创建ServiceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
//创建OkHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//返回结果,即Call或Observable
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
create()内通过动态代理生成一个代理类对象,具体来说就是通过Proxy.newProxyInstance()来创建的。此处使用的是Java动态代理创建的,可以参考Java动态代理学习,通过代理类调用接口方法时会回调invoke()方法,看一下invoke()方法内都执行了哪些逻辑:
1.创建ServiceMethod实例
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
//先从cache里面取,如果已经存在了,就不去创建,即方法执行过一次,就不会重新创建了
result = serviceMethodCache.get(method);
if (result == null) {
//通过构造者模式来创建ServiceMethod实例
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
由于ServiceMethod在创建时,会将App层执行的method作为参数传入,从而会用到反射来获取Method的请求参数等,反射会消耗性能,因此对ServiceMethod做了缓存,不会每次都去创建进行反射。
public ServiceMethod build() {
//创建callAdapter,在invoke()方法最后会用到,如果Retrofit配置了RxJava2转换器,那这里就是RxJava2CallAdapter
callAdapter = createCallAdapter();
.....
//获取response转换器
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
//解析接口内方法的注解,可以获取到Http请求方式,请求体,url等信息
parseMethodAnnotation(annotation);
}
//解析当前方法的参数
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
......
......
return new ServiceMethod<>(this);
}
private CallAdapter> createCallAdapter() {
......
Annotation[] annotations = method.getAnnotations();
try {
//此处是重点,会调用retrofit内的callAdapter方法
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
ServiceMethod在创建时,主要工作如下:
callAdapter:明确正确的callAdapter;
responseType:确定Call接口的返回值类型;
responseConverter:明确对应的数据转换器;
parameterHandlers:对接口中的注解参数进行解析配置;
2.OkHttpCall
OkHttpCall继承于Retrofit2.Call,内部主要对okhttp3一系列操作的封装:
final class OkHttpCall implements Call {
OkHttpCall(ServiceMethod serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
......
@Override public synchronized Request request() {}
@Override public void enqueue(final Callback callback) {}
@Override public Response execute() throws IOException {}
.....
}
3.CallAdapter.adapt(okHttpCall)
在invoke()方法中,最后会return serviceMethod.callAdapter.adapt(okHttpCall);,上面有提到过,这一步的作用是返回一个Retrofit2.Call或者Observable。
CallAdapter是一个接口对象,因此需要找到它的实现类。在Retrofit创建的时候,会创建默认的CallAdapter.Factory,返回Retrofit2.Call;如果配置了addCallAdapterFactory(RxJava2CallAdapterFactory.create()),会优先将接口方法返回Observable。
①默认返回Call
创建Retrofit时,配置流程如下:
------>Retrofit.build()
------>platform.defaultCallAdapterFactory(callbackExecutor)
------>new ExecutorCallAdapterFactory(callbackExecutor)
调用接口方法时,ServiceMethod创建CallAdapter流程如下:
------>SeviceMethod.createCallAdapter()
------>Retrofit.callAdapter(returnType, annotations)
------>Retrofit.nextCallAdapter()
------>adapterFactories.get(i).get(returnType, annotations, this);
通过adapterFactories.get(i).get(returnType, annotations, this),调用get()方法,最终会调用ExecutorCallAdapterFactory里面的get()方法:
//ExecutorCallAdapterFactory.java
@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>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call adapt(Call call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
通过以上逻辑可以看到,在调用get()后,会返回CallAdapter实例,然后再调用adapt()方法后,会返回new ExecutorCallbackCall<>(callbackExecutor, call),是Call接口的实现类。
static final class ExecutorCallbackCall implements Call {
final Executor callbackExecutor;
final Call delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
}
ExecutorCallbackCall的参数callbackExecutor是通过Android platform返回的,持有主线程的Handler,执行execute()后,会在主线程内执行。
//Platform.java
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
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);
}
}
}
ExecutorCallbackCall的参数call就是OkHttpCall实例,后面请求的时候会用到。
以上分析完成,在通过RetrofitApi调用其接口后,会返回Call实例。
②配置RxJava2返回Observable
在创建Retrofit时,通过配置addCallAdapterFactory(RxJava2CallAdapterFactory.create())就在callAdapterFactories列表中加入了RxJava2CallAdapterFactory,执行get()方法看一下源码实现逻辑:
//RxJava2CallAdapterFactory.java
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
......
boolean isResult = false;
boolean isBody = false;
......
......
return new RxJava2CallAdapter(responseType, scheduler, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
在get()方法会创建RxJava2CallAdapter实例,看一下源码实现逻辑:
//RxJava2CallAdapter.java
final class RxJava2CallAdapter implements CallAdapter
然后调用adapt()方法后,会返回Observable,CallObservable内的参数call就是OkHttpCall实例,后面请求的时候会用到。
以上分析完成,在通过RetrofitApi调用其接口后,会返回Observable实例。
用一张图总结一下返回Call或Observable流程:
c.方法调用
1.Call.enqueue()
上面的实例中可以看到,Call对象是通过enqueue()或者execute()发起请求的,而这个Call对象实际上是ExecutorCallbackCall的实例,前面已经分析过,在看一下ExecutorCallbackCall的enqueue方法:
@Override public void enqueue(final Callback callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response 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);
}
}
});
}
@Override public void onFailure(Call call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
当外部调用enqueue()时,最终调用的就是delegate.enqueue()方法,delegate是OkHttpCall,一起看一下OkHttpCall.java实现逻辑:
final class OkHttpCall implements Call {
private final ServiceMethod serviceMethod;
private final Object[] args;
......
private okhttp3.Call rawCall;
//invoke()方法内,创建OkHttpCall是传入serviceMethod及args
OkHttpCall(ServiceMethod serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
......
@Override public void enqueue(final Callback callback) {
.....
okhttp3.Call call;
.......
//创建okhttp3.Call对象
call = rawCall = createRawCall();
......
......
//调用okhttp3内的逻辑
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
try {
//得到response,最终调用到SeviceMethoad内的toResponse()方法
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
//回调方法
callSuccess(response);
}
......
private void callSuccess(Response response) {
try {
//回调ExecutorCallbackCall内的onResponse()
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
.......
private okhttp3.Call createRawCall() throws IOException {
//调用serviceMethod的toRequest()方法,将其组装成http请求的request
Request request = serviceMethod.toRequest(args);
//serviceMethod.callFactory对应的是okhttpClient实例,即调用okhttpClient的newCall方法
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
return call;
}
.......
}
从上面可以看到,在执行enqueue()时,会执行createRawCall(),该方法内部用到了SeviceMethod的toRequest()方法,将方法内的请求参数组装成http request,然后通过newCall创建okhttp3.call(),再调用okhttp3.call()的enqueue()方法,后续就由okhttp来进行网络请求处理了。
在得到结果后,用到了SeviceMethod的toResponse()方法,将请求结果转为为自定义的类。结果返回后会执行callbackExecutor.execute(),前面讲到,callbackExecutor.execute()是在主线程执行,因此,enqueue后返回的结果是在主线程。
以上就是app端在调用enqueue后的执行流程。
2.Observable.subscribe()
前面分析过,Observable是在RxJava2CallAdapter内部的adapt()方法返回的,最终返回的是CallObservable,当执行CallObservable.subscribe()后,从RxJava2的源码RxJava学习可以知道,每个Observable都会去调用subscribeActual(),看一下CallObservable的逻辑:
final class CallObservable extends Observable> {
......
@Override protected void subscribeActual(Observer super Response> observer) {
......
boolean terminated = false;
try {
//直接获取到response
Response response = call.execute();
if (!call.isCanceled()) {
//回调onNext()
observer.onNext(response);
}
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
}
......
}
}
通过call.execute()去发起网络请求,看一下OkHttpCall这个类的另外一个方法execute():
@Override public Response execute() throws IOException {
okhttp3.Call call;
......
call = rawCall = createRawCall();
.....
//直接调用okhttp3的execute()去获取response,然后进行转换返回
return parseResponse(call.execute());
}
可以看到,请求方式跟上面的是类似的,一个是同步,一个是异步,得到转换后的response后通过observer.onNext()回调。
至此,Retrofit2请求的原理分析已经结束了。主要涉及到Retrofit.create()用到的动态代理,网络请求的OkHttp以及与RxJava2适配等。
用一张图总结一下请求流程:
四.总结
a.使用Retrofit流程如下:
1、定义请求接口;
2、通过建造者模式创建一个Retrofit实例,对并Retrofit进行相关参数配置;
3、通过Retrofit对象的creat()方法创建一个代理对象;
4、当调用接口方法时,都会调用动态代理的invoke()方法;invoke()内部做了3件事情:
a. 对method进行解析,生成ServiceMethod对象并缓存起来,下次调用就不需要解析了;
b. 将原始的okhttp3.call[okhttp3]封装成OkHttpCall[retrofit2];
c. 通过CallAdapter转换成Call对象或者Observable对象;
5、如果返回Call对象,调用execute或者enqueue方法去做请求,最终在onResponse()里面进行请求结果逻辑处理;如果返回Observable对象,则通过Rxjava2最终在onNext()里面进行请求结果逻辑处理。
b.Retrofit封装的点:
1.Build模式创建网络请求基本配置;
2.用注解来排列组合成网络请求,以不变应万变;
3.统一提供Gson解析,提供了可复用、易扩展的数据解析方案;
4.自定义Executor(Handler)完成线程的切换;
c.Retrofit用到的设计模式
1.Retrofit实例使用建造者模式通过Builder类构建,当构造函数的参数大于4个,且存在可选参数的时候就可以使用建造者设计模式;
2.Retrofit创建的CallFactory,使用工厂方法设计模式,此处只支持OkHttp;
3.整个Retrofit采用的是外观模式,统一的调用创建网络请求接口实例和网络请求参数配置的方法;
4.Retrofit里面使用了动态代理模式来创建网络请求接口实例,这个是retrofit对用户使用来说最大的复用,其他的代码都是为了支撑这个动态代理给用户带来便捷性的;
5.使用了策略模式对serviceMethod对象进行网络请求参数配置,即通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络的url地址,网络请求执行器、网络请求适配器和数据转换器;
6.ExecutorCallbackCall使用装饰者模式来封装callbackExecutor,用于完成线程的切换;
7.ExecutorCallbackCall使用静态代理模式代理了call进行网络请求,真正的网络请求是由okhttpcall执行,然而okhttpcall不是自己执行,它是okhttp提供call给外界(retrofit)使用的唯一门户,此处是门面模式;
8.ExecutorCallbackCall的初始化是在ExecutorCallAdapterFactory里面通过适配器模式创建的,CallAdapter采用了适配器模式为创建访问call接口提供服务,默认ExecutorCallAdapterFactory将okhttp3.call转换为Retrofit中的Call,如果使用Rxjava,则将okhttp3.call转换为Observable;
9.当使用了Rxjava时,app层注册observer,即观察者模式。