Android 网络框架之Retrofit源码解析,2024最新Android开发者学习路线

Android类对应的源码不多,就几个方法,这里我们重点关注下面这几个方法:

**(1)defaultCallbackExecutor():**默认的线程执行器Executor,从源码可以看出,获取的是主线程的Hander,execute的时候,会post到主线程执行;

**(2)defaultCallAdapterFactories:**获取默认的CallAdapter.Factory,用于创建CallAdapter;

**(3)defaultConverterFactories:**获取默认的数据转换工厂ConverterFactory,用于创建转换器Converter;

总结:Platform主要是用于适配不同的平台,用于获取默认的Executor,请求适配器工厂类CallAdapterFactory,数据转换工厂类ConverterFactory等;

4.2、baseUrl

baseUrl,是我们网络请求的基础URL;

我们进源码里面看一下,具体做了啥操作;

这里主要做了两步操作:

1、首先第一步是通过解析这个baseUrl并返回一个HttpUrl对象; 2、第二步是将第一步创建的HttpUrl对象赋值给Builder;

这里我们主要看第一步的具体操作,这里的逻辑是在HttpUrl的 parse(@Nullable HttpUrl base, String input)里,通过解析URL,判断该请求的scheme是为http还是https,如果不是这其中一个,那么就会抛出异常,源码我们大致看一下;

然后下面还会解析URL,获取到主机地址host,端口号port,具体源码我就不贴了,感兴趣的可以跟着源码看一下;

4.3、Converter.Factory

这个我们上面在接受Retrofit的成员变量的时候有提过,是用于创建Converter的工厂,使用了抽象工厂的设计模式,而Converter是用来将请求返回的数据,转化为对应平台的数据,而这里,我们使用的是Gson平台;

我们先来看一下这个Converter.Factory,看看其背后是怎么实现的;

从源码可以看出,Converter.Factory是Converter的内部类,主要有两个方法,一个是requestBodyConverter,用于将请求的RequestBody转换为对应的转换器Converter;

另一个方法是responseBodyConverter,用于将返回的返回体ResponseBody转换为对应的转换器Converter;

而转换器Converter里面只有一个方法convert,用于将返回的数据转换为对应的类型;

我们在创建Retrofit的实例时,是通过GsonConverterFactory.create()来创建对应的转换器工厂的,下面我们来看看这个Gson的转换器工厂是怎么实现的;

先来看一下这个create()的方法;

最终是走的这里,进行了简单的赋值;

GsonConverterFactory这个工厂最重要的还是responseBodyConverter和requestBodyConverter方法,下面我们来具体分析;

  • requestBodyConverter:

在requestBodyConverter方法里面,通过class的Type类型,创建了Gson的TypeAdapter,这个TypeAdapter很熟悉,就是我们使用gson解析会用到的类,最终通过TypeAdapter和gson的参数创建了GsonRequestBodyConverter对象,下面来瞄一眼这个类的代码;

这个类的源码很简单,我们主要convert()这个方法;

这个方法的逻辑就是将传进来的value值通过TypeAdapter将其转化为ByteString,然后再传进RequestBody作为参数来构建RequestBody对象;

这个方法我们先了解到这里,后面在这个requestBodyConverter调用的地方再来讲一下;

  • responseBodyConverter:

这个方法和上面那个requestBodyConverter方法有点类似,也是通过class的Type类型,创建了Gson的TypeAdapter,最终通过TypeAdapter和gson的参数创建了GsonResponseBodyConverter,同理,我们也来看一下这个类的实现吧;

源码很简单,这里我们也是关注convert()这个方法;

这里的逻辑有没有很熟悉,就是我们经常用的gson解析,通过TypeAdapter读取JsonReader的数据,返回对应的数据类型,这里的参数ResponseBody就是我们上面GsonRequestBodyConverter的convert方法生成的;

到这里GsonConverterFactory就讲的差不多了,后面我们在用到的地方再详细讲一下;

4.5、CallAdapter.Factory

CallAdapter.Factory,从命名可以看出,是用来创建CallAdapter的工厂类,使用了抽象工厂的设计模式,而CallAdapter是用于将Call转化为我们所需要的请求类型,比如将Call转化为RxJava的调用类型;

而CallAdapter里面是通过adapt方法来进行转换的,adapt是接口的一个方法,交给子类去实现,这个方法的逻辑,我们下面将Retrofit的解析时,再统一讲解,这里是需要了解这是一个转换的方法即可;

image.png

下面我们来看看创建CallAdapter的工厂里面都有哪些方法,分别是用来干嘛的;

image.png

这个Factory的逻辑很少,只有几个方法,这里我们主要关注get方法,通过get方法来获取CallAdapter的对象,同理,这里也是交给子类去实现;

而上面我们Retrifit的创建,在CallAdapter.Factory的添加时,使用了RxJava的工厂,也就是RxJava2CallAdapterFactory,用于将Call请求转换为RxJava对应的请求;

下面我们来看看这个RxJava2CallAdapterFactory的实现逻辑吧;

RxJava2CallAdapterFactory的创建,也是通过RxJava2CallAdapterFactory.create()的方法,那么我们来看下这个create方法做了啥?

只是简单的new了一个RxJava2CallAdapterFactory,而构造方法里也没有其他的逻辑了,只是对Scheduler进行赋值,而这里创建时,传的是null;

上面我们看完RxJava2CallAdapterFactory的创建后,下面我们来看一下RxJava2CallAdapterFactory是怎么通过get方法创建一个CallAdapter的;

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

Class<?> rawType = getRawType(returnType);

if (rawType == Completable.class) {

// 创建RxJava2CallAdapter

return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,

false, true);

}

// 创建RxJava2CallAdapter

return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,

isSingle, isMaybe, false);

}

这个方法职责很明确,就是根据各种参数来创建RxJava的CallAdpter,也就是RxJava2CallAdapter;

这里我们来重点关注一个RxJava2CallAdapte的adapt方法的逻辑;

public Object adapt(Call call) {

// 第一步:根据是否是异步的参数创建对应的Observable

Observable<Response> responseObservable = isAsync

? new CallEnqueueObservable<>(call)
new CallExecuteObservable<>(call);

Observable<?> observable;

// 第二步:根据各种判断,再封装一层Observable返回

if (isResult) {

observable = new ResultObservable<>(responseObservable);

} else if (isBody) {

observable = new BodyObservable<>(responseObservable);

} else {

observable = responseObservable;

}

return observable;

}

这个方法的逻辑并复杂,主要是将Call请求转化为RxJava的请求,最终返回一个RxJava的被观察者:Observable,用于进行RxJava类型的网络请求,如上面的示例;

这个方法的逻辑主要有两步,我们先来看一下第一步创建的被观察者,这里会先判断是否是异步,如果是异步的话,那么就创建CallEnqueueObservable,否则就创建CallExecuteObservable;

这两个的区别就是,在调用订阅(subscribe)的时候,会执行CallEnqueueObservable的subscribeActual方法,最终是通过OkHttpCall的enqueue方法来执行异步请求;

而CallExecuteObservable在调用订阅(subscribe)的时候,也会执行CallEnqueueObservable的subscribeActual方法,在这个方法里,就直接调用OkHttpCall的execute方法来执行同步请求;

而第二步的封装,这里我们主要以BodyObservable来进行讲解,这个类会对订阅的观察者进行封装,在onNext方法中将body返回;这一步可以理解为对返回的结果进行处理;

这里是RxJava的用法,我默认你是会的,如果对RxJava还不熟悉的同学,可以后面去看看RxJava的用法;

到此,Retrofit的CallAdapter.Factory的逻辑就先告一段落了,下面我们来看看Retrofit的最终build()方法的逻辑;

4.5、Retrofit.Builder#build

废话不多说,我们直接撸源码;

public Retrofit build() {

// 判断当callFactory(OkHttpClient)为空,就重新创建一个OkHttpClient进行赋值;

okhttp3.Call.Factory callFactory = this.callFactory;

if (callFactory == null) {

callFactory = new OkHttpClient();

}

// 判断Executor为空时,就用Platform的默认Executor进行赋值,上面我们讲过,这里面使用的是主线的的Handler;

Executor callbackExecutor = this.callbackExecutor;

if (callbackExecutor == null) {

callbackExecutor = platform.defaultCallbackExecutor();

}

// 通过添加的CallAdapter.Factory来创建一个新的CallAdapter.Factory集合;

List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);

// 添加Platform的默认CallAdapter.Factory,如果我们没有添加CallAdapter.Factory,那么就会使用这个Platform的默认CallAdapter.Factory; callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

// 创建Converter.Factory的集合

List<Converter.Factory> converterFactories = new ArrayList<>(

1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

// Add the built-in converter factory first. This prevents overriding its behavior but also

// ensures correct behavior when using converters that consume all types.

// 添加默认的Converter.Factory

converterFactories.add(new BuiltInConverters());

// 添加自定的Converter.Factory

converterFactories.addAll(this.converterFactories);

// 添加Platform的默认Converter.Factory

converterFactories.addAll(platform.defaultConverterFactories());

// 最终创建Retrofit实例;

return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),

unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);

}

这个build()方法,主要是做各种参数的赋值,最终通过参数来创建Retrofit的实例,那么到这里Retrofit的创建就差不多将完了,下面我们将会学习到Retrofit的核心;

为什么我们可以通过接口定义一个类型,就可以执行请求了,对于这些方法的解析,以及参数的赋值的操作是在哪里呢?

这么就涉及到Retrofit使用的一个很重要的设计模式了,也就是动态代理设计模式;

5、Retrofit的核心,动态代理


5.1、什么是代理?

举个例子,假如我要去超市买水果,可是我好懒,周末就想呆在家里不想出门,但是心里又很想吃水果,那怎么办呢?

只能打开外卖App,在上面买完之后,由外卖小哥送过来,这时候,我就通过中介,外卖App来买到水果,而这个过程叫做代理;

不直接操作,而是委托第三方来进行操作,从而达到目的;

而Java的代理分为静态代理和动态代理;

5.2、什么是静态代理?

如果代理类在程序运行之前就已经存在了,那么这种代理方式就被称为静态代理;

还是以上面的例子,我要买水果,来定义一个买水果的接口Operator;

public interface Operator {

// 买水果

void buyFruit();

}

而我们的代理类外卖App需要实现这个接口,同时,将需要委托的对象传进来,在buyFruit的过程中,做了一些出来,比如去超市取货,取完货之后,再送货;

public class AppAgent implements Operator {

private Operator operator;

public AppAgent(Operator operator) {

this.operator = operator;

}

@Override

public void buyFruit() {

// 1、在App上,提供商品给用户下单

// 2、根据订单去超市采购水果

operator.buyFruit();

// 3、送货给客户

}

}

委托的对象,超市:

public class Market implements Operator {

@Override

public void buyFruit() {

// 到超市买水果

}

}

那么最终的实现效果就是,我们通过外卖App的一顿操作,从超市买到了水果,如下:

public class Main {

public static void main(String[] args) {

// 委托对象,超市;

Market market = new Market();

// 代理对象,外卖App;

AppAgent appAgent = new AppAgent(market);

// 通过外卖App的代理,从超市买到了水果;

appAgent.buyFruit();

}

}

以上就是我们静态代理的过程,这个例子只是举了买水果这个过程,但是如果我还想要买菜,买生活用品等一系列东西呢?

我就得在接口Operator里面再多新增好几个方法,同样的代理类也要跟着去重写一堆的方法,但是这些方法做的操作其实都是一样的,都是买这个动作,但是我们不得已,新增一种类型,我们就得在代理类里面再重写并调用;

那么这个过程其实是可以抽出来的,这种方式就叫做动态代理;

5.3、动态代理

动态代理,和静态代理不同的是,动态代理的方法是运行后才创建的,而静态代理是运行前就存在的了;

说白了,和静态代理不同的是,动态代理的方法都是在运行后,自动生成的,所以叫动态代理;

下面我们来看看动态代理是咋用的;

在使用动态代理的时候,被代理类需要实现InvocationHandler这个接口,,这个invoke方法是在动态生成的代理类中调用的,对应着我们上面在静态代理operator.buyFruit()这个方法的调用,下面来看一下这个方法对应的参数;

public interface InvocationHandler {

// Object proxy:接口的具体实现类;

// Method method:解析之后自动生成的方法;

// Object[] args:方法对于的参数;

Object invoke(Object proxy, Method method, Object[] args);

}

而最终运行时生成的代理类,一般名称会是Proxy1这种,通过Proxy.newProxyInstance()方法来生成的,这个下面会讲到,先来看一下下面的伪代码;

public final class $Proxy0 extends Proxy implements Operator {

public final boolean buyFruit() {

// h是InvocationHandlel,调用了invoke方法;

super.h.invoke(this, m1, (Object[])null);

}

}

}

在生成的代理类中,会实现我们的接口,并重写方法,在方法里面通过InvocationHandler回调参数到invoke方法里,最终通过反射调用被代理对象的方法;

而我们通过实现这个InvocationHandler接口,在invoke方法里面,通过method.invoke(object, args)可以来调用被代理的方法,然后我们可以在这个method.invoke(object, args)之前或者之后做一些处理,这样所以的方法都可以一并进行处理,而不是每次新增一个方法,就得重写一遍逻辑;

下面来看一下具体实现:

public class CustomProxy implements InvocationHandler {

private Object object;

public CustomProxy(Object object) {

this.object = object;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 1、在App上,提供商品给用户下单

// doSomeThing();

// 2、根据订单去超市采购东西(在这个方法之前或者之后都可以统一处理操作)

Object invoke = method.invoke(object, args);

// 3、送货给客户

// doSomeThing();

return invoke;

}

}

下面来看一下,最终的调用;

public class Main {

public static void main(String[] args) {

// 创建被代理类

CustomProxy customProxy = new CustomProxy(new Market());

// 动态生成代理类

Operator proxyInstance = (Operator) Proxy.newProxyInstance(Operator.class.getClassLoader(), new Class[]{Operator.class}, customProxy);

// 调用对应的方法

proxyInstance.buyFruit();

}

}

这里通过Proxy.newProxyInstance()方法,动态生成代理类$Proxy0这种,这里涉及到的反射的知识,就不再赘述了;

然后动态代理类调用方法,最终会走到CustomProxy的invoke()方法,然后我们在这个方法里面通过method.invoke(object, args)来进行最终的代理调用,而在这个最终的代理调用的前后,我们可以实现自定义的逻辑;

这个实现了InvocationHandler接口的CustomProxy,更像是一个拦截类,在代理方法的调用过程中进行拦截,然后再实现我们的自定义逻辑;

至此,动态代理你理解了吗?没有理解也没关系,多看几遍,多练几遍就可以了;

6、Retrofit的动态代理


6.1、Retrofit为什么要使用动态代理?

首先,让我们来想一个问题,Retrofit为什么要使用动态代理?

使用动态代理的好处就是在调用方法之前,我们可以统一做一些操作,而不必新增一个方法就去写一遍逻辑;

而Retrofit巧妙的使用了动态代理在调用接口的方法之前,统一的去解析处理Header和URL等操作;

这样就不用每次在新增一个请求的方法,就去写一遍这个解析的逻辑;

那么接下来我们来看看Retrofit的怎么解析这些接口的;

6.2、Retrofit是怎么使用动态代理的?

下面我们来看一下Retrofit的create的方法,动态代理的逻辑是在这里实现的;

public T create(final Class service) {

// 验证接口的参数以及配置是否正确

if (validateEagerly) {

eagerlyValidateMethods(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 Object invoke(Object proxy, Method method, @Nullable Object[] args)

throws Throwable {

// 判断是否是Object,如果是的话,就直接调用方法返回

if (method.getDeclaringClass() == Object.class) {

return method.invoke(this, args);

}

// 判断是否是Java8平台的默认方法类型,如果是的话,就调用Java8平台的invokeDefaultMethod方法

if (platform.isDefaultMethod(method)) {

return platform.invokeDefaultMethod(method, service, proxy, args);

}

// 解析方法;

return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

}

});

}

这里我们将这个方法分为两步;

第一步: eagerlyValidateMethods方法,这个方法的逻辑是用于加载接口的配置,用于判断接口对应的header,body以及方法的参数等配置是否正确,如果不正确那么就会抛出异常;

第二步: loadServiceMethod方法,这个方法的逻辑主要是用于解析我们在接口配置的注解以及参数,比如header,body,url等等;

这里我们重点关注第二步的loadServiceMethod方法方法;

我们来看一下其源码的具体实现;

ServiceMethod<?> loadServiceMethod(Method method) {

// 先从缓存map集合里面获取ServiceMethod;

ServiceMethod<?> result = serviceMethodCache.get(method);

if (result != null) return result;

synchronized (serviceMethodCache) {

result = serviceMethodCache.get(method);

if (result == null) {

// 如果从缓存map里面获取不到ServiceMethod,那么再通过解析注解,获取到ServiceMethod对象;

result = ServiceMethod.parseAnnotations(this, method);

// 将解析后的ServiceMethod对象存入到map集合中;

serviceMethodCache.put(method, result);

}

}

return result;

}

这里做的操作很简单,就是获取ServiceMethod,而在获取ServiceMethod的过程中,会先从缓存的map中获取,如果获取不到了再进行解析,这样就不必获取一次ServiceMethod,就去解析一次,比较耗性能;

而这个ServiceMethod的类是个抽象类,只有两个方法,一个是静态的parseAnnotations方法,一个是抽象的invoke方法;

我们先来看一下这个parseAnnotations方法;

static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {

// 通过解析接口方法的注解,获取RequestFactory

RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

// 解析注解并获取ServiceMethod对象

return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

面试复习笔记

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
mg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-JorjleTK-1712687243483)]

面试复习笔记

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

[外链图片转存中…(img-pVZW9OAb-1712687243484)]

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

[外链图片转存中…(img-7jckhbf2-1712687243484)]

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

[外链图片转存中…(img-I2Dy6dOh-1712687243484)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-YWBTnfjY-1712687243485)]

  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值