本文主要介绍Retrofit在android下的使用和对关键源码的解析。
使用方法
假设后端接口规定返回数据如下所示:
{
code: 200,
msg: "",
data: {} //data可以是任何数据,对象、数组、null都行
}
我们现在要通过userId查询用户信息,首先要定义模型User
data class BaseResponse<T>(val code: Int, val msg: String? = null, val data: T? = null)
data class User(val name: String, val age: Int)
然后要定义接口Service,假设我们现在有一个获取用户信息的接口,接口完整路径为http://www.jianan.com/user
,那么在Retrofit中http://www.jianan.com/
就是这个接口的baseUrl,user
就是接口的路径。
定义UserService如下:
interface UserService {
@GET("user")
suspend fun getUserInfo(@Query("userId") userId:String): Response<BaseResponse<User>>
}
接下来创建Retrofit对象,调用Service中的方法开始请求
fun getUserInfo(){
scope.launch {
val retrofit = Retrofit.Builder()
.baseUrl("http://www.jianan.com/")
.addConverterFactory()
.addCallAdapterFactory()
.build()
val resp = withContext(Dispatchers.IO){
retrofit.create(UserService::class.java)
.getUserInfo("123")
}
//这里已经拿到了resp,可以进行ui刷新了
}
}
上面是一个最简单的请求过程,没对异常什么的进行处理,通过代码可以看出Retrofit第一步通过Builder模式创建了Retrofit的对象,创建过程中哪些参数有什么意义呢?接下来调用create方法创建了Service的对象,我们知道UserService是一个接口,并没有实现类,Retrofit是如何创建Service的对象呢?带着这两个问题探寻一番Retrofit的源码。
Retrofit实例是如何创建的
Retrofit是如何创建Service对象的
先来看看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);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
这里使用了Java中的动态代理模式创建了UserService的对象,在Android中默认会调用到loadServiceMethod(method).invoke(args)这行,接下来看下loadServiceMethod做了啥,
/*
* 从缓存中拿方法,拿不到就通过静态方法parseAnnotations进行解析
*/
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;
}
ServiceMethod是对我们Service接口里定义的方法(例子中是getUser方法)的一个封装,parseAnnotations方法如下:
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//获取请求方法的返回类型,包含内部泛型,例子里这里就是Response<BaseResponse<User>>
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.");
}
//如果返回值合法就转化为HttpServiceMethod对象
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
RequestFactory用来对请求方法的参数、注解啥的进行一次封装,后续可以通过RequestFactory的实例拿到对应的数据,RequestFactory是HttpServiceMethod中的一个属性,接下来看看HttpServiceMethod是如何创建的?解答这个问题前要先理解一下kotlin中的suspend
关键字的原理。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;//是否是kotlin suspend函数
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();//拿到方法的所有注解
Type adapterType;
if (isKotlinSuspendFunction) {
//如果是suspend函数则需要特殊处理,因为suspend函数编译后会加上一个Continuaton参数,返回值会变为Any
Type[] parameterTypes = method.getGenericParameterTypes();
//在这个例子里responseType拿到的是Response<BaseResponse<User>>
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拿到的是BaseResponse<User>
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
// 包装为Call<BaseResponse<User>>的形式,之所以这么包装是因为Retrofit定义Service方法时必须使用Call类型作为返回值,如果不包装的话就要自己定义CallAdapter
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
// 从一开始创建Retrofit时注册的CallAdapter中取一个来处理这个请求
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
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);
}
}