简介
Retrofit turns your HTTP API into a Java interface.
官网简介,言简意赅。它可以将你的HTTP API简化成一种Java接口的方式书写。
1、地址
retrofit github地址:https://github.com/square/retrofit
retrofit官网:https://square.github.io/retrofit/
gradle依赖:
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
2、简单使用
STEP 1:定义接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
STEP 2:创建Retrofit实体类,并发起请求
// 1、创建Retrofit实体类
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
// 2、创建接口实现类
GitHubService service = retrofit.create(GitHubService.class);
// 3、通过实现类得到Call实例
// https://api.github.com/users/octocat/repos
Call<List<Repo>> repos = service.listRepos("octocat");
// 4、Call发起同步/异步请求
/*同步请求
try {
Response<List<Repo>> execute = repos.execute();
} catch (IOException e) {
e.printStackTrace();
}
*/
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
原理
1、动态代理
retrofit的基础就是动态代理,通过retrofit.create()方法点进去,可以看到,create方法实际就是使用动态代理生成了GitHubService接口的实现类:
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.
// 判断方法是否是Object的,如果是则不处理。
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
// 加载方法,此处为了效率,添加了缓存serviceMethodCache
: loadServiceMethod(method).invoke(args);
}
});
}
简化一下就是这样的API,
/**
* @param loader classLoader
* @param interfaces 被代理的class,数组
* @param h 被代理类的方法会被InvocationHandler中的invoke(Object proxy, Method method, Object[] args)接收
* @return 生成的代理类
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
2、反射
由上面的代码可以知道,通过使用动态代理,我们可以通过InvocationHandler拿到接口定义的方法。那我们怎么拿到我们定义的API呢?又如何拿到定义的参数呢?答案就是反射。
通过调用Retrofit.create()->loadServiceMethod()->ServiceMethod.parseAnnotations()->HttpServiceMethod.parseAnnotations()来对method的注解进行解析。
// 此处为了效率,添加了缓存
ServiceMethod<?> loadServiceMethod(Method method) {
......
result = serviceMethodCache.get(method);
......
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
......
}
// 此处有部分检查返回值类型代码
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
......
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);
}
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
......
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;
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
HttpServiceMethod.parseAnnotations()会返回CallAdapted对象,通过调用invoke()方法,生成OkHttpCall对象,即我们通过接口定义的返回值。
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
当通过OkHttpCall发起请求时,会调用OkHttpCall.createRawCall()方法,通过反射获取到的参数就是在这里被拼接成Okhttp.Request的,生成Okhttp.Call对象,便可以通过Okhttp发起请求。
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;
}
调用图解
1、retrofit.create()流程
2、call.enqueue()流程
其他
用到的部分反射方法
// 获取方法的特定注解
MyGet myGet = method.getAnnotation(MyGet.class);
// 获取参数的注解
Annotation[][] paramsAnnotations = method.getParameterAnnotations();
// 获取返回方法返回值类型(包含泛型)
Type returnType = method.getGenericReturnType();
// 获取泛型的类型
Type[] types = ((ParameterizedType) returnType).getActualTypeArguments();
// 获取返回方法返回值类型(不包含泛型)
Class returnClass = method.getReturnType();