Retrofit通过对OkHttp的再次封装,简化了网络实现。
1. 代码使用(源码示例SimpleService)
工作流程很简单如下四步:
- 创建Retrofit对象
- 创建请求接口代理对象
- 反射生成OkhttpCall对象
- 请求和解析ResponseBody返回
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our 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对象
fucntion | description |
---|---|
client | 指定要创建的自定义OkHttpClient |
callFactory | 指定要创建的自定义调用工厂 |
baseUrl | 指定要创建的基类url 一般包含协议部分、域名部分、端口部分 |
addConverterFactory | 添加用于对象序列化和反序列化的转换器工厂 |
addCallAdapterFactory | 添加一个支持服务方法返回类型的调用适配器工厂 |
callbackExecutor | 添加call执行的线程池 |
validateEagerly | 实例化接口对象完成立即验证提供的接口中所有方法的配置 |
3.创建请求接口代理对象
(1)validateServiceInterface检查接口类及其父类们是否为泛型类,如果是就抛异常
(2)下面就是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 the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != 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
- 创建代理类ExecutorCallbackCall代理OkHttpCall
4.1反射解析接口方法注解参数注解获得请求类型和urlpath等
需要得到如下信息供Retrofit使用
[7]获得方法注解数组methodAnnotations,参数类型数组parameterTypes,参数注解数组parameterAnnotationsArray
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
[9-10]解析方法注解获得请求类型httpMethod和url路径relativeUrl
private void parseMethodAnnotation(Annotation annotation) {
...
else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
...
}
[11]正则匹配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;
}
[8]生成方法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);
}
[12-22]生成CallAdapted对象
前文已经根据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.3调用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);
}
};
}
}
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(ExecutorCallbackCall.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.Request对象,调用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();
}
}
}