下面的使用不涉及到添加请求适配器、返回转换器等。
返回的就是最纯正的ResponseBody
interface MyApi {
@POST("query.php")// 表示改接口使用post的方式请求
@FormUrlEncoded// 表示content-type为:application/x-www-form-urlencoded
fun queryByTitle(@Field("param") paramJsonStr: String, @Field("type") type: Int = 0):Call<ResponseBody>
}
关于Retrofit中的注解有哪些,作用分别是什么,推荐看这篇文章:《Android 网络框架:Retrofit2注解篇》
val baseUrl = "https://www.*.com/aabb/"
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.build()
注意:baseUrl一定要以"/"结尾,具体原因会在后面的源码中说明。
val api = retrofit.create(MyApi::class.java)
// 请求参数
val paramJson = JsonObject()
paramJson.addProperty("title", "黄金瞳")
val call = api.queryByTitle(paramJson.toString())
// 异步请求
call.enqueue(object :Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
// 请求失败
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
// 请求成功
Log.d("d",response.body()?.string())
}
})
// 同步请求
// 这里会出错,因为Android不允许在主线程执行网络请求
val response = call.execute()
Log.d("d",response.body()?.string())
首先看看Retrofit.Builder
的构造函数。
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
Builder(Retrofit retrofit) {
...省略代码
}
有三个构造函数,一般来说都使用的是无参构造函数,然后可以看到调用了Platform.get()
,根据名字可以猜到这里是确定当前执行代码的平台。进去看看。
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
// 查看是否是Android平台
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
// 返回Java8平台
return new Platform(true);
}
由于上面的例子是在Android中写的,因此这里分析的时候也可以看到返回的是一个Android
对象。关于这个对象,功能很简单,就是提供了一个主线程Handler
,用于将任务回调到主线程中去。
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
// 返回了一个主线程执行器
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
// 主线程handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
// 将任务提交到主线程的队列中,这样任务就可以在主线程中执行了
// 完成了线程切换
handler.post(r);
}
}
}
现在回去Retrofit.Builder
中的baseUrl()
方法看看是如何处理传入的String
的。
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
先检查了一下是否为Null,然后将String
类型的url转换成HttpUrl
的形式。
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();// 这一步是将url进行拆解
// 必须以"/"结尾
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
这里主要是对url进行拆解,并判断是否是以"/"结尾。
配置好baseUrl
之后,再去看看build()
方法是如何生成Retrofit
对象的。
public Retrofit build() {
// 必须要设置baseUrl,在设置的时候还会检查baseUrl是不是以"/"结尾
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 所谓的callFactory 就是okHttpClient 可以看做为一个浏览器
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 这里大部分情况下是没设置的,因此这里的platform基本为Android()
// 返回的默认执行器也是主线程执行器,用于将runnable用主线程handler执行
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
// 翻译:制作适配器的防御副本,并添加默认的呼叫适配器。
// 这里优先添加自己配置的CallAdapterFactory,然后再在末尾添加一个默认的
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
// 制作防御者的副本。
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// 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());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
这一步主要涉及这几个变量的赋值:callFactory
、callbackExecutor
、callAdapterFactories
、converterFactories
。
需要注意的是,callAdapterFactories
和converterFactories
中,index越小的元素是越先被获取到的。另外可以看到,对于callAdapterFactories
是优先加入用户配置的然后才加入默认的;而converterFactories
则相反,它先加入了一个默认的,然后才加入用户配置的。
callbackExecutor
是由platform
提供的,根据上面的源码可以看到,这里返回了一个MainThreadExecutor
。用于将非主线程任务回调到主线程中。
至此,Retrofit
对象就创建好了,很明显使用了设计模式-建造者模式。
去到Retrofit
中的create()
方法看看。
public <T> T create(final Class<T> service) {
validateServiceInterface(service);// 验证接口,以及判断是否要提前解析注解,默认为false
/**
* 动态代理的方式创建interface对象
* @param service.getClassLoader() 类加载器
* @param new Class>[] { service } 要实现的类接口
* @param new InvocationHandler() 处理调用方法的InvocationHandler
* @return 返回接口中声明的对象类型
*/
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 {
...省略部分代码
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
这里的话,使用到了代理模式中的动态代理。关于代理模式,可以看看这篇文章:《【Java】小例子巧妙理解代理模式》。这样,服务端ApiInterface对象也创建好了,注意这里是创建的代理对象。
下面,看看调用其中的方法时,源码是如何执行的
了解动态代理的话应该知道,当调用代理对象的方法的时候,实际上会调用到InvocationHandler
中的invoke()
。
那么这里的话,就是调用到上面create()
中的invoke()
方法了。
如果略过第一行的校验代码的话,可以看到整个方法关键之处在于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 = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
该方法会返回一个ServiceMethod
对象,首先从缓存中查找是否有已经生成的,如果没有则调用ServiceMethod.parseAnnotations()
去生成一个,再加入到缓存中。
那么继续看看这个生成ServiceMethod
的方法。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
/**这里解析注解*/
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...省略部分校验代码
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
首先生成了一个RequestFactory
对象,根据名字,猜测应该是用于构建请求的工厂。
然后调用HttpServiceMethod
中的parseAnnotations()
方法。注意,根据idea查看,HttpServiceMethod
是ServiceMethod
这个类的唯一子类。小技巧:idea系列的代码编辑器可以通过alt+h
来查看当前类的子类以及父类。
那么根据先后顺序,先看看RequestFactory
是如何生成的,进入RequestFactory.parseAnnotations()
。
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
又是熟悉的Builder
类,建造者模式。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();// 获取方法注解
this.parameterTypes = method.getGenericParameterTypes();// 获取参数值类型
this.parameterAnnotationsArray = method.getParameterAnnotations();// 获取参数注解
}
这里的Method
就是上面的ApiInterface中的方法。即MyApi.queryByTitle()
。
可以看到,在构造函数中,根据传入的方法,获取到了方法注解、返回值类型、参数注解。
然后看看建造者模式中最精华的build()
方法。
RequestFactory build() {
// 解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...省略部分校验代码
// 解析参数注解
int parameterCount = parameterAnnotationsArray.length;// 方法参数数量
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...省略部分校验代码
return new RequestFactory(this);
}
很显然,这里在忽略了校验代码之后,主要就是将ApiInterface中的方法注解和参数注解解析出来。
首先看看解析方法注解的方法。
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);
} 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(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
看上去很头疼,这么多的if else if
语句。实际上的逻辑其实非常简单。
首先,判断注解是否属于请求方式类型的注解,如果是的话则调用parseHttpMethodAndPath()
解析出请求方式以及请求参数。
其次,如果是Headers
注解的话,就调用parseHeaders()
将要设置的请求头解析出来。
最后,如果是关于设置content-type
的注解的话,则将对应的标志位设置为true
。
老规矩,根据代码顺序,看看调用的方法中的逻辑。
首先是parseHttpMethodAndPath()
。
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
// 之前已经定义过请求方式了,再重新定义就抛出异常
throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
// 翻译:获取相对URL路径和现有查询字符串(如果存在)。
int question = value.indexOf('?');// 第一个"?"出现的位置
if (question != -1 && question < value.length() - 1) {// 存在"?",并且不在末尾
// Ensure the query string does not have any named parameters.
// 翻译:确保查询字符串没有任何命名参数。
String queryParams = value.substring(question + 1);// 所有查询参数
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
// 翻译:URL查询字符串“%s”不得包含replace块。对于动态查询参数,请使用@Query
throw methodError(method, "URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
首先判断是否已经定义了请求方式了,然后又一个正则判断,用于查看相对url中是否存在动态查询参数。
如果有查询字符串,如:“index.php?key=value&key1={param1}”,那么这里就会抛出异常,因为查询字符串应该使用@Query
这个注解。
最后调用parsePathParameters()
将请求参数解析出来。这个方法就不在这里贴代码了,有兴趣的可以自行去查看。逻辑很简单,也是使用正则表达式进行匹配的。
现在回到前面,再看看parseHeaders()
这个方法是如何把@Headers
注解解析出来的。
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder();
for (String header : headers) {
int colon = header.indexOf(':');// 第一个冒号":"的位置
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
// 冒号不存在、冒号在开头、冒号在结尾都会出错
throw methodError(method,
"@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
}
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
// 针对content-type的特殊处理,生成MediaType
if ("Content-Type".equalsIgnoreCase(headerName)) {
try {
contentType = MediaType.get(headerValue);
} catch (IllegalArgumentException e) {
throw methodError(method, e, "Malformed content type: %s", headerValue);
}
} else {
builder.add(headerName, headerValue);
}
}
return builder.build();
}
整个方法分为两个部分,第一部分利用冒号":"所在的位置,将请求头分割为headerName
和headerValue
。
第二部分是针对content-type
的特殊处理,MediaType
类型,注意:content-type
这个请求头并没有加入到builder
中,而是特地用一个contentType
变量保存起来了。
OK,到这里,关于方法中的注解就解析完成了,下面就要准备去解析参数中的注解了。
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
// 多个参数注解将报错
throw parameterError(method, p,
"Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
...省略校验代码
return result;
}
这个方法主要是循环注解,为每个参数注解都生成一个ParameterHandler
对象。
关键方法是parseParameterAnnotation()
。
这个方法比前面解析方法注解那个方法还要长,所以这里只针对性的挑选部分代码贴出来。
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
validateResolvableType(p, type);
...省略部分校验代码
gotUrl = true;
// @Url这个注解所标注的参数类型只能是:
// HttpUrl,String,URI,Uri(Android平台特有)
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl(method, p);
} else {
throw parameterError(method, p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
}
else if (annotation instanceof Path) {
validateResolvableType(p, type);
...省略部分校验代码
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);// 验证是否和url中声明的动态参数一致
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
}
else if (annotation instanceof Query) {
validateResolvableType(p, type);
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();// 是否需要urlEncode,默认false
Class<?> rawParameterType = Utils.getRawType(type);
gotQuery = true;
...这里简化了代码
return new ParameterHandler.Query<>(name, converter, encoded);
}
...省略部分代码
return null; // Not a Retrofit annotation.
}
即使只贴了部分代码,整个方法依然很长,但是整体逻辑很简单,就是根据注解类型返回对应的ParameterHandler
即可。
那么ParameterHandler
到底有什么作用呢?进去这个类看看就知道到了。
abstract class ParameterHandler<T>
是一个抽象类,那么老规矩,ctrl+h
查看一下它的子类。
可以看到有很多子类,而且注意一下可以发现,和注解是一一对应的,每个注解都对应了一个ParameterHandler
,这里的话就随便选一个进行分析吧。
static final class Field<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Field(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = Objects.requireNonNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String fieldValue = valueConverter.convert(value);
if (fieldValue == null) return; // Skip null converted values
builder.addFormField(name, fieldValue, encoded);
}
}
关键方法是apply()
,该方法接收两个参数,一个是RequestBuilder
,一个是value
。
首先将value用转换器转换成String
类型,然后将其赋值给RequestBuilder
。看过这么多建造者模式,看到这个很自然就知道,这里就是将参数注解解析后的值传给Request
。
到这里,生成RequestFactory
就完成了,然后回到前面,继续看看后面的代码。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
/**这里解析注解*/
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...省略部分校验代码
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
下面就是看看这个HttpServiceMethod.parseAnnotations()
方法干了什么了。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
// 获取返回值的类型
Type adapterType;
if (isKotlinSuspendFunction) {
...kotlon协程相关
} else {
adapterType = method.getGenericReturnType();
}
/**创建请求适配器*/
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
/**返回值类型,在Interface的方法中自己定义的*/
Type responseType = callAdapter.responseType();
// 校验返回值类型是否合法
...省略部分校验代码
/**创建返回值转换器*/
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;// 这里就是配置okHttpClient
// 选择返回哪种HttpServiceMethod
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
// 翻译:noinspection未经检查的Kotlin编译器保证ReturnT为Object。
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
这个方法主要是获取返回值转换器、请求适配器。
虽然获取的时候,函数名为create,然而实际是上调用到了Retrofit
中的方法去获取之前配置的(没有配置则选择默认的)。
从代码最后面的部分可以看到,返回的类型有三种,然而实际上只需要关注CallAdapted
这个即可,因为另外的两个是给kotlin的协程使用的。
OK,到这里,ServiceMethod
也创建好了,回到最初的原点,看看获取到ServiceMethod
之后的代码是怎么样的。
public <T> T create(final Class<T> 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 {
...省略部分校验代码
// 当调用生成的ApiInterface中的方法的时候,实际上回调用到这里
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
可以看到,当获取到ServiceMethod
对象之后,立刻调用了它的invoke()
方法,那么回到前面的源码,看看invoke()
中又进行了什么操作。
@Override
final @Nullable ReturnT invoke(Object[] args) {
// 创建实际请求对象
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
这里创建了一个OkHttpCall
,顾名思义,它就是用来发起请求的最终对象了。
另外还调用adapt()
,因为之前说了只关注CallAdapted
这个子类,所以这里直接分析CallAdapted
的adapt()
方法。
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
/**先调用callAdapter.Factory.get,获取到callAdapter
* 默认情况下是DefaultCallAdapterFactory*/
return callAdapter.adapt(call);
}
很简单,返回了一个由callAdapter
生成的对象。
由于本次源码分析没有引入其他的callAdapter
,因此这里的就是Retrofit
默认的callAdapter
了。那回到Retrofit.Builder.build()
方法中,看看默认的callAdapter
是谁?
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
调用了platform.defaultCallAdapterFactories()
,那么跟进看看方法里面是什么样子的。
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
实例化了一个DefaultCallAdapterFactory
。
继续跟进,在它的get()
方法中,发现返回了一个callAdapter
。
@Override
public @Nullable CallAdapter<?, ?> get(
...省略部分代码
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
};
}
首先判断了下是否有@SkipCallbackExecutor
这个注解,如果有这个注解的话就不进过ExecutroCallback
了,直接返回当前的call
对象。否则则返回一个ExecutorCallbackCall
。
至此,调用服务端ApiInterface中的方法也分析完成了,这一步主要就是将各种注解解析出来,然后拼接成一个RequestBuilder
对象,最后生成一个call
的子类ExecutorCallbackCall
。
根据前面的分析,可以很明显的知道,其实调用发起请求的对象是ExecutorCallbackCall
。
那么下面就来分别看看,它的异步请求和同步请求是如何执行的。
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
// 实际调用的是OkHttpCall的方法
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(() -> {
// 这里就回到主线程了
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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
这里可以看到,只是调用了delegate.enqueue()
,并在回调函数中使用callbackExecutor
执行。
通过前面的分析,可以知道callbackExecutor.execute()
只是将任务交给主线程Handler
而已,因此这里不再过多关注。更多的关注到delegate
这个对象。
在前面构建OkHttpCall这一步的时候,传入到CallAdapter
中的call
是一个OkHttpCall
。然后该call
一直被原封不动的继续向下传递,一直传递到了ExecutorCallbackCall
。那么显然这里的delegate
就是前面构建的OkHttpCall
了。既然如此delegate.enqueue()
,也就是OkHttpCall.enqueue()
。
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
...
call = rawCall = createRawCall();
...
...
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
...
// 解析response
response = parseResponse(rawResponse);
...
callback.onResponse(OkHttpCall.this, response);
...
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
...省略部分代码
}
});
}
到这里,如果以前用过OkHttp的话,就很熟悉啦。这不就是OkHttp的异步请求吗?
首先将Retrofit.Call
转换成OkHttp.Call
,调用了createRawCall()
这个方法。
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
这个方法就利用到了前面构建的RequestFactory
啦。将其变成了OkHttp.Request
,这样OkHttp才能够发起正确的请求。
请求成功后,调用parseResponse()
将OkHttp返回的响应结果解析成用户想要的返回结果。这个方法留在后面分析。
现在,来看看同步请求。
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
...省略部分校验代码
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
同步请求就更简单了,没啥可说的了,转换后的OkHttp.Call
直接调用execute()
方法获取响应结果,然后同样调用parseResponse()
去将响应结果转换成用户想要的形式。
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();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
// 翻译:缓冲整个主体以避免将来的I / O。
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
// 204:请求没有数据返回,但是头信息有用。用户代理(浏览器)会更新缓存的头信息
// 205:告诉用户代理(浏览器)重置发送该请求的文档。
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 大部分情况下,不设置转换器的时候,返回类型都是ResponseBody
// 这个时候会使用到BuiltInConverters中的StreamingResponseBodyConverter或BufferingResponseBodyConverter
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;
}
}
这次没有省略代码了,因为这个方法里面的大部分代码都很有必要知道。
首先克隆了一个原响应,这一步如果用过OkHttp原生的话应该知道为什么。因为OkHttp原响应只允许你读取一次,读取完之后就关闭了,如果你还想再去读的话,则会抛出异常java.lang.IllegalStateException: closed
。
然后根据响应状态码进行不同的处理,这里的话只分析一下正常的流程。
调用了一个responseConverter
对响应进行转换。那么这个responseConverter
又从哪里来呢?
回想之前在配置Retrofit
的时候,似乎在Retrofit.Builder
中有涉及到。
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
由于没有自己配置转换器,因此这里只有一个BuiltInConverters
和平台默认的转换器。而平台默认转换器只有在**Java8和Android API 24+**才有,而且只能转换成Optional
的形式,所以这里很显然会调用到BuiltInConverters
中去进行转换。
进入BuiltInConverters
中可以看到有这么几个内置的转换器,分别是:
BufferingResponseBodyConverter
RequestBodyConverter
StreamingResponseBodyConverter
ToStringConverter
UnitResponseBodyConverter
VoidResponseBodyConverter
分别查看后发现,只有BufferingResponseBodyConverter
和StreamingResponseBodyConverter
这两个转换器是转换成ResponseBody
的。
它们两者的区别主要是这样的。BufferingResponseBodyConverter
会将返回结果写入到内存中,如果响应结果过大的话就会发生内存溢出异常了,比如下载文件的时候。而StreamingResponseBodyConverter
则不会将结果写入到内存。它们两个之间如何选用,是根据是否使用了@Streaming
这个注释来判断的。
可以在BuiltInConverters.responseBodyConverter()
中看到。
@Override public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
if (type == ResponseBody.class) {
// 根据是否有@Streaming注解来觉得使用哪个转换器
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
if (checkForKotlinUnit) {
try {
if (type == Unit.class) {
return UnitResponseBodyConverter.INSTANCE;
}
} catch (NoClassDefFoundError ignored) {
checkForKotlinUnit = false;
}
}
return null;
}
基本源码分析到这里就结束了。当然在日常的开发中,经常会将Retrofit和RxJava、Gson、Kotlin协程等一起配合使用。这就涉及到请求与响应是如何进行转换的,这是这篇文章没有分析到的。
通过基本的分析,可以看到Retrofit使用了大量的设计模式,而这些设计模式也让它能够很快速的去适配其他框架。比如经典的适配Gson以及RxJava,就是因为它使用的策略模式。Retrofit本身并不负责转换请求以及响应,都交给了转换器去执行。而对用户而言,只需配置自己需要的转换器,即可轻松的完成转换,而不需要任何其他的代价。
另外,Retrofit本质上其实只是对OkHttp进行了封装,使用过OkHttp原生的人都知道,如果不进行封装的话,每次发起请求都要写一大堆的重复代码。如果有兴趣看看OKHttp的源码,可以关注我的这篇文章:《【Android】OkHttp系列目录》