站在Stay老司机肩膀上分析Retrofit
几个月前,第一次知道Retrofit是看了Stay的文章:Retrofit分析-漂亮的解耦套路文章看起来高大上的感觉,结果撸了一遍下来,好像很多都是一知半解。虽然老司机开车很稳,但是可能自己内功不足,沿途风景没能好好的欣赏。
现在再看回代码,感觉一下子就明白了。所以自己也打算撸一撸它的流程,自己做一回司机了,新手上路,请坐好扶稳哦(>>>)
首先引用一张Stay画的整体流程图(本来想自己画的,但是看了这张图,感觉自己也画不出更好的了)
Retrofit使用的大量的设计模式,先看看我的代码:
public static ApiService getDefault() {
if (SERVICE == null) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(logging).build();
SERVICE = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(client)
.build().create(ApiService.class);
}
return SERVICE;
}
很简单,通过Retrofit的Builder创建了一个Service对象,其中配置了一些参数。这里的Retrofit的构造的方式使用了Builder模式。
然后我们点开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, 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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
第一行的 Utils.validateServiceInterface(service) 作用是验证参数service是一个Interface.
结果是返回一个动态代理对象,使用了代理模式。这就意味着你调用service的每一个方法都会被拦截(具体就是你自己声明的API接口)
上面分析的过程图解:
在拦截的时候会进行下列一些处理:
- 加载API中的方法,解析注解。创建CallAdapter、Converter
- new一个OkHttpCall,关于Okhttp的所有参数都会在里面完成
- 用CallApater adapt OkHttpCall。
这里的步骤对应着下面几行代码:
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
首先看第一行,点进去loadSeerviceMethod(method):
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
这里其实比较简单,就是首先从缓存里面读取ServiceMethod对象,如果没有,就通过Builder模式创建出一个ServiceMethod对象。
接下来我们点进去ServiceMethod的build()方法看看,究竟做了什么:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
//一系列判断
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
//一系列判断
return new ServiceMethod<>(this);
}
上面的代码我做了简化,其实里面就做了几件事:
首先创建callAdapter,经过我查询源码createdCallAdapter最终返回的就是我们在创建Retrofit对象时addCallAdapterFactory传进去的CallAdapter,接着会创建responseConverter,这个同样是我们创建Retrofit对象时添加的Converter,然后会通过parseMethodAnnotation解析方法上面的注解。
上面分析的过程图解:
接下来解释创建OkhttpCall了,这个没什么好解释的,创建一个对象:
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
接着就用CallAdapter来适配OkHttpCall了。
return serviceMethod.callAdapter.adapt(okHttpCall);
这里的CallAdapter使用了适配器模式,他会把OkHttpCall返回的结果转换成我们声明的接口的返回值,说到这里我就要解释一下几个CallAdapter,这个CallAdapter实际上是什么东西呢?
上面说过serviceMethod.callAdapter是通过createCallAdapter()得到的,然后最终的值就是我们自己声明的,看回最前面的例子,所用的CallAdapter就是RxJavaCallAdapterFactory.create(),实际上用了Rx的CallAdapter。既然是是策略模式,当然有几种策略可供选择啦。
CallAdapter在Retrofit中提供了四种,分别为:RxJavaCallAdapterFactory、Java8CallAdapterFactory、GuavaCallAdapterFactory、AndroidCallAdapterFactory。
前面的例子使用的是RxJavaCallAdapterFactory。所以我们打开RxJavaCallAdapterFactory的源码看看:
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Response must be parameterized"
+ " as Response<Foo> or Response<? extends Foo>");
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResponseCallAdapter(responseType, scheduler);
}
if (rawObservableType == Result.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Result must be parameterized"
+ " as Result<Foo> or Result<? extends Foo>");
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResultCallAdapter(responseType, scheduler);
}
return new SimpleCallAdapter(observableType, scheduler);
}
从上面代码看来,实际上会根据Method不同的返回值类型来返回不同的CallAdapter,比如返回值是Response的话就会返回ResponseCallAdapter,返回值是Result就会返回ResultCallAdapter,返回值是普通Object的话就回返回SimpleCallAdapter。
这三个CallAdapter最后都会调用adapt方法,adapt方法的作用就是把执行请求并且把结果发射出去:
//adapt方法
@Override public <R> Observable<Response<R>> adapt(Call<R> call) {
Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
//CallOnSubscribe -> RequestArbiter
@Override
public void request(long n) {
if (n < 0) throw new IllegalArgumentException("n < 0: " + n);
if (n == 0) return; // Nothing to do when requesting 0.
if (!compareAndSet(false, true)) return; // Request was already triggered.
try {
Response<T> response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
return;
}
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
最终会调用了call.execute();这个call其实就是我们上面在动态代理new出来的OkHttpCall,然后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 {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
最后调用了parseResponse()方法,最终执行:
T body = serviceMethod.toResponse(catchingBody);
//ServiceMethod:
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
其实就是调用我们的GsonConverter来convert把数据转换成对象而已。
好了这样的一个过程就分析完毕了。
上面分析的过程图解:
最后我们分析一下Retrofit的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> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
可以看到callFactroy为null的情况下会创建一个OkHttpClient(),所以没有指定client的情况下会使用okhttpclient请求网络。如果我们没有指定CallAdapter的话,也会默认生成一个
总结
上面的总结可能有些地方混乱,因为我是结合自己的代码例子来分析整个过程的,而且对于上图右边的其他一些GuavaCallAdapterFactory、Java8…等等都没有分析,不过大体上的套路就是上面这样分析,我因为是结合例子分析,使用的是RxJava,自然就只分析到RxJavaCallAdapterFactory了,整体的流程大概就拎出来了。
分析完了,还要思考一下作者为什么要做,说解耦大家都知道! 可能还是内功不够,所以思考不出什么来呀,暂时不想它了吧。嗯,就这样了。
年轻的司机开车真是每一次都这么激动。
最后我在分析代码的时候,发现Stay的图有一点点画的不太对,我在下图把图片标注出来: