Retrofit 2.0总结
- 1. 简介
- Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
- 原因:网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装
- App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作
- 设计模式
- 动态代理模式
- 那么Retrofit为何要这么设计呢?
- 我们一个应用的请求接口可能有很多个,通过动态代理模式,能动态为每个接口都生成一个具体的代理类,并且实现了我们的接口,我们不需要关心具体请求细节是怎样的,只需要声明我们的接口并传递给Retrofit即可,然后由Retrofit动态生成具体请求对象,发起请求并将结果返回给我们,我想这也就是为何Retrofit这么受欢迎的原因之一。
- 总结
- 综上,一般为了在不修改原有类的情况下扩展其功能,并且保护被代理类不被访问,我们可以选择代理模式。动态代理模式是通过动态生成代理类的代理模式,它其实就是将目标类的类加载器和相应的接口传进去代理器(InvocationHandler),通过代理器生成了一份新的”备份“——代理类,这个动态生成的代理类里实现了接口中的所有方法,然后在 InvocationHandler.invoke() 中通过反射机制,调用目标类对象的方法。
- 动态代理运用了很多反射,在性能上会有所影响,所以并不是随处滥用,用得得当会有很好的效果,比如常说的AOP切面编程,实现无侵入式的代码扩展。
- 那么Retrofit为何要这么设计呢?
- 适配器模式
- Retrofit中用了适配器模式把OkHttpCall轻松适配到了RxJava的Observable、Android的ExecutorCallbackCall、Java8的CompletableFuture,当然还有一个Guava,如果以后要扩展就可以在继续适配就行,非常容易扩展!
- 链接:https://www.jianshu.com/p/f1b512759d6e
- 装饰模式
- 采用了装饰模式:ExecutorCallbackCall = 装饰者,而里面真正去执行网络请求的还是OkHttpCall
- 使用装饰模式的原因:希望在OkHttpCall发送请求时做一些额外操作。这里的额外操作是线程转换,即将子线程切换到主线程
- OkHttpCall的enqueue()是进行网络异步请求的:当你调用OkHttpCall.enqueue()时,回调的callback是在子线程中,需要通过Handler转换到主线程进行回调。ExecutorCallbackCall就是用于线程回调;
- 当然以上是原生Retrofit使用的切换线程方式。如果你用Rxjava,那就不会用到这个ExecutorCallbackCall而是RxJava的Call,此处不过多展开
- 链接:https://juejin.im/post/5a9f36acf265da23a1416cb6
- 动态代理模式
- 3. Retrofit 的具体使用
- 具体过程解释如下:
- 具体过程解释如下:
- 4. 源码分析
- 1. 创建Retrofit对象
- a. 使用步骤
- 步骤1
- 成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量,即配置好:
- serviceMethod
- 包含所有网络请求信息的对象
- baseUrl
- 网络请求的url地址
- callFactory
- 网络请求工厂
- CallAdapterFactory
- 该Factory生产的是CallAdapter
- CallAdapter
- 定义
- 网络请求执行器(Call)的适配器
- Call在Retrofit里默认是OkHttpCall
- 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactor
- 作用
- 将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式
- 1. 一开始Retrofit只打算利用OkHttpCall通过ExecutorCallbackCall切换线程;但后来发现使用Rxjava更加方便(不需要Handler来切换线程)。想要实现Rxjava的情况,那就得使用RxJavaCallAdapterFactoryCallAdapter将OkHttpCall转换成Rxjava(Scheduler)
- 2. Retrofit还支持java8、Guava平台。
- 1. 一开始Retrofit只打算利用OkHttpCall通过ExecutorCallbackCall切换线程;但后来发现使用Rxjava更加方便(不需要Handler来切换线程)。想要实现Rxjava的情况,那就得使用RxJavaCallAdapterFactoryCallAdapter将OkHttpCall转换成Rxjava(Scheduler)
- 将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式
- 好处
- 用最小代价兼容更多平台,即能适配更多的使用场景
- 网络请求执行器(Call)的适配器
- 定义
- CallAdapter
- 该Factory生产的是CallAdapter
- CallAdapterFactory
- 网络请求工厂
- adapterFactories
- 网络请求适配器工厂的集合
- converterFactories
- 数据转换器工厂的集合
- callbackExecutor
- 回调方法执行器
- serviceMethod
- 成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量,即配置好:
- 步骤2
- Builder设置了默认的,特别注意,这里只是设置了默认值,但未真正配置到具体的Retrofit类的成员变量当中
- 平台类型对象:Android
- 网络请求适配器工厂:CallAdapterFactory
- CallAdapter用于对原始Call进行再次封装,如Call到Observable
- 数据转换器工厂: converterFactory
- 回调执行器:callbackExecutor
- Builder设置了默认的,特别注意,这里只是设置了默认值,但未真正配置到具体的Retrofit类的成员变量当中
- 步骤3
- baseUrl()用于配置Retrofit类的网络请求url地址
- 将传入的String类型url转化为适合OKhttp的HttpUrl类型的url
- baseUrl()用于配置Retrofit类的网络请求url地址
- 步骤4
- 创建一个含有Gson对象实例的GsonConverterFactory并放入到数据转换器工厂converterFactories里
- 即Retrofit默认使用Gson进行解析
- 若使用其他解析方式(如Json、XML或Protocobuf),也可通过自定义数据解析器来实现(必须继承 Converter.Factory)
- GsonConverterFactory.creat()
- GsonConverterFactory.creat()是创建了一个含有Gson对象实例的GsonConverterFactory,并返回给addConverterFactory()
- addConverterFactory
- addConverterFactory
- GsonConverterFactory.creat()是创建了一个含有Gson对象实例的GsonConverterFactory,并返回给addConverterFactory()
- GsonConverterFactory.creat()
- 创建一个含有Gson对象实例的GsonConverterFactory并放入到数据转换器工厂converterFactories里
- 步骤5
- 步骤1
- b. 设计模式
- Retrofit实例是使用建造者模式通过Builder类进行创建的
- Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节是配置了:
- 平台类型对象(Platform - Android)
- 网络请求的url地址(baseUrl)
- 网络请求工厂(callFactory)
- 默认使用OkHttpCall
- 网络请求适配器工厂的集合(adapterFactories)
- 默认使用OkHttpCall
- 本质是配置了网络请求适配器工厂- 默认是ExecutorCallAdapterFactory
- 数据转换器工厂的集合(converterFactories)
- 本质是配置了数据转换器工厂
- 回调方法执行器(callbackExecutor)
- 默认回调方法执行器作用是:切换线程(子线程 - 主线程)
- Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节是配置了:
- Retrofit实例是使用建造者模式通过Builder类进行创建的
- a. 使用步骤
- 2. 创建网络请求接口的实例
- 2.1 使用步骤
- 2.2 设计模式
- Retrofit采用了外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法,具体细节是:
- 动态创建网络请求接口的实例 代理模式 - 动态代理
- 创建 serviceMethod对象 建造者模式 & 单例模式(缓存机制)
- 对 serviceMethod对象进行网络请求参数配置:通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络请求的url地址、网络请求执行器、网络请求适配器 & 数据转换器。(策略模式)
- 对 serviceMethod对象加入线程切换的操作,便于接收数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理装饰模式
- 最终创建并返回一个OkHttpCall类型的网络请求对象
- Retrofit是通过外观模式 & 代理模式 使用create()方法创建网络请求接口的实例(同时,通过网络请求接口里设置的注解进行了网络请求参数的配置)
- Retrofit采用了外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法,具体细节是:
- 步骤3
- 创建网络接口实例用了外观模式 & 代理模式:
- 源码分析
- ServiceMethod serviceMethod = loadServiceMethod(method);
- ServiceMethod类 构造函数
- ServiceMethod的Builder()
- ServiceMethod的build()
- 当选择了RxjavaCallAdapterFactory后,Rxjava通过策略模式选择对应的adapter
- 根据网络接口方法的返回值类型来选择具体要用哪种CallAdapterFactory,然后创建具体的CallAdapter实例
- 当选择了RxjavaCallAdapterFactory后,Rxjava通过策略模式选择对应的adapter
- OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
- 根据第一步配置好的ServiceMethod对象和输入的请求参数创建okHttpCall对象
- 根据第一步配置好的ServiceMethod对象和输入的请求参数创建okHttpCall对象
- return serviceMethod.callAdapter.adapt(okHttpCall);
- 将第二步创建的OkHttpCall对象传给第一步创建的serviceMethod对象中对应的网络请求适配器工厂的adapt()
- 返回对象类型:Android默认的是Call<>;若设置了RxJavaCallAdapterFactory,返回的则是Observable<>
- 采用了装饰模式:ExecutorCallbackCall = 装饰者,而里面真正去执行网络请求的还是OkHttpCall
- 使用装饰模式的原因:希望在OkHttpCall发送请求时做一些额外操作。这里的额外操作是线程转换,即将子线程切换到主线程
- OkHttpCall的enqueue()是进行网络异步请求的:当你调用OkHttpCall.enqueue()时,回调的callback是在子线程中,需要通过Handler转换到主线程进行回调。ExecutorCallbackCall就是用于线程回调;
- 当然以上是原生Retrofit使用的切换线程方式。如果你用Rxjava,那就不会用到这个ExecutorCallbackCall而是RxJava的Call,此处不过多展开
- 返回对象类型:Android默认的是Call<>;若设置了RxJavaCallAdapterFactory,返回的则是Observable<>
- 步骤4讲解:Call<JavaBean> call = NetService.getCall();
- NetService对象实际上是动态代理对象Proxy.newProxyInstance()(步骤3中已说明),并不是真正的网络请求接口创建的对象
- 当NetService对象调用getCall()时会被动态代理对象Proxy.newProxyInstance()拦截,然后调用自身的InvocationHandler # invoke()
- invoke(Object proxy, Method method, Object... args)会传入3个参数:Object proxy:(代理对象)、Method method(调用的getCall())Object... args(方法的参数,即getCall(*)中的*)
- 最终创建并返回一个OkHttpCall类型的Call对象
- OkHttpCall类是OkHttp的包装类
- 创建了OkHttpCall类型的Call对象还不能发送网络请求,需要创建Request对象才能发送网络请求
- 最终创建并返回一个OkHttpCall类型的Call对象
- 将第二步创建的OkHttpCall对象传给第一步创建的serviceMethod对象中对应的网络请求适配器工厂的adapt()
- ServiceMethod类 构造函数
- ServiceMethod serviceMethod = loadServiceMethod(method);
- 源码分析
- 创建网络接口实例用了外观模式 & 代理模式:
- 2.1 使用步骤
- 3. 执行网络请求
- 3.1 同步请求OkHttpCall.execute()
- 3.1.1 发送请求过程
- 步骤1:对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
- 步骤2:使用OkHttp的Request发送网络请求;
- 步骤3:对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个Response<T>对象
- 3.1.2 具体使用
- Response<JavaBean> response = call.execute();
- 3.1.3 源码分析
- ServiceMethod几乎保存了一个网络请求所需要的数据
- 发送网络请求时,OkHttpCall需要从ServiceMethod中获得一个Request对象
- 解析数据时,还需要通过ServiceMethod使用Converter(数据转换器)转换成Java对象进行数据解析
- 为了提高效率,Retrofit还会对解析过的请求ServiceMethod进行缓存,存放在Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();对象中,即第二步提到的单例模式
- 3.1.1 发送请求过程
- 3.2 异步请求OkHttpCall.enqueue()
- 3.2.1 发送请求过程
- 步骤1:对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
- 步骤2:使用OkHttp的Request发送网络请求;
- 步骤3:对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个Response<T>对象
- 步骤4:进行线程切换从而在主线程处理返回的数据结果
- 若使用了RxJava,则直接回调到主线程
- 异步请求的过程跟同步请求类似,唯一不同之处在于:异步请求会将回调方法交给回调执行器在指定的线程中执行。
- 指定的线程此处是指主线程(UI线程)
- 3.2.2 具体使用
- call是一个静态代理
- 使用静态代理的作用是:在okhttpCall发送网络请求的前后进行额外操作
- 当选择了RxjavaCallAdapterFactory后,Rxjava通过策略模式选择对应的adapter
- 根据网络接口方法的返回值类型来选择具体要用哪种CallAdapterFactory,然后创建具体的CallAdapter实例
- 当选择了RxjavaCallAdapterFactory后,Rxjava通过策略模式选择对应的adapter
- 3.2.3 源码分析
-
- 3.2.1 发送请求过程
- 3.1 同步请求OkHttpCall.execute()
- 1. 创建Retrofit对象
- 5. 本质流程
- 具体过程
- 1. 通过解析 网络请求接口的注解 配置 网络请求参数
- 2. 通过 动态代理 生成 网络请求对象
- 3. 通过 网络请求适配器 将 网络请求对象 进行平台适配
- 平台包括:Android、Rxjava、Guava和java8
- 5. 通过 数据转换器 解析服务器返回的数据
- 6. 通过 回调执行器 切换线程(子线程 ->>主线程)
- 7. 用户在主线程处理返回结果
- 4. 通过 网络请求执行器 发送网络请求
- 通过 动态代理 生成 网络请求对象
- 通过 网络请求适配器 将 网络请求对象 进行平台适配
- 具体过程
- 参考