前言
Retrofit这个强大的网络请求库相信每个做安卓的小伙伴们都不陌生,通过简单的构造之后,只需要在create中提供一个接口,就可以方便的跟后台做数据交互了,那么Retrofit到底是怎么实现这么强大的功能的呢?接下来我们就一探究竟,看看大名鼎鼎的Retrofit源码!
Retrofit源码目录(基于2.5.0)
首先我们能看到,Retrofit源码总共只有46个类(OMG,是不是突然觉得怎么这么少~~~),其中还包含了25个注解类,剩下21个类才是真正的源码(感觉一下子少了一半的工作量)。。。
真正要看的源码
注解类
请求方式注解(7个)
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
方法上部注解 (5个)
- FormUrlEncoded
- Headers
- HTTP
- Multipart
- Streaming
方法参数注解 (12个)
- Body
- Field
- FieldMap
- Header
- HeaderMap
- Part
- PartMap
- Path
- Query
- QueryMap
- QueryName
- Url
其他注解 (1个)
- EverythingIsNonNull
从Retrofit使用流程来阅读源码
首先我们来看看Retrofit官方推荐的使用流程
//首先通过Builder建造者模式拿到builder对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")//设置BaseUrl
.addConverterFactory(GsonConverterFactory.create())//添加Json的转换器
.build();//调用build()方法得到retrofit对象
//调用create()方法并传入我们的接口类,得到接口的对象?????
MyApi api = retrofit.create(MyApi.class);
//用接口的对象调用接口里面的方法?????
Response obj = api.doSomething().execute();
其实在使用的时候,我们就应该会有疑问,问什么我传入了一个接口,Retrofit却返回给我们一个接口的实体类?
Retrofit.Builder()
首先我们从Retrofit.Builder()这个方法看起,点进去之后,我们发现,里面调用了 this(Platform.get())这个方法
public static final class Builder {
public Builder() {
this(Platform.get());
}
}
我们可以看到这里调用了一个带参数的构造方法,继续往下点查看Platform.get()方法(这里贴出Platform部分代码)
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
}
顾名思义,Platform就是平台的意思,这里get()方法返回了PLATFORM对象,而该对象又是由findPlatform()方法赋值的,继续看
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
可以看到,findPlatform()方法最终会返回Android()或者Java8()这两种平台其中一种,平台不同,处理方式也不同,比如判断是否为默认方法,创建默认的CallbackExecutor等等。这里贴出Android类(Java8也是继承自Platform)
static class Android extends Platform {
@IgnoreJRERequirement // Guarded by API check.
@Override boolean isDefaultMethod(Method method) {
if (Build.VERSION.SDK_INT < 24) {
return false;
}
return method.isDefault();
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
@Override int defaultCallAdapterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
}
@Override List<? extends Converter.Factory> defaultConverterFactories() {
return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.<Converter.Factory>emptyList();
}
@Override int defaultConverterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
那么看到了这里,我们的platform对象算是拿到了,回到Retrofit.Builder()方法, 通过刚才的看源码,我们知道里面的Platform.get()得到的是一个platform对象,然后又调用了自己带参数的构造方法
public static final class Builder {
private final Platform platform;
Builder(Platform platform) {
this.platform = platform;
}
}
带参数的构造方法里面就是给自己的成员变量赋值操作,那么到此我们的Retrofit.Build()方法算是走完了。
通过Retrofit.Build()这一步,我们完成的事情有:
- 根据条件判断,得到Android或者Java8的Platform对象
- 把得到的Platform对象给Retrofit类里面的成员变量
private final Platform platform
赋值
baseUrl()方法
刚才我们的Retrofit.Builder()方法调用完成之后,下面继续调用了baseUrl("your baseUrl')这个方法,继续来看看吧!
public final class Retrofit {
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
传入baseUrl之后,首先判断了一下,是否为空,如果为空则直接抛出异常,否则调用baseUrl(HttpUrl.get(baseUrl))
方法,那么我们来看一下HttpUrl.get(baseUrl)
做了哪些操作吧!
public final class HttpUrl {
public static HttpUrl get(String url) {
return new Builder().parse(null, url).build();
}
}
注意,这里的HttpUrl是okhttp的类,所以我们不展开太详细的介绍,大体的讲一下里面的逻辑即可,主要是看Retrofit里面的源码。可以看到,HttpUrl.get(baseUrl)
方法里面,创建了一个Builder
调用parse()
方法来解析我们传进来的url,而这个parse()
方法,主要是做了一些验证的逻辑,比如是否http
或者https
之类的,最终调用build()
拿到了一个HttpUrl
对象。然后把这个对象传到了baseUrl(HttpUrl baseUrl)
这个方法里面。
public final class Retrofit {
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
}
大家可以看到,这里先是判断baseUrl
是否为空,如果不为空,再判断baseUrl
的结尾是否是以“/”
结尾的,如果不是,则抛出异常!!!(所以说baseUrl必须要以/
结尾,哈哈哈),如果baseUrl没问题,则给自己的baseUrl赋值。
小插曲:如果碰到需求,要求我们动态修改baseUrl的值,怎么办?
大家都知道,Retrofit其实并没有提供修改baseUrl方法的,但是在真实开发中,确实会有这样的需求,比如我们给测试打包,有个button可以一键切换debug和release地址,如果不动态修改的话,我们就只能给测试打2个包,测试还得来回安装卸载,很麻烦,既然Retrofit没有提供,我们就自己想办法去动态修改他的baseUrl吧(毕竟源码都看了,是吧!)。
传送门:如何动态修改retrofit的baseUrl
www.baidu.com
addConverterFactory(GsonConverterFactory.create())
设置好了baseUrl之后,我们需要调用addConverterFactory()方法来设置一个转换器,进去瞅瞅呗。
public final class Retrofit {
private final List<Converter.Factory> converterFactories = new ArrayList<>();
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
}
还是老规矩,先做了非空判断(真TM严谨。。。),若不为空,则把我们传进来的factory
对象添加到了converterFactories
里面。
差点忘了看我们传进来的factory
是什么了。。。,看下GsonConverterFactory.create()
吧。
public final class GsonConverterFactory extends Converter.Factory {
public static GsonConverterFactory create() {
return create(new Gson());
}
}
0.0 没想到吧,里面居然只是new Gson()。。。
build()
一些参数设置完了之后,终于开始调用build()
方法了
public Retrofit build() {
//老规矩啊,先对baseUrl进行非空判断
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//如果callFactory为空,则创建一个默认的
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
- 第一行,又是老规矩,对baseUrl进行非空判断。。。
- 拿到自己的
callFactory
对象,如果callFactory
为空,则创建一个默认的OkHttpClient()
对象,里面设置了默认的读写时间等等 - 拿到
callbackExecutor
对象,如果为空,则创建一个默认的platform.defaultCallbackExecutor()
对象
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
}
又new
了一个MainThreadExecutor
对象
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
可以看到,里面其实就是创建一个Handler
对象,并且传入了Looper.getMainLooper()
。所以下面的execute()
方法是执行在主线程。
- 剩下的基本就是创建集合,然后往里面添加数据,最后调用
Retrofit
带参数的构造方法,里面主要就是给变量赋值,看看就好!
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
那么到此为止,我们的retrofit
对象算是成功创建出来了,虽然我们调用起来只写了短短几行代码,但是Retrofit
内部却做了一大堆操作,这里其实就用到了好几种设计模式,比如Builder模式,外观模式,Factory模式。
create(Api.class) —— 重头戏来了
通过上面的一系列设置,最终我们得到了retrofit对象,按照官方文档的步骤,我们接下来要调用create()
方法,这个create()
方法到底做了什么,为什么我们传进去的接口类会返回给我们一个接口的实体类?这些问题我们一步一步揭晓!
public <T> T create(final Class<T> 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();
private final Object[] emptyArgs = new Object[0];
@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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
首先映入我们眼帘的,就是一个Retrofit
的常规操作,检查。。。没错,Utils.validateServiceInterface(service)
这个方法就是为了检查我们传进来的类是否为接口
,如果不是,则抛异常!
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
可能有小伙伴就会问,为什么必须传接口?传一个其他的类不行吗?对于这个问题,就要涉及到Java的动态代理模式了,因为Java的动态代理模式,只允许传入接口,不允许传入别的类,感兴趣的小伙伴可以自行研究。
动态代理模式
接下来,因为我们的validateEagerly
默认是false
,所以eagerlyValidateMethods(service)
没有被调用,我们直接来看Proxy.newProxyInstance
动态代理。
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
}
}
为了简洁,我把catch的代码直接删了,主要是看newProxyInstance
的操作,首先我们要知道的是Proxy
这个类并不是Retrofit
里面的,而是我们java.lang.reflect
下面的类,正是因为有Proxy
,我们才得以使用接口的对象调用我们接口里面的方法。
- 首先调用了非空判断,检查我们传入的
InvocationHandler
对象是否为空。 - 把我们传进来的接口数组
clone
一份(数组里面其实就只有我们传进来的一个接口类)。 - 通过
getProxyClass0
方法拿到Class的对象cl
。 - 通过
cl
拿到构造方法,并且重新创建了一个类,参数是一个Object[]
,里面放有我们传进来的InvocationHandler
对象。
看到了这里,我们肯定很好奇,由Proxy创建的类到底长什么样子?既然如此,我们不妨打印出来看看,这个类到底是何方神圣!
首先我们创建一个普通的接口类
interface ApiService {
void dosomething();
}
然后经过Proxy
一系列操作之后我们打印出来看看
public final class ApiService extends Proxy implements com.example.demo.ApiService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public ApiService(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void dosomething() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.demo.ApiService").getMethod("dosomething");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
你没有看错,直接生成了一个类,而且还自动extends Proxy
并实现了你的接口,所以这就是为什么动态代理模式只能传入接口。在生成的这个类里面,我们可以清楚地看到里面有dosomething
这个方法(所以说,我们拿到的接口对象其实就是这个类的对象)
到此为止,我们最重要的一个环节,根据我们传的接口类,创建了一个新的类,并且把这个类的对象返回给我们。
调用请求的方法
完成了一系列的配置之后,终于开始了我们的网络请求,Retrofit到底是如何帮我们实现网络请求的呢?我们继续往下看。
public interface ApiService {
@GET("url")
Call<String> dosomething();
}
api.dosomething();
我们先定义一下正常的get请求并发送该请求,通过断点,我们可以看到,发送请求时,直接进入了我们的Proxy
里面的InvocationHandler
里面(想想也正常,毕竟创建新类的时候,传入了InvocationHandler
的对象)
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
}
这里我就只截图一部分了,其实这个对象就是我们调用create
时传进去的,只不过里面的invoke
方法是在用户发送请求的时候才会被调用,原因就不用我讲了吧,直接看动态代理生成的类就明白了。
- 首先通过
method.getDeclaringClass()
检查了一下,是否为Object
的方法,显然这里不是,往下走 - 通过
platform.isDefaultMethod(method)
判断是否为平台的默认方法,显然也不是 - 最终调用
loadServiceMethod(method).invoke(args != null ? args : emptyArgs)
我们先来看loadServiceMethod(method)
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
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;
}
}
- 首先使用
serviceMethodCache.get
去取,得到一个ServiceMethod
对象result
,如果不为空,直接把result
返回 - 如果
result
为空,就调用ServiceMethod.parseAnnotations(this, method)
方法
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
}
第一行就调用了RequestFactory.parseAnnotations(retrofit, method)
,好吧,点进去看看
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
}
又调用new Builder(retrofit, method)
,继续
final class RequestFactory {
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
}
做了一堆赋值,拿到retrofit对象,方法上的注解之类的。。。没啥好说的,继续看build()
方法
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(method,
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError(method, "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++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}
if (relativeUrl == null && !gotUrl) {
throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(method, "Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError(method, "Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError(method, "Multipart method must contain at least one @Part.");
}
return new RequestFactory(this);
}
build()方法
1. 首先对methodAnnotations
这个注解数组进行了遍历,并且调用parseMethodAnnotation
方法对每一个annotation
进行解析
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
}
...
}
这里我删除了部分代码,因为里面都是if else判断,主要就是看你的注解是属于那一个,小伙伴们可以自行打开源码对比就好,以GET
为例,如果是GET
,这里直接调用parseHttpMethodAndPath("GET", ((GET) annotation).value(), false)
方法。
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.
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()) {
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);
}
- 非空判断,然后就是把我们传进来的参数给
httpMethod,hasBody
赋值 - 判断我们传进来的参数是否包含"?",如果包含,Retrofit就会帮你做一些拼接处理
- 然后给
relativeUrl
赋值 - 给
relativeUrlParamNames
赋值
到这里我们的parseMethodAnnotation
方法调用完成,注解解析完毕'
2. 对httpMethod
,是否含有body,是否为表单数据等进行一系列判断
3.返回了一个RequestFactory
对象
RequestFactory(Builder builder) {
method = builder.method;
baseUrl = builder.retrofit.baseUrl;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
headers = builder.headers;
contentType = builder.contentType;
hasBody = builder.hasBody;
isFormEncoded = builder.isFormEncoded;
isMultipart = builder.isMultipart;
parameterHandlers = builder.parameterHandlers;
}
又是一系列赋值操作,直接跳过。到此为止我们的RequestFactory
对象创建完毕。
回过头来我们再来看ServiceMethod这个类里面parseAnnotations
下面的操作,通过
method.getGenericReturnType()
拿到我们的返回值,然后调用了HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
方法。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
这里首先通过createCallAdapter()
方法,拿到了我们的callAdapter
对象,然后通过callAdapter.responseType()
拿到了返回值类型,经过一系列判断之后,调用createResponseConverter(retrofit, method, responseType)
方法,得到了一个返回值的转换器,然后使用new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter)
得到我们的HttpServiceMethod
对象并返回回去,也就是给我们上面的result
赋值。并且把该方法,放入到serviceMethodCache
缓存中。
invoke方法
通过上面的步骤,我们终于拿到了ServiceMethod
对象,并且开始真正调用方法
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
这里使用的是callAdapter.adapt
方法,因为CallAdapter
是接口,所以自然会有实现类,又因为我们使用的是系统默认提供的的,所以这里会调用DefaultCallAdapterFactory的adapt
方法
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
通过adapt方法,最终拿到了我们定义的Call对象!然后就是通过call调用enqueue或者execute完成同步或者异步的网络请求了!
尾声
第一次写这种源码解析的文章,着实感觉写出来要比自己懂难得太多了。。。不管怎么样,文章算是写出来了,希望本篇文章能对大家有所帮助吧!今后也会慢慢去写其他优秀框架的源码解读,学习学习大神们都是如何写代码的~
如果觉得文章不错,可以赞赏关注收藏哦~~~
网友评论