上一篇讲解了retrofit2的简单用法,这一边主要解析一下reftofit2的原理,就从Retrofit的create(final Class<T> service)方法看起,这个方法返回一个call对象,访问网路是通过这个对象去访问的。
我们先来看看create()这个方法里干了些什么:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
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, 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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}</span>
当看到proxy是不是有点眼熟呢,没错就是动态代理,主要使用newProxyInstance()方法来返回一个类的代理实例,它的参数需要传递一个类的加载器,类本身,以及InvocationHandler的子类对象,这里它使用的是匿名内部类。主要动作都是在InvocationHandler中进行的,它里面只有一个invoke()方法,每当我们调用代理类里面的方法时,invoke()方法都会被执行,我们可以从参数中获得很多信息,method的方法名,从args中获取到方法的参数等。
invoke()方法里主要做的就是:
首先,将method转换为serviceMethod;
然后,通过serviceMethod,arg获取到okHttpCall对象;
最后,通过serviceMethod.callAdapter.adapt()对okHttpCall进行封装返回call对象。
下面一步步来分析。
一、将method转换为serviceMethod
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod 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对象,并把它缓存起来。下面来看看这个构造器的build(0方法里都干了些啥:
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
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?");
}
responseConverter = createResponseConverter();
...
return new ServiceMethod<>(this);
}
首先在builder的构造方法里初始化一些参数,然后再build()方法里通过new ServiceMethod(),并将这个对象返回来获得servicMethod对象,下面来仔细看看build()方法:
1、createCallAdapter()获得callAdapter,源码如下:
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
这个方法里最主要就是获取到method的类型和注解,然后调用了retrofit的callAdapter()方法,
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}</span>
而retrofit的callAdapter()方法调用的是自己的nextCallAdapter()方法:
<span style="font-size:14px;">public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
这个方法里,遍历了adapterFactories,从中获取callAdapter对象,adapterFactories这个集合中有哪些calAdapter对象呢,
public static final classBuilder {
...
publicBuilderaddCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
...
public Retrofitbuild() {
List<CallAdapter.Factory> adapterFactories = newArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
...
}
}
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if(callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
上面的代码中我们可以看到,不管我们有没有往adapterFactories中添加元素,adapterFactories集合中都至少会有一个ExcutorCallAdapterFactory对象,也就是说上面通过createCallAdapter()方法得到的callAdapter就是ExcutorCallAdapterFactory,这个在后面很关键。
2、createResponseConverter()得到responseConverter转换器对象,它的作用是寻找合适的数据类型转换器,
这个的过程和构造callAdapter对象基本一致,这里不再赘述。
二、通过serviceMethod,arg获取到okHttpCall对象
OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
这一步比较简单,就是传递参数
三、通过serviceMethod.callAdapter.adapt()对okHttpCall进行封装返回call对象
我们知道serviceMethod.callAdapter就是ExcutorCallAdapterFactory,那我们只要看ExcutorCallAdapterFactory的adapt()方法就可以了:
<R> T adapt(Call<R> call);
就这么一句,这是嘛呀,但是经过第一步的分析,我们已知道serviceMethod.callAdapter就是ExecutorCallAdapterFactory,那么我们可以看看在ExecutorCallAdapterFactory类中有没有发现CallAdapter的另类应用呢,一看,果不其然在重写父类的get()方法中我们找到了答案:
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
当看到return new CallAdapter中的adapt(Call call)我们就完全知其所以然了,至于ExecutorCallbackCall怎么应用的我们在发起网络请求的时候讲解。
ok,当我们得到接口的代理实例之后,通过代理接口调用里面的方法,就会触发InvocationHandler对象中的invoke方法,从而完成上面的三个步骤并且返回一个Call对象,通过Call对象就可以去完成我们的请求了,Retrofit为我们提供两种请求方式,一种是同步,一种是异步。我们这里就以异步方式来讲解:
当我们通过retrofit的create()方法获得call对象,再调用call.enque()去访问网络时,方法中有回掉函数,回掉函数里重写两个方法,一个成功,一个失败,来看下怎么回事,这个call对象其实就是ExcutorCallAdapterFactory,来看里面具体实现:public static final classExecutorCallbackCall<T> implementsCall<T> {
finalExecutorcallbackExecutor;
finalCall<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Overridepublicvoidenqueue(final Callback<T> callback) {
if(callback == null)thrownewNullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
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(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
在ExecutorCallbackCall类中,封装了两个对象一个是callbackExecutor,它主要是把现在运行的线程切换到主线程中去,一个是delegate对象,这个对象就是真真正正的执行网络操作的对象,那么它的真身到底是什么呢?还记得我们在获取代理接口第三步执行的serviceMethod.callAdapter.adapt(okHttpCall)的分析吧,经过辗转几步终于把okHttpCall传递到了new ExecutorCallbackCall<>(callbackExecutor, call);中,然后看看ExecutorCallbackCall的构造方法:
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
可以知道delegate即使okHttpCall对象,来看okHttCall怎么异步访问网络的:
@Override
public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("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) {
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)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
上面的代码中可以看到,里面封装了一个okhttp3.Call对象,直接利用okhttp进行异步网络访问,okhttp怎么访问网络的这里不再讲解,感兴趣的可以自行翻看源码。
好了到这里,retrofit访问网络的原理基本解析完毕,希望能对大家有帮助,有什么不对之处还请多多指正。