retrofit是目前Android移动端领域最火的框架,相比我们之前使用的HttpClient 、XUtils、Volley等拥有非常方便的API、丰富的注解,帮助开发者轻松实现网络请求,并且遵从RESTFUL接口的场景。
众所周知这个框架是对OKhttp的封装,意思就是说它本身不具备网络请求的功能,它只是把我们需要请求的URL、参数以及请求类型封装起来,然后告诉底层的OkHttp发送请求,并把请求结果返回回来。
使用发送一个HTTP请求只需要三步:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://api.github.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
上面就是我们基础的发送一个网络请求需要的步骤,定义一个接口里面定义我们需要发送的网络请求url 以及参数和请求方式。 其次就是 new Retrofit.Builder().build()
使用建造者模式创建一个Retrofit
实例,调用retrofit.create(GitHubService.class)
得到一个接口实例,到此我们可以调用我们在接口定义的每个服务接口。到这里我们是不是感觉很神奇。接口上定义的@GET("users/{user}/repos")
、 @Path("user") String user
、 Call
这些东西是怎么加入到一个网络请求的呢? 待着这些疑问我们看看 >
retrofit.create
方法。在这之前我们先看看Retrofit.Builder().build
。
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//this.callFactory 其实就是一个OkHttpClient 如果我们不需要给OkHttpClient 自定义一些超时时间 和 拦截器我们不需要创建他可以自己创建
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 注释1
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// RxJava2CallAdapterFactory.create() 创建的东西最后放在callAdapterFactories
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// GsonConverterFactory.create() 创建的东西最后添加在converterFactories
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
到这里我们知道Retrofit 创建的一些核心属性,callFactory, baseUrl
不必说 主要是converterFactories
、 callAdapterFactories
、 callbackExecutor
这三个参数。
我们先复习一下动态代理。
public interface IVehical {
void run();
}
public class Car implements IVehical{
@Override
public void run() {
System.out.println("Car run ...");
}
}
@Test
public void testProxy(){
IVehical iVehical = new Car();
IVehical vehicalProxy = (IVehical) Proxy.newProxyInstance(iVehical.getClass().getClassLoader(), new Class[]{IVehical.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println("method name "+name);
Object invoke = method.invoke(iVehical, args);
return invoke;
}
});
vehicalProxy.run();
}
最后我们打印结果是
I/System.out: method name run
Car run …
iVehical com.haocang.commonui.Car@78e78e6
vehicalProxy com.haocang.commonui.Car@78e78e6
根据我们打印结果我们可以发现 IVehical vehicalProxy
这实例最后执行了IVehical iVehical
实例的run
方法。 可以理解为Proxy.newProxyInstance
创建的对象其实就是IVehical iVehical
。事实也正的是如此,两者的地址是指向的同一个地址。
动态代理 需要三个参数
classLoader
、接口类集合(传入的接口最终会被实现)、InvocationHandler
回调,然后会返回一个接口的实例对象,当这个实例对象在调用接口定义的方法的时,会执行InvocationHandler
回调的invoke
方法,并且把调用的方法信息传给invoke
作为参数。
接下来分析 retrofit.create
方法,他的返回值是GitHubService service
实例
public <T> T create(final Class<T> service) {
//验证service是一个接口,并且接口不能继承其他的接口
Utils.validateServiceInterface(service);
// validateEagerly 如果设置这个,会对GitHubService 里面编写的方法的合法性进行验证,通常为false
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//注释1
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果method 不是listRepos 而是 Object里面的方法,比如 toString
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 如果是一个接口的实现的方法 如GitHubService里面已经实现的方法。
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 注释2 核心
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
// 注释3 核心
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 注释 4 核心
return serviceMethod.adapt(okHttpCall);
}
});
}
从动态代理的讲解,我们可以得出Proxy.newProxyInstance
会创建一个GitHubService
的实例,当这个实例调用它的方法的时,InvocationHandler
的invoke
就会被调用。
所以我们在执行Call
执行的时候,> repos = service.listRepos("octocat");
invoke
的 Method method
指的是listRepos
, Object[] args
就是"octocat"
。接下来我们看invoke
方法的实现,首先他会判断GitHubService
的实例 调用的是不是Object的方法,比如toString 。接下来判断platform.isDefaultMethod(method)
是否是已经实现的方法。 接下来就是通过invoke
methd
参数得到一个ServiceMethod
实例。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
这里主要就是创建ServiceMethod 然后缓存起来。核心在ServiceMethod.Builder<>(this, method).build()
我们传入了Retrofit实例和method。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 方法的注解 @GET("users/{user}/repos")
this.methodAnnotations = method.getAnnotations();
// 获取方法的参数类型 String user
this.parameterTypes = method.getGenericParameterTypes();
// 获取方法的每个参数上的注解 @Path("user")
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
ServiceMethod.Builder
主要获取关于method一些信息,注解、 参数类型、 参数的注解。接下来看build方法
public ServiceMethod build() {
// 根据method的返回类型 决定用什么转换器,比如 默认的Call 或者 RxJava2CallAdapter的Flowable
callAdapter = createCallAdapter();
// 以RxJava2CallAdapter为例获取到responseType
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
// 通过 method 身上的信息 和 responseType 最终获取Response的Converter
responseConverter = createResponseConverter();
// 解析method身上的注解信息,比如是GET请求还是POST请求
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {}//throw methodError("Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
if (isFormEncoded) {}//throw methodError("FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST).");
}
// 获取到method身上的参数信息,最后封装到ParameterHandler身上
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {} //抛异常
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {}//抛异常
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {}//抛异常
if (isFormEncoded && !gotField) {}//抛异常
if (isMultipart && !gotPart) {}//抛异常
return new ServiceMethod<>(this);
}
这方法可以理解成解析method的信息,因为我们在method中注解了很多信息,如 请求方式、请求url、请求参数。最后封装到ServiceMethod里面。
接下来是 new OkHttpCall<>(serviceMethod, args)
这是Retrofit封装的一个Call对象,最终会创建成OkHttp的call。
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
从这里我们可以看到把我们传的args
与 parameterHandlers
一起,最后被封装到OKHttp
的requestBuilder
身上最后被callFactory.newCall
调用了转换成了RealCall.newRealCall
。
综上我们我们可以理解成把注解上的信息以及我们传递的参数,封装到一个okhttp的request上,最后newCall。其实就是在构建一个 okhttp请求。
接下来注释 3 serviceMethod.adapt(okHttpCall)
这个方法其实就是执行 方法。 执行我们调用的service.listRepos("octocat");
从前一步我们封装了一个RealCall 对象,然后传递给serviceMethod.adapt()
这个是不是就是 在执行呢?
okhttpcall.enqueue(new Callback() {})
okhttpcall.execute()
接下来验证我们的猜想。
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
这里的callAdapter是一个接口,如果我们写的是 Rxjava的返回形式, Flowable
那么他就是一个 > getOrganizations();
RxJava2CallAdapter
。 如果我们是普通的 Call
就是一个> listRepos(@Path("user") String user)
ExecutorCallAdapter
。我们直接看 RxJava2CallAdapter的实现。
@Override public Object adapt(Call<R> call) {
//根据是同步还是异步 不同的 Observable
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
// 如果isResult 和 isBody 都不是并且isFlowable isSingle isMaybe isCompletable都是false
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
//如果是 Flowable
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
如果isResult
和 isBody
都不是并且isFlowable
isSingle
isMaybe
isCompletable
都是false 那么他就是一个CallEnqueueObservable 对象。
CallEnqueueObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
//核心方法
call.enqueue(callback);
}
补一下Rxjava的知识详细见 Rxjava的调用逻辑以及线程切换原理 一个Rxjava 的链条其实是层层嵌套,从数据源位置会调用subscribeActual
产生数据,然后把传递给下一个Observer
。
我们可以看到最后他执行了call.enqueue(callback)
这也验证了上面我们的猜想。
总结
retrofit
的核心就只有一个方法create
,在这个方法里面启用了动态代理 创建了Service接口实例,当我们调用方法时,动态代理的InvocationHandler
的invoke
方法被执行,并且把我们调用方法信息和参数信息传递给invoke
方法用method
和args
接受,通过method
我们创建出ServiceMethod
对象,这个对象身上封装了注解信息,然后把这个对象传递给OkHttpCall
对象,他会得到ServiceMethod
和args
生成 OkHttp 的Request
和RealCall
实例。 最后根据我们的CallAdapter
不同的实现,执行call.enqueue(callback)