本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢!
在前两节《Android小知识-剖析Retrofit中静态内部类Builder的三个方法》和《Android小知识-剖析Retrofit中的网络请求流程以及相关参数
》中介绍了一些成员变量的初始化工作,那么本节就来介绍剖析Retrofit中的网络请求接口。
public interface NetworkInterface {
@GET("news/newsDetail")
Call<MyResponse> getNewsDetails(@QueryMap Map<String,String> map);
}
进行网络请求前需要创建网络请求接口类,在上面定义为NetworkInterface接口,其中定义了一个接受网络请求数据的方法叫做getNewsDetail,返回类型是一个泛型Call,Call里面的类型是MyResponse,MyResponse就是我们请求网络返回的数据类型,在getNewsDetail方法上添加了注解GET,表示网络请求是用GET方式来请求的,在注解GET中定义相对url地址,在Retrofit中,网络请求的URL分为两部分,第一部分在创建Retrofit时通过baseUrl传入http请求的基地址,第二部分就是上面注解GET后面定义的http请求的相对地址,两者加起来就是完整的http请求地址。
private void initRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://icould.glh/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
NetworkInterface networkInterface = retrofit.create(NetworkInterface.class);
}
创建完网络请求接口后就可以通过Retrofit的create方法,把网络请求接口的Class对象传递进去,返回一个网络请求接口的代理类。
进入create方法:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
...
}
通过工具类Utils的validateServiceInterface方法对接口的字节码进行验证,下面判断validateEagerly标志位,在《Android小知识-剖析Retrofit中的网络请求流程以及相关参数》介绍过这个标志位,表示是否提前解析网络请求接口中的方法,如果validateEagerly为true,就会执行eagerlyValidateMethods方法。
进入eagerlyValidateMethods方法:
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
在该方法先是获取具体的平台Platform,往下看是一个for循环,通过反射获取网络请求接口中的方法并遍历,在遍历时判断isDefaultMethod方法。
boolean isDefaultMethod(Method method) {
return false;
}
发现isDefaultMethod方法固定返回false,那么上面的if判断语句中就会执行loadServiceMethod方法。
进入loadServiceMethod方法:
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
...
}
loadServiceMethod方法返回一个ServiceMethod对象,在Retrofit中通过动态代理的方式将网络请求接口中的方法转换成一个个http请求,这个ServiceMethod对象就是对应接口中的一个方法,对接口中的方法进行封装。
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
...
}
在loadServiceMethod方法中一开始从serviceMethodCache集合获取请求方法对应的ServiceMethod对象,serviceMethodCache是ConcurrentHashMap集合类型,是线程安全的Map集合,如果serviceMethodCache当中存在对应请求方法的ServiceMethod对象,就直接返回该对象。
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
...
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
如果serviceMethodCache这个缓存集合中没有对应方法的ServiceMethod对象,那么就会利用Builder模式重新创建ServiceMethod对象,并将这个ServiceMethod对象保存在serviceMethodCache这个缓存集合中。
继续回到Retrofit的create方法中:
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();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
可以看到create方法返回的是网络请求接口的动态代理对象,通过Proxy的newProxyInstance方法创建动态代理对象,当我们调用代理类方法时,就会执行InvocationHandler的invoke方法。
整个Retrofit的核心就是InvocationHandler的invoke方法中的三行代码,后面一节会对这三个核心代码进行讲解。

搜索微信“顾林海”公众号,定期推送优质文章。
网友评论