框架源码 — 可能会有趣一点地简析学习 Retrofit
2016-09-18 08:41
218 查看
2016-09-13 谢三弟
鸿洋
鸿洋
鸿洋微信号
hongyangAndroid
功能介绍
你好,欢迎关注鸿洋的公众号,每天为您推送高质量文章,让你每天都能涨知识。点击历史消息,查看所有已推送的文章,喜欢可以置顶本公众号。此外,本公众号支持投稿,如果你有原创的文章,希望通过本公众号发布,欢迎投稿。
本文由谢三弟投稿。
谢三弟的博客地址:
http://imxie.cc/archives/
源码分析这种事,很多时候最好自己亲自去体验,不仅能帮助理解整体代码,可能还会有一些细节上的收获。
1
* define how requests are made. Create instances using {@linkplain Builder
* the builder} and pass your interface to {@link #create} to generate an implementation.
Retrofit 利用方法上的注解将接口转化成一个 HTTP 请求。
简单知道是什么了之后,我们对此提出疑问:
如何将接口转换为网络请求?
谁去进行网络请求?
接下来我们将从 Retrofit 的使用作为入口分析。
2
简单的使用就是这样的流程。现在我们开始层层剖析。
创建 Retrofit 的实例,进行一些配置,这里我们不用多说。但是有一个参数必须得讲讲。
Platform
在构建 Retrofit 的时候,会对当前使用平台进行判断,Java8,Android,iOS。
我们看看 Android 平台的代码:
从代码中我们得知两点:
在 Android 里我们默认使用的 CallAdapter 是 ExecutorCallAdapterFactory() 它会返回的是 Call.class。关于 ExecutorCallAdapterFactory() 我们稍后再说,你先知道这是 Android 默认 CallAdapter 就好。
默认的 Callback 是在主线程。
我在源码里写好了注释:
切合我们实际运用来看看顺序:
GankApi gankApi = retrofit.create(GankApi.class);
return (T) Proxy.newProxyInstance(...){...}
Call<Android> call = gankApi.getAndroid(1);
public Object invoke(...){...} 调用代理类的invoke()。
直到这里我们已经宏观地了解 Retrofit 是怎样的一个流程。
达成 初窥门径 成就。
千万别骄傲,为了以后走的更远更稳,我们得好好筑基,上面我们用到的是动态代理,强烈建议认真阅读两篇文章。
Retrofit2源码分析[动态代理](http://www.jianshu.com/p/a56c61da55dd)
Java静态代理和动态代理(http://blog.csdn.net/giserstone/article/details/17199755)
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
我们发现主要的方法是 new ServiceMethod.Builder(this, method).build(); ,所以接下来我们深入看看如何 解析注解 以及 构建请求方法 。
初始化一些参数
build()
这里的源码很长,做了很多异常处理,我截取重点来分析下。
一个是用来发送请求的 client ,一个是结果的转换器(Gson,FastJson …)之类,后面我们再讲这个。
上层配置就是当我们调用 Retrofit 的 addConverterFactory()和 addCallAdapterFactory(),内部会自动使用我们定义的组件。
在这里可以看到遍历我们使用方法的注解,并且解析他们。parseMethodAnnotation() 内部就是解析好 HTTP 的请求方式。
为了篇幅大小,可以在 源码 里看看具体的操作。
同时也可以看看 http 包下注解用到的接口,你会发现 @Retention(RUNTIME) 所以,从这里我们就可以明白,Retrofit 是在在运行期通过反射访问到这些注解的。
return Call
请求方法参数,请求客户端,返回值转换,我们都定义好了之后,便完成最后一步,构建好适合请求客户端的请求方法,Retrofit 默认的是 okhttpCall 。
最后将 call 返回给上层,用户调用方法进行请求。
总结
ServiceMethod 类开头注释已经很清楚的说明了作用,将接口方法改变成一个 HTTP call 。它对于 Retrofit 是很重要的存在,整个枪支内部都是由它来支撑起来。
在构建 ServiceMethod 对象的时候,有三个方法可以单独说说
build() 中 createCallAdapter() —-> retrofit.callAdapter()
解析接口方法内注解时parseParameterAnnotation()调用到的retrofit.requestBodyConverter()
build() 中 createResponseConverter() —-> retrofit.responseBodyConverter()
callAdapter()
最终会调用到 nextCallAdapter() 该方法主要是从 callAdapterFactories 中获取新的 CallAdapter,它会跳过 skipPast,以及 skipPast 之前的 Factory,然后找到与 returnType 和 annotations 都匹配的 CallAdapterFactory 。
requestBodyConverter() & responseBodyConverter()
最终会调用到 nextRequestBodyConverter()/nextResponseBodyConverter利用 converterFactories 创建一个与 RequestBody/ResponseBody 对应的 Converter 对象。
所以在这里我们就可以装填我们需要的子弹类型了。
3实战
进入实战,为我们的 Retrofit 添加 RxJava 和 Gson。
Rxjava:
adapter-rxjava 我们重点看 RxJavaCallAdapterFactory 即可,它是实现了 CallAdapter.Factory 并在对应方法里将 Call 包装成 Observable.class 返回。
然后给 Retrofit 对象加上 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()),这样我们才可以优雅的使用 Retrofit + RxJava 。
Gson:
我相信通过类名我们就可以知道每个类是用来做什么的,我在这里太过深入到具体实现反而一叶障目,
如果我们需要自定义数据转换格式,也是同样这样做。
继承 Converter.Factory 类作为适配类,同时创建两个实现 Converter 的类包装请求和响应的数据形式。
还记得我工具箱里我们提到的 ExecutorCallbackCall 吗?
这里的 Call 是对应我们选择的 call ,而此时是默认的 ExecutorCallbackCall 。如果还要问我为什么,请去看看 工具箱:Retrofit.Builder() 里 Android 平台的源码。
这里的 delegate 对应的就是 okhttp 的 call ,不禁有疑问了,这里调用的是异步请求,但是我们的回调是怎么回到主线程的呢?
带着疑问我们来看看。
首先回调是在 callbackExecutor.execute() 我们从这里入手。
我们发现在 Retrofit 的 build() 方法里:
平台默认的回调调度器,连忙回到工具箱看看:
我们发现,Android 默认的调度器是主线程的 Handler ,execute()方法也只是 mainHandler.post()。
所以这下就可以解决我们的疑问了。
这段代码我们就可以改写为:
如果看到这,还不理解为什么那就得好好补补 handler 的知识啦!
我这里推荐 melo 写的这篇,风趣易懂 带着这篇去通关所有Handler的提问(http://www.jianshu.com/p/fad4e2ae32f5) 。
最后放上两张开源社区画的流程图,我觉得特别清晰:
以上。〃´∀`)
鸿洋
鸿洋
鸿洋微信号
hongyangAndroid
功能介绍
你好,欢迎关注鸿洋的公众号,每天为您推送高质量文章,让你每天都能涨知识。点击历史消息,查看所有已推送的文章,喜欢可以置顶本公众号。此外,本公众号支持投稿,如果你有原创的文章,希望通过本公众号发布,欢迎投稿。
本文由谢三弟投稿。
谢三弟的博客地址:
http://imxie.cc/archives/
源码分析这种事,很多时候最好自己亲自去体验,不仅能帮助理解整体代码,可能还会有一些细节上的收获。
1
Retrofit 简介
Retrofit 源码开头的解释
* Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to* define how requests are made. Create instances using {@linkplain Builder
* the builder} and pass your interface to {@link #create} to generate an implementation.
Retrofit 利用方法上的注解将接口转化成一个 HTTP 请求。
简单知道是什么了之后,我们对此提出疑问:
如何将接口转换为网络请求?
谁去进行网络请求?
接下来我们将从 Retrofit 的使用作为入口分析。
2
Retrofit 分析
具体使用
首先建立 API 接口类:简单的使用就是这样的流程。现在我们开始层层剖析。
工具箱:Retrofit.Builder()
创建 Retrofit 的实例,进行一些配置,这里我们不用多说。但是有一个参数必须得讲讲。
Platform
在构建 Retrofit 的时候,会对当前使用平台进行判断,Java8,Android,iOS。
我们看看 Android 平台的代码:
从代码中我们得知两点:
在 Android 里我们默认使用的 CallAdapter 是 ExecutorCallAdapterFactory() 它会返回的是 Call.class。关于 ExecutorCallAdapterFactory() 我们稍后再说,你先知道这是 Android 默认 CallAdapter 就好。
默认的 Callback 是在主线程。
外壳:Create()
// 生成接口实现类 GankApi gankApi = retrofit.create(GankApi.class);
我在源码里写好了注释:
切合我们实际运用来看看顺序:
GankApi gankApi = retrofit.create(GankApi.class);
return (T) Proxy.newProxyInstance(...){...}
Call<Android> call = gankApi.getAndroid(1);
public Object invoke(...){...} 调用代理类的invoke()。
直到这里我们已经宏观地了解 Retrofit 是怎样的一个流程。
达成 初窥门径 成就。
千万别骄傲,为了以后走的更远更稳,我们得好好筑基,上面我们用到的是动态代理,强烈建议认真阅读两篇文章。
Retrofit2源码分析[动态代理](http://www.jianshu.com/p/a56c61da55dd)
Java静态代理和动态代理(http://blog.csdn.net/giserstone/article/details/17199755)
结构:ServiceMethod
Retrofit 有一个双链表用来缓存方法private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
我们发现主要的方法是 new ServiceMethod.Builder(this, method).build(); ,所以接下来我们深入看看如何 解析注解 以及 构建请求方法 。
初始化一些参数
build()
这里的源码很长,做了很多异常处理,我截取重点来分析下。
callAdapter = createCallAdapter(); responseConverter = createResponseConverter();
一个是用来发送请求的 client ,一个是结果的转换器(Gson,FastJson …)之类,后面我们再讲这个。
上层配置就是当我们调用 Retrofit 的 addConverterFactory()和 addCallAdapterFactory(),内部会自动使用我们定义的组件。
for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); }
在这里可以看到遍历我们使用方法的注解,并且解析他们。parseMethodAnnotation() 内部就是解析好 HTTP 的请求方式。
为了篇幅大小,可以在 源码 里看看具体的操作。
同时也可以看看 http 包下注解用到的接口,你会发现 @Retention(RUNTIME) 所以,从这里我们就可以明白,Retrofit 是在在运行期通过反射访问到这些注解的。
return Call
请求方法参数,请求客户端,返回值转换,我们都定义好了之后,便完成最后一步,构建好适合请求客户端的请求方法,Retrofit 默认的是 okhttpCall 。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);
最后将 call 返回给上层,用户调用方法进行请求。
总结
/** Adapts an invocation of an interface method into an HTTP call. */
ServiceMethod 类开头注释已经很清楚的说明了作用,将接口方法改变成一个 HTTP call 。它对于 Retrofit 是很重要的存在,整个枪支内部都是由它来支撑起来。
子弹:xxxFactory()
Retrofit 给我们最大的便利就是自身框架优雅的设计,只需要很小的改动,便可以优雅的适应不同的需求。所以很需要我们再补充点额外知识,了解什么是适配器模式(http://blog.csdn.net/zhangjg_blog/article/details/18735243),然后回到这里看看 Retrofit 是如何应用的。在构建 ServiceMethod 对象的时候,有三个方法可以单独说说
build() 中 createCallAdapter() —-> retrofit.callAdapter()
解析接口方法内注解时parseParameterAnnotation()调用到的retrofit.requestBodyConverter()
build() 中 createResponseConverter() —-> retrofit.responseBodyConverter()
callAdapter()
最终会调用到 nextCallAdapter() 该方法主要是从 callAdapterFactories 中获取新的 CallAdapter,它会跳过 skipPast,以及 skipPast 之前的 Factory,然后找到与 returnType 和 annotations 都匹配的 CallAdapterFactory 。
requestBodyConverter() & responseBodyConverter()
最终会调用到 nextRequestBodyConverter()/nextResponseBodyConverter利用 converterFactories 创建一个与 RequestBody/ResponseBody 对应的 Converter 对象。
所以在这里我们就可以装填我们需要的子弹类型了。
3实战
进入实战,为我们的 Retrofit 添加 RxJava 和 Gson。
Rxjava:
adapter-rxjava 我们重点看 RxJavaCallAdapterFactory 即可,它是实现了 CallAdapter.Factory 并在对应方法里将 Call 包装成 Observable.class 返回。
然后给 Retrofit 对象加上 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()),这样我们才可以优雅的使用 Retrofit + RxJava 。
Gson:
我相信通过类名我们就可以知道每个类是用来做什么的,我在这里太过深入到具体实现反而一叶障目,
如果我们需要自定义数据转换格式,也是同样这样做。
继承 Converter.Factory 类作为适配类,同时创建两个实现 Converter 的类包装请求和响应的数据形式。
开枪打靶: Call.enqueue()
注意:我这里只列举一个默认状态下的情况还记得我工具箱里我们提到的 ExecutorCallbackCall 吗?
这里的 Call 是对应我们选择的 call ,而此时是默认的 ExecutorCallbackCall 。如果还要问我为什么,请去看看 工具箱:Retrofit.Builder() 里 Android 平台的源码。
这里的 delegate 对应的就是 okhttp 的 call ,不禁有疑问了,这里调用的是异步请求,但是我们的回调是怎么回到主线程的呢?
带着疑问我们来看看。
首先回调是在 callbackExecutor.execute() 我们从这里入手。
我们发现在 Retrofit 的 build() 方法里:
Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); }
平台默认的回调调度器,连忙回到工具箱看看:
我们发现,Android 默认的调度器是主线程的 Handler ,execute()方法也只是 mainHandler.post()。
所以这下就可以解决我们的疑问了。
这段代码我们就可以改写为:
如果看到这,还不理解为什么那就得好好补补 handler 的知识啦!
我这里推荐 melo 写的这篇,风趣易懂 带着这篇去通关所有Handler的提问(http://www.jianshu.com/p/fad4e2ae32f5) 。
最后放上两张开源社区画的流程图,我觉得特别清晰:
以上。〃´∀`)
相关文章推荐
- Android源码学习之六——ActivityManager框架解析
- 开源搜索框架Lucene学习之分词器(3)——通过分词器源码学习抽象方法与虚方法的区别
- android开发——框架理解及源码学习计划
- android网络框架retrofit源码解析二
- android网络框架retrofit源码解析一
- 一点有趣的思考---来自ado.net学习过程
- 2014-11-6Android学习------SurfaceView的框架源码
- 腾讯前端框架学习一点心得
- yii框架源码阅读学习点滴
- Redis源码学习之【网络通信框架】
- 开源搜索框架Lucene学习之分词器(4)——通过分词器源码学习装饰者模式
- Android源码学习——ActivityManager框架解析
- Surf算法学习心得(二)——源码简析
- Android再学习-->源码框架
- Tomcat6.0源码学习--启动框架
- Android源码学习之六——ActivityManager框架解析
- Android源码学习之六——ActivityManager框架解析
- Redis源码学习之【网络通信框架】
- android网络框架retrofit源码解析四
- Surf算法学习心得(二)——源码简析