文章目录
Retrofit 结合OkHttp构成了当前非常流行的Android的网络框架。而Retrofit对OKHttp进行了一层封装,可能入手的门槛高一点,但是使用习惯以后可以说是非常的简洁和高效。
Retrofit 还可以跟 Rxjava 转化成Obserable,形成了链式编程风格,深得我心。
Retrofit的基本源码流程:
- 动态代理获取Method
- Method从提取出注解参数
- 执行网络操作
- 转换成对应结果
本文不会直接跟着代码走完所有流程,只拿出重要的几点分析。
在开始分析之前,先写个简单的例子,我们申明一个接口 getServiceName
public interface ServiceApi {
@GET
Call<String> getServiceName();
}
下面来看,Retrofit 如何解析ServiceApi并进行网络操作。
Retrofit类定义了几个重要的变量:
// Retrofit
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
Retrofit的第一步就是获取
-
ServiceMethod对应着根据Method解析出的注解、返回的结果类型等,并缓存到了serviceMethodCache,避免每次都需要重新解析
-
callFactory 是okhttp创建call的类
-
baseUrl
-
converterFactories 是一个集合,负责对网络请求的RequestBody 和网络请求结果 ResponseBody的转换,例如我们经常使用的GsonConverterFactory
-
callAdapterFactories 也是一个集合,负责对最后的返回结果的封装或转换,例如我们经常使用的RxJava2CallAdapterFactory
-
callbackExecutor 是负责执行,Android默认执行器是利用handler抛到主线程执行回调结果。所以我们会看到retrofit的结果都在主线程中。
1. 动态代理获取Method
retrofit之所以利用动态代理,有两个目的:
- 可以实例化上面ServiceApi这个接口,直接调用getServiceName进行网络请求;
- 可以通过动态代理拿到对应的Method,也就可以拿到Method上的注解,进行参数解析;
除了这种动态代理的实现方式以外,要想达到一样的效果的就是类似ButterKnife注入框架,在编译时候利用AnnotionProcessor生成ServiceApi实现类。因为是编译期生成,所以不会影响运行效率,但是也会存在其他问题。
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];
public Object invoke(Object proxy, Method method,
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);
}
});
}
这里直接看最后的一句:
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
2. Method从提取出注解参数
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;
}
parseAnnotations()的作用:
- 解析注解转换成各种http参数
- 解析出返回类型Type
- 找出对应的CallApater
- 找出对应的Converter
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) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
...
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be 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);
}
}
3. 执行网络操作
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
ServiceMethod.invoke()进行了网络操作和转换操作,不过他是个抽象方法,直接看他的子类HttpServiceMethod
// HttpServiceMethod
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
具体看CallAdapted实现类,他就是一个封装类,封装了CallAdapter。
转发调用了CallAdapter的adapt,这里的CallAdapter是由上面parseAnnotations()中找出对应的CallAdapter。
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
callAdapter.adapt()根据不同的具体callAdapter执行不同的操作。
其中默认的实现也只是执行了Okhttp的Call.enque()流程。
再回来看HttpServiceMethod 的invoke()方法,内部主要是构造了一个retrofit2.OkHttpCall对象,里面封装了OkHttp 的Call对象、Converter,其实就是封装了整个Okhttp的请求流程,最后对Converter结果转换。
这里不贴代码了。
实现一个简单的Retrofit框架
自定义Retrofit 需要做到:
- 动态代理
- 解析参数
- 执行操作和转换结果,返回对应类型的结果
定义一个参数注解
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD})
public @interface CustomParam {
int value();
}
CustomParam就是最简单的一个注解参数,value是一个整数,对应着是Retrofit各种复杂网络参数配置。
定义一个执行者CallAdapter接口
public abstract class CustomCallAdapter<P, R> {
public abstract R adapt(P params);
public abstract Type getResponseType();
}
CustomCallAdapter是一个CallAdapter的简化版本,内部负责调用和返回结果类型。用户可以自定义实现CallAdapter
定义一个CustomRetrofit
public class CustomRetrofit {
// 存储各种自定义的CallAdapter
private List<CustomCallAdapter> mCallAdaters;
private CustomRetrofit() {
mCallAdaters = new ArrayList<>();
}
private <T, R> void addCalladapter(CustomCallAdapter<T, R> callAdapter) {
mCallAdaters.add(callAdapter);
}
public <T> T create(Class<T> cls) {
return (T) Proxy.newProxyInstance(cls.getClassLoader(), new Class[]{
cls},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return convert(method);
}
});
}
// 真正的执行
private Object convert(Method method) {
Type type = method.getReturnType();
// 根据需要的返回类型找出CallAdapter
CustomCallAdapter callAdapter = getCallAdapter(type);
if (callAdapter == null) {
throw new RuntimeException("no callAdapter");
}
// 解析参数
CustomParam param = method.getAnnotation(CustomParam.class);
int value = param == null ? 0 : param.value();
// callAdatper执行(忽略了最后结果转换这一步)
return callAdapter.adapt(value);
}
private CustomCallAdapter getCallAdapter(Type type) {
for (CustomCallAdapter item : mCallAdaters) {
if (type == item.getResponseType()) {
return item;
}
}
return null;
}
// 简单的builder模式
public static class Builder {
private CustomRetrofit instance = null;
public Builder() {
instance = new CustomRetrofit();
}
public Builder addCallAdapter(CustomCallAdapter callAdapter) {
instance.addCalladapter(callAdapter);
return this;
}
CustomRetrofit build() {
return instance;
}
}
}
上面的注解很简单和清晰了,不做过多解释。
使用
public interface SimpleApi {
@CustomParam(2)
Integer test();
}
public class SimpleCallAdapter extends CustomCallAdapter<Integer, Integer> {
@Override
public Integer adapt(Integer param) {
return param;
}
@Override
public Type getResponseType() {
return Integer.class;
}
}
测试一下
@Test
public void testRetrofit() {
CustomRetrofit retrofit = new CustomRetrofit.Builder()
.addCallAdapter(new SimpleCallAdapter())
.build();
int result = retrofit.create(SimpleApi.class).test();
System.out.println(result);
}
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/app/6261.html