Retrofit2源码解析系列

  • Retrofit2源码解析(一)
  • Retrofit2源码解析——网络调用流程(上)

本文基于Retrofit2的2.4.0版本

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
复制代码

上次我们分析到网络请求是通过OkHttpCall类来完成的,下面我们就来分析下OkHttpCall类。

final class OkHttpCall<T> implements Call<T> {...@Overridepublic void enqueue(final Callback<T> callback) {checkNotNull(callback, "callback == null");okhttp3.Call call;Throwable failure;synchronized (this) {if (executed) throw new IllegalStateException("Already executed.");executed = true;call = rawCall;failure = creationFailure;if (call == null && failure == null) {try {//调用createRawCall创建OkHttp3的Callcall = rawCall = createRawCall();} catch (Throwable t) {throwIfFatal(t);failure = creationFailure = t;}}}...call.enqueue(new okhttp3.Callback() {@Overridepublic void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {Response<T> response;try {//解析返回的结果response = parseResponse(rawResponse);} catch (Throwable e) {callFailure(e);return;}try {callback.onResponse(OkHttpCall.this, response);} catch (Throwable t) {t.printStackTrace();}}@Overridepublic void onFailure(okhttp3.Call call, IOException e) {callFailure(e);}private void callFailure(Throwable e) {try {callback.onFailure(OkHttpCall.this, e);} catch (Throwable t) {t.printStackTrace();}}});}...
}
复制代码

OkHttpCall的enqueue方法主要干了2件事,一个是创建OkHttp3的Call用于执行网络请求;另一个是解析返回的结果并回调。下面我们来看看创建OkHttp3的Call的过程

//OkHttpCall.class
private okhttp3.Call createRawCall() throws IOException {okhttp3.Call call = serviceMethod.toCall(args);if (call == null) {throw new NullPointerException("Call.Factory returned null.");}return call;
}
复制代码

可以发现是通过serviceMethod的toCall方法来创建的

//ServiceMethod.class
okhttp3.Call toCall(@Nullable Object... args) throws IOException {RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,contentType, hasBody, isFormEncoded, isMultipart);...for (int p = 0; p < argumentCount; p++) {handlers[p].apply(requestBuilder, args[p]);}//最后调用OkHttpClient的newCall方法返回Callreturn callFactory.newCall(requestBuilder.build());
}
复制代码

ServiceMethod的toCall方法也是通过OkHttpClient的newCall方法来返回Call的。

在我们通过OkHttpClient请求得到结果后,我们还需要将返回的结果Response解析成我们接口需要的实体类型,这就需要用到我们在创建Retrofit时设置的ConverterFactory了,比如GsonConverterFactory。

//OkHttpCall.class
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();rawResponse = rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();...ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);try {//通过serviceMethod的toResponse方法解析T body = serviceMethod.toResponse(catchingBody);return Response.success(body, rawResponse);} catch (RuntimeException e) {catchingBody.throwIfCaught();throw e;}
}
复制代码

OkHttpCall的parseResponse方法调用的是serviceMethod的toResponse方法来解析返回的结果。

//ServiceMethod.class
R toResponse(ResponseBody body) throws IOException {return responseConverter.convert(body);
}
复制代码

在ServiceMethod中最后调用responseConverter的convert方法来转换返回的结果。这个responseConverter和上面分析的CallAdapter的确定过程一样,也是在ServiceMethod的build方法中,通过调用retrofit的requestBodyConverter方法遍历我们传入的ConverterFactory,直到找到合适的。

//Retrofit.class
public <T> Converter<T, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
}public <T> Converter<T, RequestBody> nextRequestBodyConverter(@Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations,Annotation[] methodAnnotations) {...int start = converterFactories.indexOf(skipPast) + 1;for (int i = start, count = converterFactories.size(); i < count; i++) {Converter.Factory factory = converterFactories.get(i);Converter<?, RequestBody> converter =factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);if (converter != null) {//noinspection uncheckedreturn (Converter<T, RequestBody>) converter;}}...
}
复制代码

需要注意的是在创建Retrofit时默认添加了一个BuiltInConverters,这个是Retrofit为我们提供一个默认的responseConverter,它主要处理的是返回类型是ResponseBody和Void的情况。

final class BuiltInConverters extends Converter.Factory {@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,Retrofit retrofit) {if (type == ResponseBody.class) {return Utils.isAnnotationPresent(annotations, Streaming.class)? StreamingResponseBodyConverter.INSTANCE: BufferingResponseBodyConverter.INSTANCE;}if (type == Void.class) {return VoidResponseBodyConverter.INSTANCE;}return null;}...
}
复制代码

因为我们一般返回值类型都是具体的实体类型,所以我们需要添加自己的responseConverter,一般也就是GsonConverterFactory了。

至此,网络调用的后半部分流程也清楚了:

我们调用Call对象的enqueue方法发起异步请求时,实际上调用的是OkHttpCall对应的enqueue方法。OkHttpCall会先调用ServiceMethod类的toCall方法利用OkHttpClient的newCall方法创建OkHttp3的call对象,然后利用这个call对象执行具体的网络请求。在网络请求返回成功以后会调用ServiceMethod类的toResponse方法利用我们设置的responseConverter将返回结果转换成我们需要的类型,然后通过我们设置的回调或是默认的回调方法,将结果回调回主线程,从而完成整个请求过程。

总结

Retrofit2的网络调用的整个流程我们已经分析完了。通过这次分析,我们可以看到Retrofit2中最主要的就是3个类:Retrofit、ServiceMethod和OkHttpCall。这三个类指责明确,相互配合共同完成整个网络调用的流程。

(1)Retrofit负责供外部初始化和定制,保存CallAdapter的列表和ResponseConverterFactory列表。

(2)ServiceMethod对应每一个接口方法的信息,包括解析注解和参数等,同时它也是连接Retrofit和OkHttpCall的桥梁。ServiceMethod中保存着当前接口对应方法所需要的CallAdapter和ResponseConverter。利用CallAdapter将OkHttpCall转换成接口需要的类型,供接口调用。利用toResponse方法让OkHttpCall调用ResponseConverter解析网络请求返回的结果。

(3)OkHttpCall则是用来执行具体网络请求。Retrofit2没有直接使用OkHttp3的Call接口,而是有自己的Call接口。在OkHttpCall内部通过组合的方法持有OkHttp3的Call接口,并通过ServiceMethod的toCall方法得到OkHttp3的call来进行网络请求,减少对OkHttp3的耦合。


                    欢迎关注我的微信公众号,和我一起每天进步一点点!
复制代码

Retrofit2源码解析——网络调用流程(下)相关推荐

  1. android 输入法如何启动流程_android输入法02:openwnn源码解析01—输入流程

    android 输入法 02:openwnn 源码解析 01-输入流程 之后要开始 android 日文输入法的测试,因此现在开始研究 android 输入法.之前两 篇文章已经对 android 自 ...

  2. Retrofit2源码解析

    一.前言: Retrofit: 一个 Restful 设计风格的 HTTP 网络请求框架的封装.基于 OkHttp 严格地说,Retrofit2并不是一个网络请求交易框架,它只是对网络请求框架的封装. ...

  3. Android四大组件之ContentProvider 全面解析,ContentResolver源码解析如何调用其它APP的ContentProvider

    今天来总结下Android中的ContentProvider(以下简称CP),具体代码请见https://github.com/Mangosir/ContentProviderReview/tree/ ...

  4. Glide源码解析-加载流程

    1 引言 一直想要阅读Glide源码,但是苦于时间和功力都不够,总是断断续续的,趁着现在有一些空暇时间,来简要分析Glide的源码.Glide的实现太过复杂,不可能做到面面俱到,如果每一行都细致分析, ...

  5. Retrofit2源码解析(一)

    本文基于Retrofit2的2.4.0版本 implementation 'com.squareup.retrofit2:retrofit:2.4.0' Retrofit2底层基于OkHttp3,是对 ...

  6. 【ceph】CEPH源码解析:读写流程

    相同过程 Ceph的读/写操作采用Primary-Replica模型,客户端只向Object所对应OSD set的Primary OSD发起读/写请求,这保证了数据的强一致性.当Primary OSD ...

  7. Ceph源码解析:读写流程

    一.OSD模块简介 1.1 消息封装:在OSD上发送和接收信息. cluster_messenger -与其它OSDs和monitors沟通 client_messenger -与客户端沟通 1.2 ...

  8. Retrofit2 源码解析

    Retrofit是什么 简单的说它是一个基于OkHttp的RESTFUL Api请求工具,从功能上来说和Google的Volley功能上很相似,但是使用上很不相似. Retrofit怎么用 比如你要请 ...

  9. 3.MyBatis源码解析-CRUD执行流程--阿呆中二

    CRUD执行流程 MyBatis CRUD执行流程 与我联系 MyBatis 本文是对mybatis 3.x源码深度解析与最佳实践学习的总结,包括XML文件解析流程.SqlSession构建流程.CR ...

最新文章

  1. 英国熊孩子频繁攻击学校网络,政府被逼爹味儿下场:当白帽黑客吧!年薪45万...
  2. Android-PullLayout
  3. axure没有团队页签_Axure教程:多页签可滚动的选项卡制作
  4. excel公式:定位单元格
  5. 成为Java流专家–第2部分:中级操作
  6. 书评:Mockito Essentials
  7. mongodb 系列 ~ mongo 用户验证系列
  8. Python 求解斐波那切(三种方法)
  9. 深入理解JVM之JVM内存区域与内存分配
  10. 大话机器学习之数据预处理与数据筛选
  11. datanode启动后闪退_网友吐槽12306 App:不同意获取个人信息就会“闪退”
  12. JavaScript入门到精通,需要掌握的技能盘点
  13. greensock插件下载_使用GreenSock插件轻松制作精美的Web动画
  14. MATLAB激活时填错Windows用户名怎么办?
  15. xlsx如何查找替换_Excel中如何使用通配符查找和替换
  16. python extractor_Python Extractor for Python Editor 1.2
  17. 2021年开始,Adobe Flash Player 不能用了?
  18. MacBook 安装固态硬盘
  19. 如何解决电脑使用中任务栏“卡死”问题。
  20. ​​【​观察】萨提亚为微软中国定下主基调 平台价值释放与生态伙伴共赢

热门文章

  1. java多线程意义_Java多线程学习之多线程的概念及意义
  2. 怎么用贝塞尔工具画圆_Win10恶意软件删除工具怎么用?这个方法都舍不得分享...
  3. emc文件存储服务器,emc存储怎么挂在linux服务器上
  4. C++ 虚函数和虚表
  5. pytorch简单框架
  6. channels2.X 学习笔记
  7. 深入探究Spark -- Cluster Manger部署(最常用为YARN实现Task Scheduler)
  8. .NET Framework 2.0 组件和非托管代码与交互操作详解(转)
  9. tomcat8 进入不了Manager App 界面 403 Access Denied
  10. 对于下一代互联网的畅想