Retrofit源码浅析

if (callbackExecutor == null) throw new AssertionError();

return new ExecutorCallAdapterFactory(callbackExecutor);

}

//主线程执行器

static class MainThreadExecutor implements Executor {

private final Handler handler = new Handler(Looper.getMainLooper());

@Override

public void execute(Runnable r) {

handler.post®;

}

}

}

Android中默认的网络回调执行器为MainThreadExecutor,与主线程Looper的Handler绑定,将网络回调推送到主线程执行。

默认的CallAdapter.Factory为ExecutorCallAdapterFactory对象。CallAdapter.Factory主要适配接口的返回类型,如listRepo的接口方法为:

public interface GitHubService{

@GET(“users/{user}/repos”)

Call<List> listRepos(@Path(“user”) String user);

}

返回为Call< T>类型,Call< T>类型是由ExecutorCallAdapterFactory来适配的,如果在创建Retrofit对象时配置使用RxJava2CallAdapterFactory:

Retrofit retrofit = new Retrofit.Build()

.addCallAdapterFactoryFactory(RxJava2CallAdapterFactory.create())

,build()

那么接口listReops的返回类型可谓Observable< T>。

build最后初始化了转换器工厂类的集合,转换器工厂主要负责网络响应的解析,如果我们设置为GsonConverterFactory,那么就可以使用Gson解析网络结果,如果设置为ProtoConverterFactory,则可以使用ProtoBuf解析网络结果。

2、实现网络接口


在示例中,我们定义了网络接口Githubservice,然后使用创建的Retrofit对象的create方法来实现该接口,网络接口的实现为Retrofit最重要的逻辑,而网络接口的实现就是使用Java的动态代理实现的。create方法的调用和实现如下:

GitHubService githubService = retrofit.create(GitHubService.class);

public T create(final Class service) {

return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },

new Invocation​
Handler() {

private final Platform platform = Platform.get();

@Override public Object invoke(Object proxy, Method method, Object… args)

throws Throwable {

//创建ServiceMthod对象,完成接口方法的解析和封装

ServiceMethod serviceMethod = loadServiceMethod(method);

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

return serviceMethod.callAdapter.adapt(okHttpCall);

}

});

}

Retrofit的create方法的主要逻辑就是返回一个GithubService接口的代理对象。注意这里是代理对象,并不是通过implement关键字实现GithubService接口的实现类,当我们调用代理对象的接口方法时,如调用listRepos方法时:

Call<Lsit> octocat = githubSerivce.listRepos(“octocat”);

就会触发InvocationHandler的invoke方法的调用来完成listRepos接口的实现:返回一个Call< T>对象。

在invoke方法中,调用loadServiceMethod加载一个ServiceMethod对象,如果已经加载过了,则会从缓存中获取,如果没有缓存,则会创建一个新的ServiceMethod对象,在创建过程中完成了对网络接口方法的解析,进而封装成一个ServiceMethod对象。ServiceMethod对象中的成员变量如下:

final class ServiceMethod<R,T>{

final okhttp3.Call.Factory callFactory;

final CallAdapter<R,T> callAdapter;

private final HttpUrl baseUrl;

private final Converter<RespinseBody,R> respinserConverter;

private final String httpMethod; //请求方法:POST GET等

private final String relativeUrl;

private final Headers headers; //请求头

private final MediaType contentType;

}

这些成员变量大部分都是通过解析网络接口方法的注解完成初始化的。在获取到ServiceMethod对象后,使用它完成OkHttpCall< Object>对象的创建。最后通过代码:

return serviceMethod.callAdapter.adapt(okHttpCall);

返回一个对象。这个对象在当前示例下返回的是一个 ExecutorCallbackCall对象,它的创建过程还是比较复杂的,首先serviceMethod中的callAdapter对象是由createCallAdapter创建,而 createCallAdater内部是使用Retrofit对象来获取一个CallAdapter对象,createCallAdapter的调用和实现如下:

public ServiceMethod build() {

callAdapter = createCallAdapter();

}

private CallAdapter<?> createCallAdapter() {

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);

}

}

callAdapter方法会遍历CallAdapter.Factory集合adapterFactories,根据网络接口方法的返回值来匹配CallAdapter对象,进而返回对应的CallAdapter。Retrofit的callAdapter方法的实现如下:

//Retrofit.java

public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {

return nextCallAdapter(null, returnType, annotations);

}

public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,

Annotation[] annotations) {

checkNotNull(returnType, “returnType == null”);

checkNotNull(annotations, “annotations == null”);

int start = adapterFactories.indexOf(skipPast) + 1;

//遍历CallAdapter.Factory集合

for (int i = start, count = adapterFactories.size(); i < count; i++) {

//根据网络接口的返回类型匹配相对应的CallAdapter.Factroy,进而获取CallAdapter对象

CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);

if (adapter != null) {

return adapter;

}

}

throw new IllegalArgumentException(builder.toString());

}

之前在创建Retrofit对象的时候,会默认添加一个ExecutorCallAdapterFactroy对象到CallAdapter.Factory的集合中。

所以在遍历CallAdapter.Factroy集合遍历到ExecutorCallAdapterFactory对象时,就会调用该对象的get方法获取一个CallAdapter对象:

//ExecutorCallAdapterFactory.java

@Override

public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

Class<?> rawType = getRawType(returnType);

// 如果匹配的类型不为Call则返回null

if (rawType != Call.class) {

return null

}

final Type responseType = Utils.getCallResponseType(returnType);

//返回一个CallAdapter对象

return new CallAdapter<Object,Call<?>>{

@Override

public Type responseType(){

return responseType

}

@Override

public Call adapter(Call call){

return new ExecutorCallback<>(callbackExecutor,call);

}

}

}

在get方法中会根据网络接口的返回类型进行匹配,如果返回类型不为Call,则返回null,如果为Call类型,比如网络接口方法listRepos的返回类型为Call,那么就会通过判断来返回一个CallAdapter对象。再回到之前的代码:

serviceMethod.callAdapter.adapter(okHttpCall);

所以serviceMethod.callAdapter实际上是获取的是CallAdapter对象,CallAdapter对象的adapter方法会返回一个ExecutorCallbackCall对象。

所以,如果网络接口的返回类型为Call类型,那么在InvocationHandler的invoke方法中返回对象的类型为ExecutorCallbackCall。

3、网络请求的发送


通过网络接口的的实现可知,调用接口方法如下:

Call<List> octocat = getHubService.listRepos(“octocat”);

返回的Call对象实际上是ExecutorCallbackCall对象,所以接下来我们使用Call对象发送网络请求,如异步网络请求:

octocat.enqueue(mCallback);

实际上执行的是ExecutorCallbackCall中的enqueue方法,enqueue方法的实现如下:

@Override

public void enqueue(final Callback callback) {

call.enqueue(new okhttp3.Callback() {

//内部使用okhttp完成异步请求

@Override

//网络成功的回调

public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)

throws IOException {

Response response;

try {

response = parseResponse(rawResponse);

} catch (Throwable e) {

callFailure(e);

return;

}

callSuccess(response);

}

});

在enqueue方法内部,最终使用OkHttp执行网络请求,网络响应或失败都会通过MainThreadExecutor分发到主线程。

总结


  1. 从Retrofit的build方法 建造出一个 Retrofit对象,过程中有两个重要的工厂集合:

(1)adapterFactories集合,是CallAdapter的工厂实现类,里面装着网络回调执行器callbackExecutor(就是绑定主线程的Handler)

(2)converterFactories集合,Converter的工厂实现类,里面装着网络响应转化器,比如说Gson

  1. 网络接口的实现为Retrofit的最终要的逻辑,也就是其create方法

通过动态代理将网络接口转化成一个ServiceMethod对象,这个ServiceMethod中封装了网络请求的所有信息,然后通过 OkHttpCall<>(ServiceMehtod,args) 来封装成一个OkhttpCall对象,最后用这个OkHttpCall通过callAdapter方法 遍历一开始的adapterFactories集合,通过get方法最终来返回与网络接口匹配的CallAdapter对象。

  1. 通过create最终创造的CallAdapter对象可以通过调用其接口方法其实现一个同步/异步请求。

在异步请求中,enqueue实际上就是调用CallAdapter的enqueue方法 通过OkHttp实现网络请求,执行的结果通过MainThreadExecutor对象回调到主线程中。

关于OkHttp和Retroift疑问


有人就会问了,为什么Retrofit的网络请求是基于Okhttp,我们要去用Retrofit,而不是直接去用OkHttp呢?

我们先来看看OkHttp的特点

  • 支持SPDY,因此可以同一IP多个连接共享同一个socket(SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强)

  • 在Http/2不可用时, 连接池可极大减少延时;

  • 支持Gzip压缩响应体,降低传输内容的大小;

  • 支持Http缓存,避免重复请求;

  • 服务器

  • 配置多IP情况下,当前IP请求失败,支持自动切换到其他IP;

。。。。

再来看看OhHttp的缺点:

  • 是消息回来需要切到主线程,主线程要自己去写。

  • 调用比较复杂,需要自己进行封装。

  • 缓存失效:网络请求时一般都会获取手机的一些硬件或网络信息,比如使用的网络环境。同时为了信息传输的安全性,可能还会对请求进行加密。在这些情况下OkHttp的缓存系统就会失效了,导致用户在无网络情况下不能访问缓存。

再来看看Retrofit的优缺点

  • 可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等;

  • 请求的方法参数注解都可以定制;

  • 支持同步、异步和RxJava;

  • 超级解耦;

  • 可以配置不同的反序列化工具来解析数据,如json、xml等;

  • 使用非常方便灵活;

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
全性,可能还会对请求进行加密。在这些情况下OkHttp的缓存系统就会失效了,导致用户在无网络情况下不能访问缓存。

再来看看Retrofit的优缺点

  • 可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等;

  • 请求的方法参数注解都可以定制;

  • 支持同步、异步和RxJava;

  • 超级解耦;

  • 可以配置不同的反序列化工具来解析数据,如json、xml等;

  • 使用非常方便灵活;

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-bcOa2mAH-1719092443912)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值