1、Retrofit
根据官网的描述:一种类型安全的java和android的http客户端。
类型安全:指的是在编译的时候就会把类型错误暴露出来,不会在运行的时候抛出类型错误。
public interface GitHubService
{
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}
使用Retrofit首先定义一个服务接口
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val retrofit:Retrofit = Retrofit.Builder()
.baseUrl("https://aip.github.com/")
.build()
val service = retrofit.create(GitHubService::class.java)
val repos: Call<List<Repo>> = service.listRepos("octocat")
repos.enqueue(object :Callback<List<Repo>?>{
override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
TODO("Not yet implemented")
}
override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
TODO("Not yet implemented")
}
})
}
}
Retrofit的基本get请求调用如上,可见如OkHttp一样,主要的入口是enqueue()
的方法,追踪enqueue可以发现是一个接口方法。所以最终的实现是由repos对象提供的。repos对象由service里面的listRepos()
方法提供,追踪发现是我们在最开始定义接口,故所以,最终的业务入口可以成功定位出来了,就是:
retrofit.create(GitHubService::class.java)
1.1、create()
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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});//动态代理
validateServiceInterface()
方法主要是对接口的规范性做检查.PS:里面有个参数能控制是否进行激进检查,激进检查可以把所以的接口方法都在初始化的时候检查,涉及到反射,可快速测试,但是有可能影响性能。
剩下的所有的代码其实都是调用newProxyInstance()
的方法。该方法也是实现了retrofit的核心,动态代理功能。
何为代理?代理,指的是retrofit创建一个类继承我们的接口,并且会实现我们接口中的方法,也就是说retrofit代理了我们所以的接口。
何为动态?动态,指的是在该类是在运行的时候创建,而不是编译时。
1.2、newProxyInstance()
该方法一共有三个参数: ClassLoader,Class<?>[],InvocationHandler
其中一是ClassLoader,任意一ClassLoader都可用,Class<?>[]为接口集合,即我们传进的接口,第三个匿名内部类InvocationHandler。所以如何实现匿名内部类,就是如果实现retrofit的动态代理。
具体实现接口方法的模式,大概是将InvocationHandler这个内部类的对象,交给代理类(运行过程中继承我们接口,创建的类),并且通过我们接口中的方法来实际调用InvocationHandler#invoke
。可以当成代理类是载体,内部类InvocationHandler#invoke
是实际的干活人。
1.3、InvocationHandler#invoke()
@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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
第一个if里面的逻辑,检查是否为Object方法,如果是,直接调用。也就是如果我们接口中的方法是系统的方法,如toString等,Retrofit就不代理,直接调用。
第二个if里面的逻辑,不代理JAVA8里面的默认方法。
最后一行返回了一个 loadServiceMethod(method)#invoke();
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
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);
}
abstract @Nullable T invoke(Object[] args);
}
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
loadServiceMethod()
调用 HttpServiceMethod的parseAnnotations()
实现了他本身的invoke()
方法。创建了一个retrofit的OkHttpCall对象,然后用过adapt()
在做了某些操作。我们先来看看OkHttpCall是个怎么样的对象。
我们可以发现OkHttpCall继承于Call接口,并且实现了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
}
}
通过上述代码,我们不难发现,enqueue()
的发方法,创建了一个okhttp的Call
okhttp3.Call call;
并却,在内部实现了okhttp3的enqueue()方法
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
}
}
到这里,Retrofit的基本工作就做完了,剩下正真的网络请求就交给OkHttp去做了。
附带一篇Retrofit深度解析好文:https://www.jianshu.com/p/0c055ad46b6c