本文主要通过Retrofit的简单使用,来分析使用Retrofit的大致过程,通过分析分析源码来了解一下它的秘密。
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
下面分析的Retrofit版本也是2.8.1
interface ApiService {
//普通版
@GET("article/list/{page}/json")
fun getArticleList(@Path("page") page: Int): Call<Result<PageEntity<Article>>>
//java 8支持
@GET("article/list/{page}/json")
fun getArticleList1(@Path("page") page: Int): CompletableFuture<Result<PageEntity<Article>>>
//使用kotlin协程
@GET("article/list/{page}/json")
suspend fun getArticleList2(@Path("page") page: Int): Result<PageEntity<Article>>
}
下面分析主要以普通版为主,其他类似,关于kotlin协程的支持可以看看我之前写的另一篇文章kotlin 协程在 Android 中的使用——Jetpack 中的协程、Retofit中使用协程及源码分析 文中有相关代码分析
val retrofit= Retrofit.Builder()
.baseUrl("https://www.wanandroid.com")
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().enableComplexMapKeySerialization().create()))
.build()
val api = retrofit.create(ApiService::class.java)
api.getArticleList(1).enqueue(object :Callback<Result<PageEntity<Article>>>{
override fun onFailure(call: Call<Result<PageEntity<Article>>>, t: Throwable) {
Log.i("main","failure")
}
override fun onResponse(
call: Call<Result<PageEntity<Article>>>,
response: Response<Result<PageEntity<Article>>>
) {
Log.i("main","onResponse")
}
})
以下分析以getArticleList()方法为主
下面就沿着getArticleList
方法看一下Retrofit如何执行的,当我们调用enqueue
方法时发起异步请求,点击enqueue
方法发现是一个 接口方法,getArticleList
是我们定义的接口方法也没有具体实现,那我看个鬼代码呀,洗洗睡了 return。
哈哈,睡不着还是看看代码吧,我们在分析分析,我们定义的接口实例对象是通过retrofit.create(ApiService::class.java)
创建的,那就看看这个create方法吧,点击查看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.
//如何这个方法是父类(Object)的方法,那就直接执行,eg. toString()
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//java 8 接口也可以有默认实现,如何有默认实现,就直接执行默认实现
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
这个方法主要时利用动态代理 Proxy.newProxyInstance
/**
* @params loader 类加载器
* @params interfaces 需要代理的接口数组
* @params h InvocationHandler 是一个回调接口,有个invoke方法,每当调用代理接口的方法时,
* invoke都会被调用
**/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
当我们调用接口方法是时候,invoke 就会被调用,该方法最后一行调用的loadServiceMethod 然后在调用它的invoke方法并将返回值return,点击进入它的invoke方法,发现是个抽象方法,那就先放着吧,先看loadServiceMethod方法干了啥
ServiceMethod<?> loadServiceMethod(Method method) {
//serviceMethodCache是ConcurrentHashMap<>() 用来缓存解析后的方法相关值
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;
}
上面loadServiceMethod 返回的是一个ServiceMethod>
对象,这个有什么用, 我们在看看ServiceMethod.parseAnnotations
方法吧
ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析注解<1>
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
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.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
RequestFactory 通过 parseAnnotations 通过建造者模式,从 retrofit 和method对象中解析中一些值保存到RequestFactory 对象中,我们定义的注解就是在这解析处理的
private final Method method;
private final HttpUrl baseUrl;
final String httpMethod; //通过解析注解获取 eg. GET 、POST
private final @Nullable String relativeUrl;//相对地址 @GET("list")
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
final boolean isKotlinSuspendFunction;//是否是kotlin suspend函数
parseAnnotations 方法的最后调用了,HttpServiceMethod.parseAnnotations,我们在去看看这个方法干了啥
妈呀这个方法好多行@_@。让我先看看
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//是否是kotlin suspend 函数
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
// -------------start 获取adapterType-------------------------
//是kotlin suspend 函数,可以略过这个细节,先看最普通情况流程怎么走
if (isKotlinSuspendFunction) {
//获取参数类型,包括泛型的参数
Type[] parameterTypes = method.getGenericParameterTypes();
//获取suspend 最后一个参数,suspend函数编译后,会在原来的参数后面多一个参数
//这个参数是kotlin.coroutines.Continuation<函数返回值类型>
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
//判断函数返回值是否是Response
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response.
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 eg. Call<函数返回值类型>
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
// ---------------end -----------------------
//根据adapterType创建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)" );
}
// 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.");
}
//创建responseConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {//不是suspend 返回一个CallAdapted对象
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);
}
}
代码有点多,因为2.6.0版本加入了对kotlin协程的支持,多了一些分支判断,我们按照getArticleList
方法调用走的流程,来简化一下上面的方法如下
HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//kotlin suspend 方式代码省略
Type adapterType;
adapterType = method.getGenericReturnType();
//1. 根据adapterType创建CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
// 省略responseType合法性判断
//2. 创建responseConverter,
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//3. 返回 CallAdapted(HttpServiceMethod)//kotlin suspend 省略
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
到此为止,通过loadServiceMethod(Method method)
方法得到的对象是类型是CallAdapted
在上面InvocationHandler
的invoke
的方法最后一句执行的是
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
现在我们知道了,在上述情况分析下 loadServiceMethod(method)
得到的是CallAdapted的对象,那么我们就去CallAdapted 类中看看invoke 方法吧,但是发现并没有此方法。CallAdapted 继承自HttpServiceMethod 我们在这个类中找到了invoke方法
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
该方法最后调用了adapt 方法,它是抽象方法,由它的子类CallAdapted 实现
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
那这个callAdapter是什么??它是通过CallAdapted构造方法参数传入来的。那我们就要回到CallAdapted 创建对象的时候,看看传入的callAdapter是什么,那就要回到HttpServiceMethod.java 的parseAnnotations方法再看一看,发现callAdapter 是通过下面这行代码等到的
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
这个方法追踪下去会看到这个方法
Retrofit.java
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//代码省略
}
会发现有一个callAdapterFactories集合,这个集合是Retrofit通过build创建对象时就准备好的,然后根据returnType, annotations来找到合适的adapter。下面是Retrofit 的build方法中关于callAdapterFactories的部分代码
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
从上面我们可以知道,在Retrofit 通过build()构建对象时,如果是java8 那么callAdapterFactories集合中的元素有CompletableFutureCallAdapterFactory 和DefaultCallAdapterFactory 两个类的对象。如何不是java8 那就只有DefaultCallAdapterFactory 这一个元素。
那现在再回到nextCallAdapter的方法,看看最终返回的的是那个adapter。CompletableFutureCallAdapterFactory 的get方式是这样的
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != CompletableFuture.class) {
return null;
}
//省略代码
}
如果返回值不是CompletableFuture.class
就返回null,我们上面getArticleList的返回值是Call 显示不是这个
那在看看DefaultCallAdapterFactory 的get方法
@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 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);
}
};
}
我们写的方法符合这个,所以我们callAdapter 对象是通过DefaultCallAdapterFactory 的get方法得到的,他的adapt方法返回值是new ExecutorCallbackCall<>(executor, call)
到此为止我们知道了当我们调用getArticleList方法会经过上面一系列的过程,最终返回ExecutorCallbackCall
对象。
上面我们getArticleList的方法的返回值调用enqueue
方法发起了异步回调。那么ExecutorCallbackCall这个类中应该有我们想看到的enqueue
方法实现,下面就是它的代码
@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()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
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));
}
});
}
上面delegate是什么鬼,它是 retrofit2.Call
类型的它是ExecutorCallbackCall<>(executor, call)
创建对象通过构造方法传入过来的。那这个call对象是从那么传入来的呢。我们验证它的传入往上找一找,发现是在HttpServiceMethod.java 的invoke方法中创建的
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
所以上面delegate就是这个OkHttpCall,在它的enqueue里面,会创建一个Okhttp的Call对象,利用OkHttp发起网络请求,Retrofit把网络数据转换成相应的对象就是在这里操作的。
再点击OkHttpCall类中查看它的enqueue方法如下
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
因为Retrofit是对OKHttp 的封装,所以这个方法里面可以看到它创建了一个okhttp的Call 然后调用他来实现的异步网络请求,到此一个完整的网络请求流程就走完了。
1.Retrofit通过Build 模式创建对象,Retrofit相当于一个配置管理,里面有要请求的baseUrl、用于发起网络请求的CallAdapter的工厂集合([DefaultCallAdapterFactory])、还有用于转换网络数据格式的Converter.Factory集合,例如上面实例代码利用Gson转换工厂。
2.定义Retrofit网络请求方法,只需要定义接口,使用相关注解。通过create()方法创建接口实例,当我们调用方法时,会进行注解解析等工作,这个比较耗时,所以他有缓存机制,就像上图灰色区域。
3 通过ServiceMethod对象调用invoke方法得到Call对象,是通过Retrofit对象中的合适的CallAdapter的工厂创建的,当调用Call对象的enqueue时,是通过Okhttp发起请求,当请求成功后通过数据转换工厂Converter.Factory转换为相应的数据,然后调用retrofit2.Callback回调。
好了我对Retrtofit的源码分析就到此结束 ,睡觉。