Android高频面试专题 - 架构篇(三)Retrofit

Retrofit并不是网络请求框架,严格说只是对网络请求的一种封装,我们只需要定义一个接口类,在请求方法上加上相应的注解,甚至都不需要实现,就可以实现网络请求。但面试可就不只是要求会使用了,咱得知道内部是怎么实现的,才能顺利过关。

本篇内容,只是作为面试,提炼一下要点,建议还是先熟悉一下Retrofit的整个源码流程。关于retrofit完整源码解析,请回复【框架解析】获取视频讲解。

1、静态代理和动态代理

提到这个是因为,retrofit的精髓就在于内部的动态代理模式。

Java中的静态代理要求代理类(ProxySubject)和委托类(RealSubject)都实现同一个接口(Subject)。静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效率相对动态代理来说相对高一些,但是静态代理代码冗余大,一旦需要修改接口,代理类和委托类都需要修改。

动态代理的两种实现方式:

JDK自带的java.lang.reflect.Proxy,只能代理接口类

CGLib,生产子类来实现方法增强,无需实现接口

Retrofit使用的就是JDK的动态代理。

2、简单介绍下retrofit实现原理

首先,通过Builder创建Retrofit对象,在create方法中,通过JDK动态代理的方式,生成实现类,在调用接口方法时,会触发InvocationHandler的invoke方法,将接口的空方法转换成ServiceMethid, 然后生成okhttp请求,通过callAdapterFactory找到对应的执行器,比如RxJava2CallAdapterFactory,最后通过ConverterFactory将返回数据解析成JavaBena,使用者只需要关心请求参数,内部实现由retrofit封装完成,底层请求还是基于okhttp实现的。

3、Retrofit关键类

Retrofit源码非常简练,关键类就看类成员变量,就只有下面7个。

public final class Retrofit {
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> callAdapterFactories;
  final @Nullable Executor callbackExecutor;
  final boolean validateEagerly;
  ....
 }

ServiceMethod

核心处理类,解析接口中定义的请求方法参数和注解,通过toCall方法将其转换成okhttp的call对象,有了Call对象,就可以发送请求了。

callFactory

字面意思就是生产Call的工厂,这里的Call是okhttp包下面的Call,CallFactory默认就是OkHttpClient

HttpUrl

就是将创建retrofit对象时传入的baseUrl转换成对象,进行格式校验等。

converterFactories

数据解析器Converter,将response通过converterFactory转换成对应的JavaBean数据形式,常见解析器有,GsonConverterFactory,FastJsonConverterFactory,当然也有xml的。

callAdapterFactories

通过calladapter将原始Call进行封装,找到对应的执行器。如rxjavaCallFactory对应的Observable,转换形式Call --> Observable

callbackExecutor

主线程执行器,返回结果在UI线程执行

validateEagerly

是否立即校验所以接口方法,也就是将接口类中的方法全部转换成ServiceMethod,默认为false

4、注解相关

定义一个注解:

@Documented  //该注解类应该被javadoc工具记录
@Target(METHOD)  //注解使用的地方
@Retention(RUNTIME)  //注解保留期限
public @interface GET {
  String value() default ""; //注解参数
}

@Documented

表示该注解类会被收录进JavaDoc,不影响运行
@Target
表示注解要使用的地方,比如@Target(METHOD)用在方法上,@Target(TYPE)用在类/接口上,@Target(FIELD)用在成员变量上
@Retention
注解保留期限,@Retention(SOURCE)在源文件有效,@Retention(CLASS)在class文件中有效,@Retention(RUNTIME)在运行期有效
注解的使用

使用反射在运行时获取注解,进行业务逻辑处理

通过预编译工具进行处理(pre-compiler tools),在编译期间生成新的类文件

5、retrofit多个BaseUrl如何解决

根据不同BaseUrl创建不同的Retrofit对象(不可取)

@GET、@POST、@Url不仅可以传相对路径,也可以传绝对路径

大神JessYan的方案https://www.jianshu.com/p/2919bdb8d09a


更多完整面试专题和进阶知识分享,尽在“Android扫地僧”

在这里插入图片描述