深入剖析 Android 网络开源库 Retrofit 的源码详解
文章目录
- 概述
- 一、Retrofit 简介
- Android主流网络请求库
- 二、Retrofit 源码剖析
- 1. Retrofit 网络请求过程
- 2. Retrofit 实例构建
- 2.1 Retrofit.java
- 2.2 Retrofit.Builder()
- 2.2.1 Platform.get()
- 2.2.2 Android 平台
- 2.3 Retrofit.Builder().baseUrl()
- 2.4 Retrofit.Builder.client()
- 2.5 Retrofit.Builder.addConverterFactory()
- 2.5.1 GsonConverterFactory.create()
- 2.6 Retrofit.Builder.addCallAdapterFactory()
- 2.6.1 RxJava2CallAdapterFactory.create()
- 2.7 Retrofit.Builder.build()
- 3. Retrofit 创建网络请求接口实例
- 3.1 Retrofit.create()
- 3.2 Retrofit.loadServiceMethod()
- 3.3 ServiceMethod.parseAnnotations()
- 3.3.1 RequestFactory.parseAnnotations()
- 3.4 HttpServiceMethod.parseAnnotations()
- 3.4.1 HttpServiceMethod.createCallAdapter()
- 3.4.2 Retrofit.callAdapter()
- 3.4.3 HttpServiceMethod.createResponseConverter()
- 3.4.4 Retrofit.responseBodyConverter()
- 3.4.5 GsonConverterFactory.responseBodyConverter()
- 3.4.6 GsonResponseBodyConverter
- 3.5 HttpServiceMethod
- 3.6 OkHttpCall
- 3.7 RxJava2CallAdapter.adapt()
- 小结
- 4. Retrofit 执行网络请求
- 4.1 Observable.subscribe()
- 4.2 BodyObservable.subscribeActual()
- 4.3 CallObservable.subscribeActual()
- 4.4 OkHttpCall.execute()
- 4.4.1 RequestFactory.create()
- 4.4.2 OkHttpClient.newCall()
- 4.4.3 RealCall.newRealCall()
- 4.5 OkHttpCall.parseResponse()
- 4.5.1 GsonResponseBodyConverter.convert()
- 4.5.2 Gson.getAdapter()
- 4.5.3 ReflectiveTypeAdapterFactory.Adapter.read()
- 4.6 Response.success()
- 小结
- 总结
- 参考
概述
在 Android 开发中,通过网络请求获取服务端数据是一项基本且常见的需求。目前有多种网络请求框架可供选择,其中 Android-Async-Http、Volley、OkHttp 和 Retrofit 是较为流行的、开源的网络请求框架。如何选择它们?孰优孰劣?仁者见仁智者见智,我个人觉得适合的就是最好的,不要盲目跟风去更换掉之前选用的网络请求框架,毕竟老代码那是牵一发而动全身哈!对于新项目来说,选择一个好用的网络请求框架,还是很有必要的,而 Retrofit 作为当下最火的一个网络开源请求库,还是值得学习并尝试使用的。
一、Retrofit 简介
Retrofit 是一个在 Android 开发中常用的网络请求框架。是 Square 公司基于他们自己的另一个比较火的网络库 OkHttp,进行封装的一个 RESTful 的 HTTP 网络请求框架。其提供了简洁而强大的 API,用于与 RESTful 服务进行通信。
- App 应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作;
- 请求获取到服务端的响应后,OkHttp 将服务端返回的、原始的数据交给 Retrofit, Retrofit 再根据用户的需求对结果进行解析。
Retrofit 的一些主要特点和优势:
- 简单易用的 API:Retrofit 提供了简洁、直观的 API,使得定义和执行网络请求变得非常简单。通过定义接口,并使用注解来描述请求参数和响应数据,可以轻松地与 RESTful API 进行交互;
- 自动化网络请求处理:Retrofit 处理了大部分网络请求的细节,包括请求的构建、执行、响应的解析等,大大简化了网络请求的代码编写过程;
- 内置支持 RxJava:Retrofit 2.0 内置支持 RxJava,可以方便地将网络请求转换为 Observables 或 Singles,实现更加优雅的异步编程模式;
- 请求和响应的数据转换:Retrofit 支持多种数据格式的转换,包括:Gson、JSON、XML、Protobuf 等,可以方便地进行数据的序列化和反序列化;
- 灵活的请求配置:Retrofit 允许你配置全局的请求参数,包括:连接超时、读取超时、请求头、日志输出等,以满足不同场景下的需求;
- 强大的错误处理机制:Retrofit 提供了灵活的错误处理机制,可以根据不同的 HTTP 状态码和错误情况进行统一处理,使得应用程序在遇到错误时能够优雅地处理并给出相应的提示。
Retrofit 与其它主流网络请求库之间的功能与区别:
二、Retrofit 源码剖析
1. Retrofit 网络请求过程
结合上图,解释一下 Retrofit 网络请求过程:
- 通过解析网络请求接口的注解配置网络请求参数
- 通过动态代理生成网络请求对象
- 通过网络请求适配器将网络请求对象进行平台适配(包括:Android、RxJava、Guava 和 Java8)
- 通过网络请求执行器发送网络请求
- 通过数据转换器解析服务器返回的数据
- 通过回调执行器切换线程(子线程切到主线程)
- 用户在主线程处理并展示返回结果
本文不准备详细介绍 Retrofit 的使用,主要是深入源码剖析其原理,下面就根据上面的请求过程,逐步剖析 Retrofit 的源码调用过程,注意:后续的源码基于 Retrofit 2.5.0 版本进行分析。
2. Retrofit 实例构建
Retrofit 实例是使用建造者模式通过 Builder 类进行创建的:
OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new TokenHeaderInterceptor()) // 动态添加token .addInterceptor(new NullResponseInterceptor()) // 返回空字符的时候显示 .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS) .readTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(mBaseUrl) .client(client) // okhttp实例对象 .addConverterFactory(GsonConverterFactory.create()) // 添加转换器工厂 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 请求指定适配器 RxJava .build();
2.1 Retrofit.java
public final class Retrofit { // 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象) // 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等 private final Map responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter(gson, adapter); } @Override public Converter adapter = gson.getAdapter(TypeToken.get(type)); return new GsonRequestBodyConverter(gson, adapter); } }
GsonConverterFactory.creat() 方法中创建了一个含有 Gson 实例的 GsonConverterFactory 实例对象, 并返回给 Builder.addConverterFactory() 方法作为方法的入参将其放入到 converterFactories 集合中。
2.6 Retrofit.Builder.addCallAdapterFactory()
public final class Retrofit { public static final class Builder { ...... private final List callAdapterFactories = new ArrayList(); ...... // 添加网络请求 Call 的适配器工厂,以支持除 Call 以外的服务方法返回类型 public Builder addCallAdapterFactory(CallAdapter.Factory factory) { callAdapterFactories.add(checkNotNull(factory, "factory == null")); return this; } } }
Builder.addCallAdapterFactory() 方法为网络请求 Call 添加适配器工厂,以支持除 Call 以外的服务方法返回类型。本文以 RxJava2CallAdapterFactory 为例,调用 RxJava2CallAdapterFactory.create() 方法来创建实例对象。
2.6.1 RxJava2CallAdapterFactory.create()
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory { public static RxJava2CallAdapterFactory create() { // 继续调用 RxJava2CallAdapterFactory 有参构造方法,只是 Scheduler 传入为 null return new RxJava2CallAdapterFactory(null); } private final Scheduler scheduler; private RxJava2CallAdapterFactory(Scheduler scheduler) { this.scheduler = scheduler; } @Override public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) { Class rawType = getRawType(returnType); // 获取当前方法参数的具体类型 if (rawType == Completable.class) { // 返回类型是否是Completable类 // Completable 没有参数化(这是该方法的其余部分所处理的),因此只能用单个配置创建它 return new RxJava2CallAdapter(Void.class, scheduler, false, true, false, false, false, true); } // 由于本文是结合 RxJava 进行使用的,因此返回值类型是 Observable 类型的 boolean isFlowable = rawType == Flowable.class; // isFlowable 为 false boolean isSingle = rawType == Single.class; // isSingle 为 false boolean isMaybe = rawType == Maybe.class; // isMaybe 为 false if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) { return null; // 不是 Completable、Flowable、Single、Maybe 和 Observable 则返回 null } boolean isResult = false; boolean isBody = false; Type responseType; if (!(returnType instanceof ParameterizedType)) { // 非参数化类型 String name = isFlowable ? "Flowable" : isSingle ? "Single" : "Observable"; throw new IllegalStateException(name + " return type must be parameterized" + " as " + name + " or " + name + "