基于上一篇对okhttp的源码分析,我们结合rxjava和retrofit再次进行源码分析,没看过上一篇的请跳转链接:
okhttp中的线程池及源码分析
通常我们使用这套组合拳的代码可以在
Rxjava2+retrofit2+rxAndroid+okHttp
这里看到,那么我们接下来分析代码:
Rxjava 功能主要是一个发布订阅模式,与真正的请求无关,那么请求是在okhttp中做的,这点毫无疑问。retrofit呢?我们主要来看下retrofit的代码:
Retrofit retrofit_user = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(host)
.client(httpClient)
.build();
myinterface= retrofit_user.create(UserInterface.class);
retrofit主要是这么使用的,建造者模式去构建一个retrofit对象,调用create方法做了什么呢?
//1
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
@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);
}
//2
ServiceMethod serviceMethod = loadServiceMethod(method);
//3
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
create方法返回了一个代理对象,看标注1Proxy.newProxyInstance,最终处理委托给invoke方法。当用户调用接口中的方法时,会回调invoke方法。
标注2是一个核心的解析注解的内容,通常我们调用接口的时候会这样写:
@Headers({"Content-type:application/json;charset=UTF-8"})
@POST("/api/v1/user/login")
Observable<UserBean> login(@Body RequestBody body);
我们看下loadServiceMethod源码:
result = new ServiceMethod.Builder(this, method).build();
再进入build方法:
public ServiceMethod build() {
//1
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) {
//2
parseMethodAnnotation(annotation);
}
}
核心内容来了,标注1,取得了CallAdapter对象,看下createCallAdapter方法,最终调用到Retrofit中的nextCallAdapter方法,
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
adapterFactories是你添加的RxJavaCallAdapterFactory,调用RxJavaCallAdapterFactory中的get方法:
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
*********************
CallAdapter callAdapter = this.getCallAdapter(returnType, this.scheduler);
****************
}
再进入getCallAdapter方法:
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
************
return new RxJavaCallAdapterFactory.SimpleCallAdapter(observableType, scheduler);
}
返回的是RxJavaCallAdapterFactory.SimpleCallAdapter对象,即ServiceMethod build方法中的callAdapter 实际为RxJavaCallAdapterFactory.SimpleCallAdapter,当然如果这里你没传入CallAdapterFactory,那就不是这个了。接下来看标注2,进入parseMethodAnnotation方法:
private void parseMethodAnnotation(Annotation annotation) {
***************
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
}
根据获取的注解,调用parseHttpMethodAndPath方法:
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
this.httpMethod = httpMethod;
this.hasBody = hasBody;
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
获取参数信息,传给局部变量。
调用的是标注3中的serviceMethod.callAdapter.adapt(okHttpCall);这里我们看到serviceMethod的callAdapter对象是我们传入的RxJavaCallAdapterFactory中的SimpleCallAdapter,因此这里调用的是SimpleCallAdapter的adapter方法:
public <R> Observable<R> adapt(Call<R> call) {
Observable observable = Observable.create(new RxJavaCallAdapterFactory.CallOnSubscribe(call)).lift(OperatorMapResponseToBodyOrError.instance());
return this.scheduler != null?observable.subscribeOn(this.scheduler):observable;
}
这里返回了Observable 对象,而Observable 对象创建时传入了RxJavaCallAdapterFactory.CallOnSubscribe(call),对于响应式编程,我们需要知道,发布订阅模式一定会调用被观察者的subscribe方法,然后调用观察者的Call方法,我们看下RxJavaCallAdapterFactory.CallOnSubscribe(call)这个方法:
static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
@Override public void call(final Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
Call<T> call = originalCall.clone();
// Wrap the call in a helper which handles both unsubscription and backpressure.
RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
subscriber.add(requestArbiter);
subscriber.setProducer(requestArbiter);
}
}
看到调用subscribe方法后,执行了这里的Call方法,并且调用了setProducer方法:
public void setProducer(Producer p) {
long toRequest;
boolean passToSubscriber = false;
if (passToSubscriber) {
subscriber.setProducer(producer);
} else {
// we execute the request with whatever has been requested (or Long.MAX_VALUE)
if (toRequest == NOT_SET) {
producer.request(Long.MAX_VALUE);
} else {
producer.request(toRequest);
}
}
}
可以看到这里最后调用的是producer.request方法,当然这里的其他数据处理是为了解决并发的问题,进入request方法中:
@Override public void request(long n) {
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;
}
}
问题来了,这里调用的是call.execute方法,这里的call是什么呢?是OKHttpCall的对象,我们进到execute方法去:
@Override public Response<T> execute() throws IOException {
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());
}
这里调用了createRawCall方法,拿到call,再调用execute方法,取得Response,那么这里的Call是什么?
看下createRawCall方法:
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
前面已经知道serviceMethod.callFactory为OKhttpClient,那么newCall方法根据上一篇得到的就是RealCall对象。而真正的请求是执行的RealCall中的excute方法,即同步任务。由上一篇我们知道RealCall中有enqueue方法,执行异步任务,而且异步任务的线程池可以根据程序的运行情况自动来调整线程池中的线程数量。
下面看下整个流程图:
可以看到如果你想要执行异步线程任务的时候,不要用RxJavaCallAdapterFactory,而是手动调用Call的enqueue方法即可。代码如下:
mFileInterface.getTestFile().execute();//同步方法
mFileInterface.getTestFile().enqueue(new Callback<VerticalInfo>() {//异步方法
@Override
public void onResponse(Call<VerticalInfo> call, Response<VerticalInfo> response) {
}
@Override
public void onFailure(Call<VerticalInfo> call, Throwable t) {
}
});
getTestFile为如下:
@GET("/api/v1/base/code/getcode")
Call<VerticalInfo> getTestFile();
区别在于返回值为Retrofit2.Call和Observable。