最近项目将网络框架换成Retrofit2.0.2,文中说的Retrofit都是指的Retrofit2这里要说明一下,毕竟和Retrofit1差别还是蛮大的,结合Okhttp,RxJava还是比较好用的,网上有很多前辈介绍过使用方法,本文是想研究一下Retrofit的源码。关于Retrofit的介绍可以查阅Retrofit的官方网站
直接进入主题:(注本文是结合RxJava介绍的,最好可以了解一下RxJava不了解也没有关系,大部分的思想是一样的)
Retrofit的基本使用
Retrofit使用是非常简单的,在上边的官网上介绍的也非常详细。但是为了后边的分析,还是把使用的代码贴在这儿:
一般在项目中会将需要请求网络方法写在一个接口中,如下:
public interface GitHubService {
@GET("users/{user}/repos")
Observable> listRepos(@Path("user") String user);
}
如果要使用Retrofit还需要构建Retrofit的对象:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
主要就是配置baseUrl,ConverterFactory,CallAdapterFactory。这里用的是Gson,和RxJava所以相应的就是GsonConverterFactory,RxJavaCallAdaperFactory这个在后边的源码分析中会用到。
最后直接调用就可以了:
GitHubService service = retrofit.create(GitHubService.class);
service.listRepos("octocat")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(list->{
if(list!=null){
//TODO 取得数据后逻辑处理
}
});
可以说,代码还是非常简洁的。用起来也很容易上手。
Retrofit工作流程
如上面的使用中我们可以看到:
1.通过Retrofit.Builder().build()构建Retrofit实例。
2.调用Retrofit的create()方法将生成接口GitHubService的实例。
3.调用GitHubService的listRepos()方法返回Observable
,这里的GitHubService实例实际上是个代理对象,这个下文再说。 >
下图是我整理的Retrofit运行时主要节点的时序图,当然不是所有的过程都反映出来了。
看不懂没关系,一步一步来,先看看Retrofit源码的构成:
回到上边步骤2,调用Retrofit的create()方法将生成接口GitHubService的实例:
GitHubService service = retrofit.create(GitHubService.class);
将GithubService.class作为参数,传入create(),然后又返回一个GithubService实例,看起来是不是很神奇。源码如下:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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 {
// 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);
}
});
}
这里使用了动态代理,返回了一个 Proxy 代理类,调用GithubService(在自己的项目中是XXXService接口)接口中的任何方法都会调用 proxy 里的 invoke 方法。这个方法里边最重要的就是第23,24,25行代码。
1.构建ServiceMethod实例
先看第23行
ServiceMethod serviceMethod = loadServiceMethod(method);
通过loadServiceMethod方法获取ServiceMethod实例:
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;
}
第4行首先会先尝试从serviceMethodCache(类型Map
)中get,如果缓存中没有则构建一个ServiceMethod实例。接着看怎么构建ServiceMethod实例,ServiceMethod.java中源码:
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() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
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);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
使用Builder模式来构建serviceMethod实例,将retrofit实例,和invoke的方法作为参数来初始化。第10行通过调用createCallAdapter()创建CallAdapter实例callAdapter。
private CallAdapter> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
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);
}
}
看第11行,获取到了,接口方法中使用的注解,在我们本文中的GithubService的listRepos的注解就是@Get();第13行会通过调用Retrofit的callAdapter()方法来返回CallAdapter实例:
Retrofit.java文件中:
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
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;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
真的实现是在Retrofit.java中的nextCallAdapter()方法中实现的。上边代码第25行,adapterFactories是一个缓存CallAdapter.Factory的list,我们在构建Retrofit实例时,曾经设置过addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就意味着adapterFactories.get(i)将获得到RxJavaCallAdapterFactory,然后会执行其get()方法。
RxJavaCallAdapterFactory.java文件中:
@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class> rawType = getRawType(returnType);
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 && !(returnType instanceof ParameterizedType)) {
String name = isSingle ? "Single" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + " or " + name + " extends Foo>");
}
if (isCompletable) {
// Add Completable-converter wrapper from a separate class. This defers classloading such that
// regular Observable operation can be leveraged without relying on this unstable RxJava API.
// Note that this has to be done separately since Completable doesn't have a parametrized
// type.
return CompletableHelper.createCallAdapter(scheduler);
}
CallAdapter> callAdapter = getCallAdapter(returnType, scheduler);
if (isSingle) {
// Add Single-converter wrapper from a separate class. This defers classloading such that
// regular Observable operation can be leveraged without relying on this unstable RxJava API.
return SingleHelper.makeSingle(callAdapter);
}
return callAdapter;
}
正常情况下,会执行到第27行,通过getCallAdapter方法,获得Observable泛型的CallAdapter,继续跟进去看看:
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 or Result extends Foo>" );
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResultCallAdapter(responseType, scheduler);
}
return new SimpleCallAdapter(observableType, scheduler);
}
第3行会getRawType(observableType)会返回Observable具体类型,例如本例中,
public interface GitHubService {
@GET("users/{user}/repos")
Observable> listRepos(@Path("user") String user);
}
返回值是Observable
那么getRawType(observableType)将得到List.class,这样程序将执行第22行,将返回一个SimpleCallAdapter实例,那么它就是CallAdapter的真正实现。 >
回到ServiceMethod的build()方法中,继续执行第18行responseConverter = createResponseConverter();过程也和createCallAdapter差不多,也是使用工厂模式,通过get()方法获得Converter的真正实现,篇幅所限就不一步一步的跟了,本例使用的是Gson,所以Converter得实现是GsonResponseBodyConverter。之后就是解析注解,参数等,这样ServiceMethod已经构建好了。
生成OkHttpCall
回到Retrofit动态代理invoke方法中,第二步就是生成Call的实例了,目前Retrofit的默认使用的是OkhttpCall。其是OkHttp的包装类,所有OkHttp需要的参数都在该类中找到。
adapt Call
第三步执行serviceMethod.callAdapter.adapt(okHttpCall),通过之前的分析,serviceMethod.callAdapter真正的实现是SimpleCallAdapter,那么自然也是执行的它的adapt()方法。为了证实这个,可以debug一下就知道了。
RxJavaCallAdapterFactory.SimpleCallAdapter.adapt():
@Override public Observable adapt(Call call) {
Observable observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}
其返回类型Observable,也就是我们需要的结果,还记得我们是怎么使用的RxJava的吗?
service.listRepos("octocat")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(list->{
if(list!=null){
//TODO 取得数据后逻辑处理
}
});
看代码service.listRepos(“octocat”)应该是一个Observable,而刚刚分析的,service.listRepos(“octocat”)确实会返回一个Observable,有了这个Observable之后,我们就可以通过subscribeOn给他指定运行线程,这样像网络请求耗时操作就不会再UI线程中运行,从而达到异步的目的,然后通过observeOn()将线程切回UI线程,当Okhttp请求完数据并进行相应的convert之后,就可以在UI处理相应的逻辑。
回到adapt方法,第2行创建Observable,而new CallOnSubscribe<>(call)生成了一个OnSubscribe()的实例,而OnSubscribe继承自Action1,其只包含一个call()方法,而这个call是在CallOnSubscribe中实现:
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.
Call call = originalCall.clone();
// Wrap the call in a helper which handles both unsubscription and backpressure.
RequestArbiter requestArbiter = new RequestArbiter<>(call, subscriber);
subscriber.add(requestArbiter);
subscriber.setProducer(requestArbiter);
}
}
首先clone了一份Call,然后生成了RequestArbiter,他继承自AtomicBoolean,实现了Subscription, Producer接口,Producer只有一个request方法;一般实现该接口的类,都会包含一个Subscriber对象和一个待处理的数据:
static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer {
private final Call call;
private final Subscriber super Response> subscriber;
RequestArbiter(Call call, Subscriber super Response> subscriber) {
this.call = call;
this.subscriber = subscriber;
}
@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 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();
}
}
@Override public void unsubscribe() {
call.cancel();
}
@Override public boolean isUnsubscribed() {
return call.isCanceled();
}
}
那么看看request()方法到底干了什么?第16行代码call.execute()最终将执行okhttp的execute(),为什么这里会同步请求数据呢,还记得之前我们把耗时操作切换到子线程中吗?既然已经不是在UI线程了,这里就可以使用同步获取response数据了。在获取到response后就通过执行subscriber.onNext(response);这样subscribe过Observable的subscriber都可以收到数据了。而因为我们设置过observeOn(AndroidSchedulers.mainThread()),所以当我们接受到数据的时候,已经是在UI线程中了,所以就可以做后续的逻辑处理了。
总结:Retrofit 的代码并不是很多,其底层网络通信时交由 OkHttp 3来完成的,但是Retrofit运用了大量的设计模式,代码逻辑很清晰。没事的时候,不妨研究研究,毕竟是Jake Wharton大神的杰作。