Retrofit严格意义上不是OkHttp的,但是这两个东西联系太紧密了,在Android开发时,经常会把Retrofit和OkHttp混到一起用,很方便!! 所以不得不讲一下Retrofit
注意下,这篇文章是讲原理的,不是讲用法的,想学习Retrofit怎么用,不要看这篇文章,纯属浪费时间
深入到Retrofit的源码中可以看到,Retrofit的设计是非常精巧的,他利用了动态代理和注解技术,用几个类搭建了一个可扩展性非常好的框架,实在是我辈的楷模。
Retrofit的逻辑分成以下三个部分
- 创建代理对象
- 对注解的解析,得到ServiceMethod,从名字上就可以看出,这是一个类的方法
- 对第一步解析出的ServiceMethod的调用(invoke)
除了上面两部分外,我们还会讲一下ConverterFactory
创建代理对象
直接上代码吧。
使用Retorfit要第一步当然是通过调用create方法来创建Retrofit实例
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//核心就是这个动态代理方法,通过service传入对应的接口,使用动态代理构造出代理对象
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] {
service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
...
//上面有一些代码,无关主流程,不看了,关键在这里,
//先通过loadServiceMethod,解析注解,得到ServiceMethod对象
//然后调用invoke发起实际的网络请求
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
解析注解(loadServiceMethod)
我们首先看loadServiceMethod方法的直接实现
ServiceMethod<?> loadServiceMethod(Method method) {
//看到没,这里有一个cache,也就是说注解实际上只解析一次,之后就放到缓存中
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析注解
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
接下来我们到ServiceMethod.parseAnnotations中看看怎么解析注解的
经过简单的代码走读,我们会走到HttpServiceMethod中,这个是ServiceMethod的子类
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
//这里有一些Kotlin相关的代码,我们先忽略不看,我们针对的环境是Retrofit+RxJava2
...
} else {
//这里获取我们的返回值类型
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
//这里实际上行是一个非常精巧的设计,我们的Retrofit支持自定义类来处理请求的,这里就是实际上会调用到我们的
// 创建Retrofit时设置的CallAdapterFactory里面。
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
//同上,Response的数据类型是支持自定义的,具体的解析方法在我们创建Retrofit时设置的ConverterFactory里面
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
//到这里,我们创建了CallAdapted,就算结束了,我们拿到了CallAdapted类,注意这个名字,
//这个类实际上是HttpServiceMethod的一个子类
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
}
发起网络请求
看第一章就知道,关键在invoke方法
@Override final @Nullable ReturnT invoke(Object[] args) {
//这里是不是很熟悉,我们拿到了OkHttpCall,这个实际上是最终发起网络请求的位置
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
经过简单的代码走读,我们就会发现他实际上走到了CallAdapter的adapt方法,我们找一下哪里实现了他
最终我们找到了在RxJava2CallAdapter里面,这里已经是我们在创建Retrofit时,设置的CallAdapterFactory的地盘了
继续看
//这里的Call就是我们上一段代码的OkHttpCall。
//也就是说,我们传入的CallAdapterFactory实际上就是控制我们怎么调用OkHttpCalld的问题
@Override public Object adapt(Call<R> call) {
//一个同步,一个异步,我们直接看同步的吧
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
...
}
//当RxJava被observe的时候,会走到这里,这里用CallCallback封装了下
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
if (!callback.isDisposed()) {
//这里开始发起真正的网络请求
call.enqueue(callback);
}
private static final class CallCallback<T> implements Disposable, Callback<T> {
private final Call<?> call;
private final Observer<? super Response<T>> observer;
private volatile boolean disposed;
boolean terminated = false;
CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
this.call = call;
this.observer = observer;
}
//拿到真实的网络请求结果
@Override public void onResponse(Call<T> call, Response<T> response) {
if (disposed) return;
try {
//看到没,看到没,我们熟悉的onNext
observer.onNext(response);
...
}
}
ConverterFactory
使用Retrofit是可以自定义返回值类型的,
但是很奇怪,我们直接从OkHttp中拿到的肯定是string,对吧?
所以我们需要有一个地方来讲string处理成我们需要的类型。
这个地方就是OkHttpCall
//将string转为我们需要的类型
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
...
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
...这里就是我们进行转换的地方
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}