之前写了一个Gank.io的客户端练手学习了下RxJava+Retrofit的基本使用,顺着代码看了下相关的源码,将分析笔记记录于此,欢迎有兴趣的小伙伴多多指正,共同进步。
在写Gank的过程中,查看妹子福利时的代码如下,从创建接口到访问网络数据再到转换数据,RxJava+Retrofit到底是怎么完成的呢?
public interface GankApi {
@GET("data/福利/{number}/{page}")
Observable getGirls(@Path("number") int number, @Path("page") int page);
}
//1.创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJavaCallAdapterFactory)//4
.build();//5
//2.构造请求接口
gankApi = retrofit.create(GankApi.class);
//3.执行请求
gankApi.getGirls(10, page++)
按照代码我们的分析也分成了三块:Retrofit对象的创建、GankApi请求接口的生成、执行网络请求的调用。
Retrofit采用Builder模式创建,首先从Builder开始看起,先是初始化平台对象,并向集合converterFactories中默认添加了一个BuiltInConverters对象
Builder(Platform platform) {
this.platform = platform;
// 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());
}
我们知道Retrofit本质上还是利用OkHttp进行网络访问,这一步就是提供一个okHttpClient对象用来发送请求,同时设置请求地址的基本路径。如果不设置则会报异常。
这一步指定使用Gson对返回数据进行解析,使用RxJava进行回调,具体创建操作后面再进行分析。
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
这里就是基于Builder创建Retrofit的代码,主要信息都在注释里面了。
public Retrofit build() {
//1.如果没有设置baseUrl则抛出异常
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//2.如果没有设置OkHttpClient对象则进行设置
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//3.如果没有设置Executor则根据平台设置默认的Executor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//4.基于Executor创建默认的CallAdapter.Factory,这里具体就是ExecutorCallAdapterFactory对象
List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
callbackExecutor, validateEagerly);
}
上面就是其Retrofit的对象的构建过程,基本就是设置了OkHttpClient和基础路径,然后设置Converter.Factory和CallAdapter.Factory。有一点区别是Converter.Factory的集合在我们设置GsonConvert之前就添加了一个元素BuiltInConverters,而对于CallAdapter.Factory则是在设置完成后添加的。对于构建完成后的两个集合如下(偷懒直接断点截了个图,捂脸):
下面是我们关注的重点,其create方法创建我们想要的Api类以及方法的调用
通过下面的create方法的代码我们可以看出Retrofit是通过动态代理来创建调用我们的请求方法的,首先将调用的Method解析为ServiceMethod,
然后封装为OkHttpCall请求对象,最后通过CallAdapter执行请求返回数据。这一部分我们重点分析ServiceMethod的创建。
public T create(final Class 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 {
//...代码省略
//1.将Method解析为ServiceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
//2.将ServiceMethod和args参数封装为OkHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//3.发送请求返回封装好的Call对象,如果是RxJava作为Adapter则返回Observable对象
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;、
this.method = method;
this.methodAnnotations = method.getAnnotations();//获取方法的注解数组
this.parameterTypes = method.getGenericParameterTypes();//获取形参数据
this.parameterAnnotationsArray = method.getParameterAnnotations();//获取形参的注解
}
public ServiceMethod build() {
//1.创建CallAdapter对象,并获取响应的数据类型,其实我们要转换的数据类型
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
//2.创建Converter对象
responseConverter = createResponseConverter();
//3.解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//4.解析参数注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
上面是去掉各种异常处理之后的简化代码,其主要做了四项操作。
下面来看下四步的代码(具体到细节的话每一步都可以写成一篇文章,因此这里只做简单分析):
CallAdapter的创建
最终调用的是Retrofit中的nextCallAdapter。
上面提到了,在构建Retrofit时,使用List集合存放CallAdapter.Factory,RxJavaCallAdapterFactory存放于0,默认的DefaultCallAdapterFactory或者ExecutorCallAdapterFactory存放于1,因此在创建CallAdapter时如果设置了RxJavaCallAdapterFactory优先使用RxJavaCallAdapterFactory创建Adapter。
//adapterFactories集合,默认skipPast为null,因此indexOf返回-1,start从0开始,遍历第一个就是RxJavaCallAdapterFactory
//使用该对象创建CallAdapter对象,
public CallAdapter> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
下面是RxJavaCallAdapterFactory的get方法具体的代码,returnType参数就是我们所调用方法的返回值类型
@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class> rawType = getRawType(returnType);
//获取全类名为rx.Observable因此isSingle与isCompletable均为false,最终调用getCallAdapter方法来获取对象
//具体细节这里不再分析,这里最终返回的是SimpleCallAdapter类的对象。
String canonicalName = rawType.getCanonicalName();
boolean isSingle = "rx.Single".equals(canonicalName);
boolean isCompletable = "rx.Completable".equals(canonicalName);
if (rawType != Observable.class && !isSingle && !isCompletable) {
return null;
}
if (isCompletable) {
return CompletableHelper.createCallAdapter(scheduler);
}
CallAdapter> callAdapter = getCallAdapter(returnType, scheduler);
if (isSingle) {
return SingleHelper.makeSingle(callAdapter);
}
return callAdapter;
}
PS:RxJavaCallAdapterFactory提供了ResponseCallAdapter、SimpleCallAdapter、ResultCallAdapter三种Adapter,具体细节区别有兴趣的同学可以研究下源码。
public Converter nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//start为0
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
//首先遍历到的是BuiltInConverters,这时的返回类型就是我们定义方法里面的类型,BuiltInConverters的responseBodyConverter返回null。第二次遍历是GsonConverterFactory的GsonResponseBodyConverter,直接返回GsonResponseBodyConverter对象,
Converter converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
}
//创建GsonResponseBodyConverter
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
}
}
对于参数注解的解析,首先遍历每一个参数的每一个注解,然后对每个参数的注解构造ParameterHandler对象。具体细节这里不再赘述
上述操作完成后就完成了ServiceMethod的构建。
在构建请求完成后就是调用我们的方法了,具体到我们的代码就是调用了SimpleCallAdapter的adapt方法:
@Override public Observable adapt(Call call) {
Observable observable = Observable.create(new CallOnSubscribe<>(call)) //1.将call传递给CallOnSubscribe,执行网络请求
.flatMap(new Func1, Observable>() {//2.对数据进行转换成函数所需要的Obserable对象,
@Override public Observable call(Response response) {
if (response.isSuccessful()) {
return Observable.just(response.body());
}
return Observable.error(new HttpException(response));
}
});
//
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
可以看到,首先是将call传递给了CallOnSubscribe。这是RxJavaCallAdapterFactory的一个内部类,简化后的代码如下
static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
private final Call originalCall;
CallOnSubscribe(Call originalCall) {
this.originalCall = originalCall;
}
@Override public void call(final Subscriber super Response> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
final Call call = originalCall.clone();
// Attempt to cancel the call if it is still in-flight on unsubscription.
subscriber.add(Subscriptions.create(new Action0() {
@Override public void call() {
call.cancel();
}
}));
//执行网络请求
Response response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
}
}
可以看到是在CallOnSubscribe的call方法中执行了网络请求execute()并将Response对象作为参数通过flatMap转换为相应的Observable对象,也就是我们的接口方法的返回类型Observable,剩下的就是利用Gson和RxJava进行数据的解析和转换最终生成符合我们需要的数据。
到这里我们开头访问妹子福利代码的执行流程基本搞清楚了,总体而言Retrofit源码比较简单而且设计的非常好,建议大家都去认真阅读下。
最后总结下阅读源码的三点感受:
1. 不要只看分析文章,自己分析源码很重要
2. 结合代码,从一个点开始顺藤摸瓜,总会找到让你高潮的代码与逻辑
3. 断点调试很重要!断点调试很重要!断点调试很重要!