在Android开发过程中,除了Android自带的一些像HttpUrlConnection这些网络请求框架之外呢,常常会会用到的一些开源框架像OkHttp、Retroift等,OkHttp是我们最常用到的一种,它支持同步和异步两种请求方式,内部封装线程池等等优点;本节介绍另一个网络请求框架Retrofit,在它内部还是实现了OkHttp,但是比OkHttp的性能更好,除了多平台的适配性,还通过注解来封装了请求接口url。
1.Retrofit的导入
com.squareup.retrofit2:retrofit:2.7.1
将这个Retrofit的依赖地址导入。
2.接口注解
在开篇我就提到了,Retrofit是通过注解来封装接口,通过注解封装的接口实例,在使用Retrofit的时候,通过建造者模式创建的Retrofit对象,调用它的create方法就可以得到一个接口的实例,在这个create方法内部,就是通过动态代理模式来完成的。
public <T> T create(final Class<T> service) {
validateServiceInterface(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 {
// 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的create方法的源码,这个方法最终return了一个动态代理对象,就是Proxy.newProxyInstance(...,...,...)
这个方法,其中传入的三个参数,分别是第一个参数是类加载器,在create方法中传入的是 Class<T> service
就是获取这个接口类的类加载器,第二个参数是一个class数组,类似于占位符,传入的就是在create方法中传入的service
,第三个参数是InvocationHandler()
,这是一个接口,会重写里面的invoke方法
public interface InvocationHandler {
Object invoke(Object var1, Method var2, Object[] var3) throws Throwable;
}
create方法真正执行的就是invoke方法中执行的代码;在invoke方法中,有一个 比较重要的代码就是return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
其中loadServiceMethod(method).invoke
就是真正发起网络请求的方法。
ServiceMethod<?> `loadServiceMethod`(Method method) {
//注意这里,当去解析注解的时候,首先会去缓存中查询
//是否解析过这个请求,如果解析过,那么就直接去缓存中取出解解析结果。
**//缓存都是保存在ConcurrentHashMap中**
ServiceMethod<?> result = serviceMethodCache.get(method);
//result不为空
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;
}
从代码中可以看出,loadServiceMethod
是ServiceMethod
的一个方法,这个方法中传入一个Method对象,返回了一个result对象(ServiceMethod.parseAnnotations(this, method);
),这个result对象其实就是ServiceMethod
解析接口中的注解。
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);
}
在ServiceMethod
的parseAnnotations
方法中,首先是创建了一个RequestFactory
对象,在这个对象也有一个parseAnnotations
方法,
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
在返回的build方法中,其实就是获取注解中的信息,调用parseMethodAnnotation
方法,获取注解中的GET信息,其实RequestFactory
就是将注解中的信息拼接成网络请求的url字符串。
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;
}
}
从代码中可以看出,在ServiceMethod.parseAnnotations(this, method);
中,真正是由HttpServiceMethod
(ServiceMethod
的子类)去执行invoke方法,发起网络请求。
从头开始我们先串一下:当我们创建一个Retrofit对象的时候,我们通过调用Retrofit对象的create方法,最终得到一个接口的实例;那么在create方法内部中,使用的是动态代理的设计模式,最终返回的是一个动态代理对象,当中核心方法就是InvocationHandler()
接口的invoke方法,在这个方法中,最重要的一个方法就是loadServiceMethod
,这个方法是ServiceMethod
类的方法,通过执行ServiceMethod
类的parseAnnotations
方法得到一个ServiceMethod
对象,其实真正执行parseAnnotations
方法的,是ServiceMethod
的一个子类HttpServiceMethod
执行的,也就是说loadServiceMethod
最终返回的是一个HttpServiceMethod
对象,然后执行了invoke方法,也就是HttpServiceMethod
的invoke方法。
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
上述代码是HttpServiceMethod
中的invoke
方法。
在invoke方法中,首先创建一个OkHttpCall对象,然后调用CallAdapter的adapt方法,返回一个适配接口类的Call对象。也就是说在创建成代理对象之后,通过调用其中的方法就返回了一个适配该接口类型的call对象。
@Override protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<Response<ResponseT>> continuation =
(Continuation<Response<ResponseT>>) args[args.length - 1];
// See SuspendForBody for explanation about this try/catch.
try {
return KotlinExtensions.awaitResponse(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
3.动态代理模式
在上一节提到了,Retrofit的create方法中使用到了动态代理模式,我们的网络请求是通过注解接口的方式实现的,而且对于动态代理模式来说,只支持接口的形式。