Retrofit通过对okHttp进行再次封装,简化了网络实现。
1.代码使用
- 创建Retrofit对象
- 创建请求接口代理对象
- 反射生成okHttpCall对象
- 请求和解析ResponseBody返回
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl()
.addConverterFactory()
.build();
// create an instance of out github API interface.
GitHub github = retrofit.create(GitHub.class);
// create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
List<Contributor> contributors = call.execute().body();
2.创建Retrofit对象
建造者模式创建Retrofit对象
build,首先retrofit会新建一个call,其实质就是okHttp,作用就是网络请求器;
默认callAdapter是ExecutorCallAdapterFactory,其实质就是网络请求器call的适配器,而在Retrofit中call就是指okhttp,callAdapter就是用来将okhttp适配给不同的平台的;
Retrofit提供了四种callAdapter:ExecutorCallAdapterFactory,GuavaCallAdapterFactory,Java8CallAdapterFactory,RxJavaCallAdapterFactory;
提供适配器的目的是易于扩展,只需要添加即可使用,使用RxJava的适配器后,功能更加强大 Retrofit负责接收配置的功能然后进行对象的初始化,这个也就是Build模式屏蔽掉创建对象复杂过程的好处;
| function | description |
|---|---|
| client | 指定要创建的自定义okHttpClient |
| callFactory | 指定要创建的自定义调用工厂 |
| baseUrl | 配置服务器地址,指定要创建的基类url,一般包含协议部分、域名部分、端口部分 |
| addConverterFactory | 添加用于对象序列化和反序列化的转换器工厂,将http返回的数据解析成java对象,常见的有xml,gson等;GsonConverter就是将gson数据转换成我们的java对象,而不用重新去解析这些gson数据 |
| addCallAdapterFactory | 添加一个支持服务方法返回类型的调用适配器工厂,callAdapter同样被一个list维护,用户可以添加多个callAdapter |
| callbackExecutor | 添加call执行的线程池 |
| validateEagerly | 实例化接口对象完成立即验证提供的接口中所有方法的配置 |
3.创建请求接口代理对象
- validateServiceInterface检查接口类及其父类们是否为泛型类,如果是就抛异常;
- 下面就是retrofit核心技术点动态代理:利用 Proxy 请求接口类,创建 InvocationHandler 的实例对象,用来处理被代理类的所有请求方法调用;
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = atgs != null ? args : emptyArgs;
Platform platform = Platform.get();
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
平台是 android29 环境,所以 get 方法返回的实例是 Android24;
private static final class Android24 extends Platform {
static boolean isSupported() {
return Build.VERSION.SDK_INT >= 24;
}
private @Nullable Constructor<lookup> lookupConstructor;
@Override
Executor defaultCallbackExecutor() {
return MainThreadExecutor.INSTANCE;
}
@Override
List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories (@Nullable Executor callbackExecutor) {
return asList(
new CompletableFutureCallAdapterFactory(),
new DefaultCallAdapterFactory(callbackExecutor));
}
...
}
4.生成OkHttpCall对象
- 反射解析接口方法注解,参数注解生成CallAdapted;
- 调用invoke方法生成okHttpCall,该invoke方法中创建了一个okHttpCall对象,并调用了adapt(call, args) 方法;
- 创建代理类ExecutorCallbackCall代理okHttpCall;
4.1反射解析接口方法注解参数注解获得请求类型和urlpath等
需要得到如下信息供Retrofit使用获得方法注解数组methodAnnotations,参数类型数组parameterTypes,参数注解数组patameterAnnotationsArray
Build(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
解析方法注解获得请求类型httpMethod和url路径relativeUrl;
private void parseMethodAnnotation(Annotation annotation) {
...
else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
...
}
正则匹配url获得path字符串集合赋值给relativeUrlParamNames;
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
生成方法parameterHandler后面用来替换relativeUrl中的path;
RequestFactory build() {
...
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);
}
生成CallAdapter对象;
前文已经根据android29环境生成了Platform.Android24,再结合retrofit.build方法,根据请求接口类方法返回值是Call,创建defaultCallAdapterFactory.get()的callAdapter对象和GsonResponseBodyConverter.responseBodyConverter的GsonResponseBodyConverter对象;
callFactory是用的默认创建的okhttpClient
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
...
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
...
}
}
4.2调用invoke方法生成okHttpCall
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
...
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
}
4.3创建代理类ExecutorCallbackCall代理okHttpCall
Platform.Android24生成了一个MainThreadExecutor.INSTANCE,所以adapt会生成ExecutorCallbackCall对象;
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
...
@Override
public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceOf ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
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);
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? Call : new ExecutorCallbackCall<>(executor, call);
}
};
}
}
android中一般情况下都是在UI线程完成UI操作,但是okhttp没有这个能力,所以作者用静态代理模式,实现了enqueue回调从子线程切换到UI线程;
static final class ExecutorCallbackCall<T> implements Call<T> {
...
@Override
public void enqueue(final Callback<T> callback) {
objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallback.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));
}
});
}
...
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
...
}
目前除了生成ExecutorCallbackCall对象还在RequestFactory存储了如下值
| 参数名 | 来源途径 | 值 |
|---|---|---|
| httpMethod | 接口方法注解名 | GET |
| baseUrl | 自定义传入 | api.github.com/ |
| relativeUrl | 接口方法注解值 | /repos/{owner}/{repo}/contributors |
| ParameterHandler | RequestFactory方法 parseParameterAnnotation | 2个ParameterHandler$Path name参数一个是owner一个是repo |
5.请求和解析ResponseBody返回
- 生成okhttp3.Requset对象,调用okhttpClient请求
- 使用前面生成的responseConverter解析ResponseBody
5.1调用okhttpClient请求,调用okhttpClient请求
final class okHttpCall<T> implements Call<T> {
...
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = getRawCall();
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
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;
}
...
}
5.2Gson解析ResponseBody
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}