简介
刚接触Retrofit
的时候,就写了一篇简单的使用介绍:Retrofit 2.0基本使用方法,算是对Retrofit的基础入门。也算是接触Retrofit
一段时间了,现在差不多可以对源码层进行解析,最起码,理解原理后可以使得我们使用起来更加得心应手 _。
网络请求使用基本方法
参考官网:
Introduction
Retrofit turns your HTTP API into a Java interface.
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
The Retrofit class generates an implementation of the GitHubService interface.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.
Call<List<Repo>> repos = service.listRepos("octocat");
//synchronous request
repos.execute();
//asynchronous request
repos.enqueue(new Callback<ResponseBody>() {/***/});
Use annotations to describe the HTTP request:
URL parameter replacement and query parameter support
Object conversion to request body (e.g., JSON, protocol buffers)
Multipart request body and file upload
源码解析: retrofit:2.3.0
从上一节的使用Retrofit
进行网络请求中,我们可以看到,请求过程主要分为以下几步:
- 创建一个接口进行HTTP请求描述;
- 使用
Retrofit.Builder
构建模式构造出一个Retrofit
实例; - 调用
retrofit.create()
方法获取请求接口实例; - 由请求接口实例获取到
Call
对象; - 进行网络请求(同步/异步)
接下来,我们就按照以上正常的网络请求顺序来对Retrofit
源码进行解析。
-
创建一个接口进行HTTP请求描述
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
这里主要做的就是采用注解的方式进行HTTP描述,后面在第4步由请求接口实例获取到Call
对象时进行反射提取注解内容进行HTTP请求构造(如果开启了预先加载解析(validateEagerly=true
),那么在第3步调用retrofit.create()
方法获取请求接口实例的时候就会进行注解解析),具体解析方法参考后续分析。
-
使用Retrofit.Builder构建模式构造出一个Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
那我们就先来看下Retrofit.Builder
部分源码:
/**
* Build a new {@link Retrofit}.
* <p>
* Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods
* are optional.
*/
public static final class Builder {
private final Platform platform;
//callFactory通过newCall(Request request)方法,返回一个okhttp3.Call对象,以便让我们进行实际的HTTP请求
//也就是说callFactory是我们用来生成一个客户端HTTP请求工厂实例
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
//converterFactories生产Converter<F, T>,用于将HTTP返回结果F类型转换为T类型,或将HTTP请求类型F转换为T。
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//adapterFactories生产 CallAdapter<R, T>,用于将retrofit2.Call<R>网络请求类型转换为T类型:T adapt(Call<R> var1);
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private @Nullable
Executor callbackExecutor;
private boolean validateEagerly;
···
···
···
}
从Retrofit.Builder
的注释中,我们可以看到,在调用Retrofit.Builder.build()
之前,除了baseUrl()
是必须配置的以外,其他的内容都是可选配置。
这里要对两个类型做下讲解,因为笔者在刚分析Retrofit
源码时,被这两个类型的概念弄得头晕眼胀,好在一顿分析后,终于有了一点眉目,这两个类型就是:Converter<F, T>
和CallAdapter<R, T>
。
Converter<F, T>
:数据转换器,用来将HTTP请求返回结果由F类型转换为T类型,或者将HTTP请求类型F转换为T
/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter<F, T> {
T convert(F value) throws IOException;
···
···
···
}
举例:
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
上面配置了ConverterFactory
为GsonConverterFactory
,那么当HTTP请求结果返回时,就会由GsonConverterFactory
产生的Converter
,假设为Converter<ResponseBody, List<Repo>>
,该Converter
就会将HTTP返回结果ResponseBody
转换为 List<Repo>
。
而若是将对象转换为数据,那么假设类型为:Converter< List<Repo>, RequestBody>
,该Converter
在构建请求体时,会将List<Repo>
转换为RequestBody
对象。
CallAdapter<R, T>
:请求适配器,用于将retrofit2.Call<R>
网络请求类型转换为T类型
/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is
* {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit}
* instance.
*/
public interface CallAdapter<R, T> {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type
* is used to prepare the {@code call} passed to {@code #adapt}.
* <p>
* Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();
/**
* Returns an instance of {@code T} which delegates to {@code call}.
* <p>
* For example, given an instance for a hypothetical utility, {@code Async}, this instance would
* return a new {@code Async<R>} which invoked {@code call} when run.
* <pre><code>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
* return Async.create(new Callable<Response<R>>() {
* @Override
* public Response<R> call() throws Exception {
* return call.execute();
* }
* });
* }
* </code></pre>
*/
T adapt(Call<R> call);
/**
* Creates {@link CallAdapter} instances based on the return type of {@linkplain
* Retrofit#create(Class) the service interface} methods.
*/
···
···
···
}
举例:
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
上面配置了CallAdapterFactory
为RxJava2CallAdapterFactory
,这里的作用就是将Retrofit2.Call<T>
对象转换为Observable<T>
类型,所以如果配置了RxJava2CallAdapterFactory
,那么接口方法声明应该改为如下形式:
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
其实这个addCallAdapterFactory
实现原理是挺简单的,因为Retrofit
里面维护了CallAdapter.Factory
一个数组,在使用Builder
配置的时候,所有配置的CallAdapter.Factory
最后都会保存到Retrofit
那个数组中,后面在进行转换是,Retrofit
会根据接口方法返回结果类型(此处为:Observable<List<Repo>>)
,遍历CallAdapter.Factory
数组,找到一个能处理该返回类型的CallAdapter
后,就不再遍历。更多具体的解析方法请参考后续整体流程的介绍。
上面讲了那么多的东西,可是还是没有讲到Retrofit
实例的创建,别着急,在查看Retrofit.Builder.build()
方法前,我们还要看下Builder
的构造函数:
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());
}
public Builder() {
this(Platform.get());
}
当我们调用:
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
就会走入:Builder()--> Builder(Platform platform)
然后我们看到,在Builder(Platform platform)
构造函数里面,会往converterFactories
里面添加进一个BuiltInConverters
对象,所以默认的ConverterFactory
就是BuiltInConverters
。前面说过ConverterFactory
主要是用来将HTTP返回结果进行类型转换或者将HTTP请求体进行类型转换,然后我们看下BuiltInConverters
是怎样的转换方式:
final class BuiltInConverters extends Converter.Factory {
//返回结果转换
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
//如果annotations是Streaming类型
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
//请求转换
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
@Override public Void convert(ResponseBody value) throws IOException {
value.close();
return null;
}
}
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override public RequestBody convert(RequestBody value) throws IOException {
return value;
}
}
static final class StreamingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
return value;
}
}
static final class BufferingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
}
返回结果转换的时候,有3种情况:
- 如果返回类型是
ResponseBody
类型,那么可能返回的是:StreamingResponseBodyConverter.INSTANCE
或者BufferingResponseBodyConverter.INSTANCE
,再跟踪进去这两个类里面的convert
函数:
@Override public ResponseBody convert(ResponseBody value){···}
发现传入的是ResponseBody
,返回的也是ResponseBody
(BufferingResponseBodyConverter
里面有进行特殊处理,主要是为了去除future I/O),所以我们可以认为BuiltInConverters
对HTTP返回结果没有进行转换处理。
- 如果返回类型是
Void
类型,那么最终就将ResponseBody
资源关闭后,直接返回null
。 - 如果返回类型不是
ResponseBody
和Void
类型,直接返回null
。
同理,我们来看下请求体转换:
//请求转换
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override public RequestBody convert(RequestBody value) throws IOException {
return value;
}
}
可以看到,如果是RequestBody
类型,那就不转换,如果不是RequestBody
类型,直接返回null
。
综上所述:BuiltInConverters
只能响应ResponseBody
和RequestBody
,但是并不进行任何转换.对于其他类型,统统返回null。
到这里,终于可以走进Retrofit.Builder.build()
函数,一窥究竟:
/**
* Create the {@link Retrofit} instance using the configured values.
* <p>
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
*/
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//callFactory默认为OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//默认的callbackExecutor为Platform.Android.MainThreadExecutor
//MainThreadExecutor继承Executor,并复写execute(Runnable r),
// execute内部直接通过主线程Handler.post(r),即r.run发生在主线程
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//defaultCallAdapterFactory是ExecutorCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//BuiltInConverters在Retrofit.Builder(Platform)构造时,已被传入
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
build
函数一进去,就看到:
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
这说明baseUrl
是一定要进行配置的,否则程序就会抛出异常,这跟我们上面讲到的一致。
接着往下看:
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//callFactory默认为OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//默认的callbackExecutor为Platform.Android.MainThreadExecutor
//MainThreadExecutor继承Executor,并复写execute(Runnable r),
// execute内部直接通过主线程Handler.post(r),即r.run发生在主线程
callbackExecutor = platform.defaultCallbackExecutor();
}
这里可以看到,如果没有配置okhttp3.Call.Factory
,那么就会使用默认的HTTP工厂类:OkHttpClient
,用于客户端程序创建okhttp3.Call
对象,以进行实际的HTTP网络请求。
如果没有线程调度器callbackExecutor
,那么就会使用默认的线程调度器:Platform.Android.MainThreadExecutor
:
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
从源码可以看出,默认的线程调度器是主线程调度器。
接下来再看:
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//defaultCallAdapterFactory是ExecutorCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
可以看到,这里为adapterFactories
增加了一个CallAdapterFactory
:
//Platform.java
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
//ExecutorCallAdapterFactory.java
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements retrofit2.Call<T> {
final Executor callbackExecutor;
//HTTP请求委托类
final retrofit2.Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
//异步请求
@Override
public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
//同步请求
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
···
···
···
}
在Android平台上,callbackExecutor
默认不为null,所以defaultCallAdapterFactory
返回的是ExecutorCallAdapterFactory
。从ExecutorCallAdapterFactory
的get
函数,可以看到,ExecutorCallAdapterFactory
只会响应返回类型为Call
的函数声明(所以,如果我们没有配置addCallAdapterFactory()
,那么我们接口函数声明的返回类型必须为Call<?>
),响应处理的最终结果就是返回一个CallAdapter
,这个CallAdapter
的adapt()
函数会传入一个HTTP请求委托类,然后返回一个HTTP请求代理类:ExecutorCallbackCall<T> implements retrofit2.Call<T>
,这个代理类代理了委托类的异步HTTP网络请求,并将返回结果通过线程调度器将回调监听函数分发到具体线程上执行(默认线程调度器是主线程调度)。
讲到这里,Retrofit
实例的配置创建就算是完成了。下面这个图展示了Retrofit.Builder
提供的配置选项:
-
调用retrofit.create()方法获取请求接口实例
GitHubService service = retrofit.create(GitHubService.class);
那我们接下来就看一下create()
的源码:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
//1.是否是接口
//2.不能继承其他接口
Utils.validateServiceInterface(service);
//预先加载解析注解:loadServiceMethod
//默认false,即调用接口方法后,才进行解析
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, @Nullable 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);
}
//java8平台使用
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
这里我们可以看到,create
方法返回的是一个 (T) Proxy.newProxyInstance()
方法产生的一个动态代理对象(如果不清楚动态代理,可以看下我之前写的文章:Java代理模式,里面对java的动态代理有详细讲解)。使用该动态代理对象进行方法调用后,会自动被InvocationHandler
拦截,最终进入InvocationHandler
的invoke
函数里面。
-
由请求接口实例获取到Call对象
Call<List<Repo>> repos = service.listRepos("octocat")
从上面create
的分析中,我们知道,此处的service
是一个动态代理类对象,所以,在调用方法时,会被InvocationHandler
的invoke
方法拦截,所以调用:service.listRepos("octocat")
就会进入InvocationHandler.invoke()
中,查看下invoke
函数,最主要的操作就是如下3句话:
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
ServiceMethod
在Retrofit
中是一个很重要的类,主要做的就是对接口方法注解进行解析,最终生成一个Request
。
那我们先来看下loadServiceMethod()
源码:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
serviceMethodCache
是一个缓存容器,是对接口方法的解析缓存。
//class Retrofit
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
从loadServiceMethod()
中可以看到,ServiceMethod
的实例也是通过builder
模式进行构建的,构建过程需传入Retrofit
对象和Method
对象。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//取得接口方法的注解
this.methodAnnotations = method.getAnnotations();
//返回接口方法参数类型
this.parameterTypes = method.getGenericParameterTypes();
//返回接口方法各个参数注解
//按参数声明顺序排列,每个参数可能有多个注解,故二维数组
//parameterAnnotationsArray[0][i]:第一个参数第i个注解
//parameterAnnotationsArray[1][j]:第二个参数第j个注解
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
//CallAdapter<T, R> callAdapter;适配Call的响应类型,将默认响应类型R转换为类型T
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?");
}
//Converter<ResponseBody, T> responseConverter;HTTP交互中,转换对象为数据 或 从数据转换为对象
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
···
···
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);
}
···
···
return new ServiceMethod<>(this);
}
在ServiceMethod.Builder.build()
源码中可以看到:
callAdapter = createCallAdapter();
首先创建一个callAdapter
,具体创建过程如下:
private CallAdapter<T, R> createCallAdapter() {
//接口方法return类型
Type returnType = method.getGenericReturnType();
···
···
Annotation[] annotations = method.getAnnotations();
//noinspection unchecked
···
···
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
}
可以看到,其最终调用到的是retrofit.callAdapter()
:
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(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
// final List<CallAdapter.Factory> adapterFactories;
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;
}
}
//throw exception
···
···
}
可以看到,createCallAdapter()
就是从Retrofit
的List<CallAdapter.Factory> adapterFactories
数组中,遍历找到一个可以处理该接口方法返回类型和注解的CallAdapter<?, ?>
。那根据我们之前的分析,如果我们没有进行CallAdapter
的配置,那么默认的CallAdapter
就是ExecutorCallAdapterFactory.get(Call.class,xxx,retrofit)
;
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if(getRawType(returnType) != Call.class) {
return null;
} else {
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
public Type responseType() {
return responseType;
}
public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
}
};
}
}
可以看到,默认的CallAdapter.Factory
只会响应接口方法返回类型为Call
,所以遍历adapterFactories
的时候,如果接口方法返回类型不是Call
,那么ExecutorCallAdapterFactory.get()
自然返回的就是null
,然后就会继续找下一个CallAdapterFactory
,继续尝试,直到找到能处理该接口方法返回类型的CallAdapterFactory
,由其返回一个CallAdapter
。
上面的流程可以这样想(较为生动):
createCallAdapter
说:retrofit
,给我一个能处理我这个接口方法返回类型(假设为Observable<T>
)的CallAdapter
。
retrofit
接收到请求后,就会从自己的adapterFactories
仓库中一个一个的进行询问:
首先找到默认的CallAdapter.Factory
:ExecutorCallAdapterFactory
,然后说:ExecutorCallAdapterFactory
啊,你能处理Observable<T>
这个返回类型吗?
ExecutorCallAdapterFactory
一看,说:retrofit
啊,你给我的返回类型不是Call
类型,我没办法处理,你找下一位CallAdapter.Factory
仁兄吧。
既然默认的ExecutorCallAdapterFactory
没办法处理这个接口方法返回类型,那retrofit
就只能继续问下一位CallAdapter.Factory
啦,假设下一位是RxJava2CallAdapterFactory
,然后,retrofit
开始发问,说:RxJava2CallAdapterFactory
仁兄呀,你能处理Observable<T>
这个返回类型吗?
RxJava2CallAdapterFactory
一看,说:retrofit
兄啊,你这个Observable<T>
我拿手呀,随随便便进行处理,处理的结果拿到了这个CallAdapter
,你赶紧拿着给createCallAdapter
交差吧。
retrofit
一听,太高兴了,说到:RxJava2CallAdapterFactory
兄啊,您真牛逼,谢谢您了,好的好的,我赶紧拿着您给的CallAdapter
给createCallAdapter
交差,那边催的紧呢。
于是,retrofit
高高兴兴地就往createCallAdapter
那边赶了,adapterFactories
后面还没问到的兄弟就不管了,没办法,哥(retrofit
)时间紧,没有那么多时间去一 一问候兄弟们,望兄弟们见谅 _。
我们接着看ServiceMethod.Builder.build()
方法,可以看到,createCallAdapter
后,又createResponseConverter
了:
//Converter<ResponseBody, T> responseConverter;HTTP交互中,转换对象为数据 或 从数据转换为对象
responseConverter = createResponseConverter();
responseConverter
是Converter<ResponseBody, T>
类型,其实我们一看到这个,就应该大概知道是怎么做了,肯定又是跟retrofit
请求,retrofit
又从仓库中进行查找,只是这回是从List<Converter.Factory> converterFactories
中查找,直到找到一个能处理这种responseType
的Converter.Factory
,由其返回一个Converter
。让我们看下源码是不是这样的:
//ServiceMethod.java
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
//Retrofit.java
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
/**
* Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available
* {@linkplain #converterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no converter available for {@code type}.
*/
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
//throw exception
···
···
···
}
可以看到,跟我们上面所说的过程是一样的。
还记得吗,有一个默认的retrofit2.Converter.Factory
是:BuiltInConverters
。那从BuiltInConverters
得到的Converter<ResponseBody, T>
是什么呢,根据我们之前的分析:
- 如果
responseType
是ResponseBody
类型,那么返回的还是ResponseBody
(BufferingResponseBodyConverter
有经过一些处理); - 如果
responseType
是Void
类型,那么释放ResponseBody
资源,然后返回null; - 其他
responseType
类型,直接返回null
。
所以,如果我们没有配置addConverterFactory
,那么接口返回类型应该声明为Call<ResponseBody>
或者Call<Void>
这类型的,这样,默认的retrofit2.Converter.Factory
才能进行处理。
接着看Retrofit.Builder.build()
方法,可以看到:
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
这个是一个很重要的操作,就是对接口方法进行解析,追踪进去再看下解析源码:
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else 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 PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} 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());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
可以看到里面对很多方法都进行了解析,这里,我们就只拿GET
方法解析源码来分析下解析流程,其余方法解析都是类似的:
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
···
···
···
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
按照官网那个例子,那么:this.relativeUrl = value = "users/{user}/repos"
,在parseHttpMethodAndPath
最后,调用了 parsePathParameters(value)
:
/**
* Gets the set of unique path parameters used in the given URI. If a parameter is used twice
* in the URI, it will only show up once in the set.
*/
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
这里采用正则表达式取出形如"{*}"这种结构的内容,保留在全局Set<String> relativeUrlParamNames
集合里面。
像官网这个例子,当程序来到parsePathParameters("users/{user}/repos")
的时候,正则表达式就获得了user
这个字符串,并存储到全局relativeUrlParamNames
里面。这样,接口方法的可变字符串就被记录了起来,后续只要获取到参数注解内容的名字是一样的(eg:@Path("user") String user
,参数注解内容是"user“
),将参数转换(Converter
,默认为StringConverter
,转换就是直接调用参数对象的toString()
方法转成字符串)放入方法路径可成为一个真正的relativeUrl
。
以上就是方法注解的解析过程。
但是接口方法参数的注解还没进行解析,那我们就继续往下看ServiceMethod.Builder.build()
方法,可以看到:
//有多少个参数带注解
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中
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
参数注解解析过程的最后调用了:parseParameter
,这个方法会根据传入的参数类型和对应注解集合进行解析,封装成为ParameterHandler
,将每个参数的注解解析最后都存入到parameterHandlers
数组中,所以parameterHandlers[0]
就是第一个带注解的参数的解析内容,parameterHandlers[1]
就是第二个带注解的参数的解析内容····:
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
return result;
}
可以看到parseParameter
主要做的就是遍历参数的所有注解,一个一个进行注解解析:parseParameterAnnotation
,这个方法内部代码特别长,因为有很多种注解需要分析,在这里,我们就只抽取出@Path
的注解解析部分内容:
//参数注解解析
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
····
····
····
else if (annotation instanceof Path) {
if (gotQuery) {
throw parameterError(p, "A @Path parameter must not come after a @Query.");
}
if (gotUrl) {
throw parameterError(p, "@Path parameters may not be used with @Url.");
}
if (relativeUrl == null) {
throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod);
}
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
/**
* 有效性检验:
* 1.命名规范:必须符合正则:[a-zA-Z][a-zA-Z0-9_-]*
* 2.注解value必须存在relativeUrlParamNames方法变量,对应起来
*/
validatePathName(p, name);
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(name, converter, path.encoded());
}
···
···
···
}
这里对@Path
的解析最主要的就是获取一个Converter<?, String>
,获取是通过retrofit.stringConverter()
:
/**
* Returns a {@link Converter} for {@code type} to {@link String} from the available
* {@linkplain #converterFactories() factories}.
*/
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<?, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, String>) converter;
}
}
// Nothing matched. Resort to default converter which just calls toString().
//noinspection unchecked
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
同样,这里是通过遍历converterFactories
,找到一个能处理这种类型type
的Converter.Factory
,返回一个 Converter<?, String>
,如果找不到,就使用BuiltInConverters.ToStringConverter.INSTANCE
。查看下BuiltInConverters.ToStringConverter.INSTANCE
源码:
//BuiltInConverters.java
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
可以看到,默认的StringConverter
就是通过调用paramter
对象的toString
方法,直接将结果类型转成String
类型。
到这里,我们就明白了:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
接口方法参数user
的类型其实可以不用是String
类型,就算是其他类型也可以,但是默认的StringConverter
调用该类型对象的toString
方法返回的结果要符合你自己需求。
比如,我们现在自定义一个java bean:
public class StringWrapper {
private String content;
public StringWrapper(String content)
{
this.content = content;
}
@Override
public String toString() {
return content;
}
}
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") StringWrapper user);
}
这样也是可以的,因为StringWrapper.toString
跟我们上面直接定义成的String
最终结果是一样的。
回到正题,parseParameterAnnotation
中对@Path
的解析最终会返回一个ParameterHandler.Path
对象:
static final class Path<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) {
throw new IllegalArgumentException(
"Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
}
最后,参数解析所有的信息都放入到了全局数据parameterHandlers
中,没个parameterHandlers[i]
都包含了各个参数的所有注解解析信息。
到这里,
ServiceMethod.Builder.build()
方法也算是解析完毕了。总结一下:ServiceMethod的创建过程主要做了几件事:
- 根据接口方法返回类型,通过遍历
retrofit
的adapterFactories
列表,找到适合的CallAdapter<T, R> callAdapter
。 - 根据HTTP返回结果类型,通过遍历
retrofit
的converterFactories
列表,找到适合的Converter<ResponseBody, T> responseConverter
。 - 对接口方法注解进行解析:
parseMethodAnnotation(Annotation annotation)
。 - 对接口方法参数注解进行解析:
parseParameter
- 完成以上工作后,创建
ServiceMethod
对象。
最后,用一张图来表达下ServiceMethod
的创建过程:
现在继续分析
Retrofit.create
中InvocationHandle
r的invoke
剩余部分源码:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
这里创建了一个okHttpCall
:
final class OkHttpCall<T> implements retrofit2.Call<T> {
···
···
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
···
}
OkHttpCall<T>
这里可以看到OkHttpCall内部持有一个okhttp3.Call,所以其实OkHttpCall所进行的HTTP请求实际上都是交由okhttp3.Call进行的。
InvocationHandler
的invoke
最后返回了:
return serviceMethod.callAdapter.adapt(okHttpCall);
经过前面的分析,假设我们对Retrofit
没有经过特殊配置,即Retrofit
采用默认配置,那么:serviceMethod.callAdapter
返回的就是默认的ExecutorCallAdapterFactory.get(Call.class,annotations,retrofit)
//ExecutorCallAdapterFactory.java
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
serviceMethod.callAdapter.adapt(okHttpCall)
返回的就是一个new ExecutorCallbackCall<>(callbackExecutor, okHttpCall)
的对象。
static final class ExecutorCallbackCall<T> implements retrofit2.Call<T> {
final Executor callbackExecutor;
//HTTP请求委托类
final retrofit2.Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
这里可以看到,ExecutorCallbackCall
就是okHttpCall
的代理类,而okHttpCall
又持有okhttp3.Call
实例。因此,进行HTTP请求的过程就明晰了:
ExecutorCallbackCall.enqueue-->okHttpCall.enqueue-->okhttp3.Call.enqueue
ExecutorCallbackCall
持有的Executor callbackExecutor
默认是主线程调度器,会将ExecutorCallbackCall
发送HTTP请求的返回结果回调到主线程上执行。
那我们最后就来看一下发送网络请求的具体过程。
-
进行网络请求(同步/异步)
网络请求是通过我们得到的ExecutorCallbackCall<>(callbackExecutor, okHttpCall)
对象进行请求,这里就只看下异步请求过程:
repos.enqueue(new Callback<ResponseBody>() {/***/});
上面分析知道,ExecutorCallbackCall
内部封装了网络请求和线程调度作用,而实际起网络请求作用的是OkHttpCall
。
那我们就来看下OkHttpCall
的异步网络请求enqueue
源码:
@Override
public void enqueue(final Callback<T> callback) {
···
···
okhttp3.Call call;
···
···
call = rawCall = createRawCall();
···
···
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
···
···
callSuccess(response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
···
callback.onFailure(OkHttpCall.this, e);
···
}
···
···
}
}
可以看到,OkHttpCall
里面是通过函数createRawCall
获得一个真正的能用于HTTP网络请求的okhttp3.Call
对象,那么我们就来看下createRawCall()
源码是怎样构建出一个okhttp3.Call
对象:
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;
}
这里,我们先来看下:
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
serviceMethod.callFactory
默认就是retrofit
的callFactory
,也就是OkHttpClient
,所以这里就是由OkHttpClient
创建出一个真正用于进行HTTP网络请求的okhttp3.Call
对象。
接下来我们回顾上一行代码,可以看到是通过serviceMethod.toRequest(args)
构建出一个Request
,此处的args
就是我们接口方法的参数,那么我们就先来看下serviceMethod.toRequest
源码是怎样构建一个Request
的:
/** Builds an HTTP request from method arguments. */
Request toRequest(@Nullable Object... args) throws IOException {
//从接口方法注解解析信息
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
//接口方法参数注解解析信息
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
所以我们前面为什么说ServiceMethod
在Retrofit
里面是很重要的,在这里也可以知道,ServiceMethod
既负责解析接口方法,接口参数,又负责从retrofit
那边获取合适的CallAdapte
r和Converter
,又要负责将接口解析出来的内容组装成一个HTTP Request···可以说,ServiceMethod
就是Retrofit
的核心引擎。
回到toRequest
函数,从上面的源码中可以看到,首先是根据接口方法解析的信息组装成了一个RequestBuilder
,然后再根据方法参数信息(Object... args
),经由之前解析的参数注解信息可以得到一个最终的RequestBuilder
,由这些信息就可以build
出一个Request
。
toRequest
里面有句代码是:
handlers[p].apply(requestBuilder, args[p]);
这里其实获取得到的就是接口方法第p个参数解析出来的效果,举个例子来说,比如,我们之前handlers[p]
解析出来的是@Path
的信息,那么handlers[p]
就是一个ParameterHandler.Path
类型的对象,而ParameterHandler.Path
是ParameterHandler
静态内部类,同时也是一个ParameterHandler
子类:
static final class Path<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) {
throw new IllegalArgumentException(
"Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
}
所以,handlers[p].apply(requestBuilder, args[p])
按官网的例子就变成了:
Path.apply(requestBuilder,String user)-->builder.addPathParam(”user", valueConverter.convert("user"), encoded);
而由我们前面的分析,此处的valueConverter
默认是ToStringConverter
:
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
所以valueConverter.convert("user")-->"user".toString()=="user"
,所以最终返回的就是字符串"user"
,所以:
builder.addPathParam(”user", valueConverter.convert("user"), encoded)-->builder.addPathParam(”user", "user", encoded)。
对于@Path
来说,肯定是将参数信息替换掉接口方法注解内容相对路径的{*}内容,所以,builder.addPathParam
就是实现这个功能的:
void addPathParam(String name, String value, boolean encoded) {
if (relativeUrl == null) {
// The relative URL is cleared when the first query parameter is set.
throw new AssertionError();
}
relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
}
经过以上步骤,就构建出了一个HTTP请求。
最后,我们就可以用这个请求进行真正的网络发送call.enqueue
,回顾上面OkHttpCall.enqueue
方法,可以看到请求返回结果解析是在:
//OkHttpCall.enqueue片段代码
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
可以看到,请求成功的时候,会调用parseResponse
得到一个我们需要的Response<T>
类型对象,具体解析方法如下:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
···
···
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
···
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
···
}
parseResponse
就是对得到的rawResponse
进行处理判断,最后交由到serviceMethod.toResponse
做出最终的转换。
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
可以看到这里就是用到了数据转换器Converter<ResponseBody, R>
将HTTP返回结果ResponseBody
转换成我们自己定义的类型R
(默认的Converter.Factory
是BuiltInConverters
,它所生产的Convert
默认不对ResponseBody
进行转换)。
所以分析到了这里,Retrofit
整体的流程我们也差不多整理完毕了。
最后进行总结一下:
- 我们要是用
Retrofit
进行HTTP网络请求的时候,首先要创建一个接口进行HTTP动作描述,之所以用接口是为了后面动态创建一个对应的接口代理类(java的动态代理只能支持接口); - 接口描述创建完成后,通过建造者模式可以配置出一个
retrofit
实例 - 由
retrofit
的`create函数就可以创建出一个接口的动态代理类 - 调用动态代理类的接口方法时,就会被动态代理类拦截,拦截的主要原因就是为了隐式的创建出一个用于HTTP网络请求的
Call
对象,具体做了3件事:
1. 解析接口注解内容并保存,功能类为ServiceMethod
。
2. 创建一个OkHttpCall
对象,OkHttpCall
内部持有okhttp3.Call
实例。OkHttpCall
的作用就是从ServiceMethod
和当前参数获取得到一个Request
,并通过OkHttpClient
根据这个Request
创建出一个okhttp3.Call
对象。
3. 最后从ServiceMethod
中拿到一个可以处理接口方法返回类型的CallAdapter
,由其adapt
返回得到一个可以对HTTP请求结果进行线程调度的retrofit2.Call
对象(该Call
对象是OkHttpCall
的代理类)。
网友评论