第二篇:Retrofit调用流程图和使用到的设计模式
2016-05-08 09:35:58
这篇文章解析一下Retrofit的调用流程
1. 先看一下我们是如何使用Retrofit的,代码如下:
public interface WeatherDataService {
@GET("/wtr-v2/temp/realtime")
Call<MiWeatherData> getMiWeather(@Query("cityId") String cityId);
@GET("/wtr-v2/temp/realtime")
Observable<MiWeatherData> getMiWeatherObservable(@Query("cityId") String cityId);
@GET("/wtr-v2/temp/realtime")
MiWeatherData getMiWeatherCustomCallAdapter(@Query("cityId") String cityId);
}
这是获取天气信息的三个请求方法,区别在于返回值不同。下面代码展示了getWeather()是如何调用的,返回值类型时标准的Call<T>:
private void getWeather() {
retrofit = new Retrofit.Builder()
.baseUrl("http://weatherapi.market.xiaomi.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.build(); (1)
service = retrofit.create(WeatherDataService.class); (2)
Call<MiWeatherData> result = service.getMiWeather("101010100"); (3)
try {
Response<MiWeatherData> r = result.execute(); (4)
MiWeatherData data = r.body(); (5)
Log.e("David", "ResponseBody data = " + data);
if (data != null) {
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.SD);
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.cityid);
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.WS);
}
} catch (IOException e) {
e.printStackTrace();
}
}
(1)构建Retrofit对象,因为返回值是json串,所以用GsonConverter,使用默认的CallAdapter,也就是说返回值是Call<T>;
(2)使用动态代理创建我们自己定义的WeatherDataService接口实例;
(3)调用接口中真正获取天气信息的方法,返回值是Call<T>;
(4)调用Call<T>的execute()方法,真正执行网络请求,前面的UML途中提到过,还有一个enqueue()方法,两方法的区别是:execute()是同步且在主线程,enqueue()是异步且在工作线程,这里的工作线程不是我们设置的callbackExecutor,而是有okhttp3来控制的;
(5)由于getWeather()方法返回的是Response<T>,body()方法取到真正的MiWeatherData对象,Gson已经将json转换为Object;
2. 调用流程解析
其实整个调用流程最关键的就是上面提到的5个点,我们顺着这5个点来探究一下Retrofit是怎么调用的。
第一步就不用多说了,构建Retrofit对象,参数的作用上一篇文章已经做过分析了。
第二、三步很重要,我们看一下create()方法:

从(1)可以发现,确实是使用了动态代理,返回值就是我们自定义的接口实例对象T。由于T的所有方法都是抽象方法,当调用T的方法时,会被InvocationHandler拦截,真正的调用会转到InvocationHandler的invoke()方法中,其中method参数就是我们自己的抽象方法。
(2)处代码基于我们自己的method构造了一个ServiceMethod,构建过程中对方法中的各种注解做了解析,作用前面讲过了。又创建了一个OkHttpCall对象,这个对象将会在被adapt之后返回给客户端,类型取决于客户端的方法返回类型和设置的CallAdapter。这里的代码其实不是很好,耦合性太高,其实本意只是将OkHttpCall转换成客户端需要的返回值,那么CallAdapter对象是否有必要放在ServiceMethod,可以再仔细斟酌一下。
第四步execute网络请求,看一下源码:

1处代码创建一个真正的网络请求okhttp3.Call对象,源码如下:

首先调用了ServiceMethod的toRequest方法得到Request,里面包含了请求类型、请求参数等。然后调用了ServiceMethod的callFactory的newCall方法,这里的CallFactory是Retrofit.Builder的callFactory()设置的参数,默认使用OkHttpClient,我们也可以定义自己的网络请求类,只需要实现okhttp3的Call接口即可。因此默认使用的最终的网络请求类其实是okhttp3.RealCall。
2处代码执行真正的网络请求,绕了这么一大圈,终于进入正题了,同时对返回值做了解析。

其中调用了ServiceMethod的toResponse()方法,源码:

这里真正使用了我们设置的Converter,返回客户端需要类型的返回值。
3. 最终的流程图

作者在Retrofit的构建中使用了不少的设计模式,达到了耦合性低、扩展性强、灵活性高的目的。
第二篇:Retrofit调用流程图和使用到的设计模式的更多相关文章
- #PHP#微信支付 第二篇 JSAPI 调用统一下单接口获取预支付交易数据
上一篇讲到成功获取 openid,本篇要调用微信统一接口创建预支付交易单,并获取到相关数据,以便(后边)在微信内调起H5支付 第三步,调用微信统一下单接口创建预支付交易单 微信统一下单API是微信支付 ...
- 微信支付 第三篇 微信调用H5页面进行支付
上一篇讲到拿到了 预支付交易标识 wx251xxxxxxxxxxxxxxxxxxxxxxxxxxxxx078700 第四步,是时候微信内H5调起支付了! 先准备网页端接口请求参数列表 微信文档中已经明 ...
- [置顶] android利用jni调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so
0:前言 1:本文主要作为丙方android公司的身份来写 2:作者有不对的地方,请指出,谢谢 [第一篇:android利用jni调用第三方库——编写库libhello.so] [第二篇:androi ...
- javascript立即调用的函数表达式N种写法(第二篇)
原文:javascript立即调用的函数表达式N种写法(第二篇) 上一篇博客我谈到将函数声明转换为函数表达式最常见的一种写法是:通过括号()将匿名函数声明转换为函数表达式即(function(){}) ...
- ETL第二篇 调用webservice
ETL第一篇(Kettle Spoon) 初遇 ETL第二篇 调用webservice 前言 这里使用ETL [Java代码] 实现 代码中使用axis调用webservice 在ETL提供了 Pro ...
- android调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so (转载)
转自:http://blog.csdn.net/jiuyueguang/article/details/9449737 版权声明:本文为博主原创文章,未经博主允许不得转载. 0:前言 1:本文主要作为 ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- 深入理解javascript对象系列第二篇——属性操作
× 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...
- [转]Android开源项目第二篇——工具库篇
本文为那些不错的Android开源项目第二篇--开发工具库篇,主要介绍常用的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多 ...
随机推荐
- dev LayoutControl布局控件
标题长短不一致,很难看 设置LayoutControl属性 效果: 修改字体: 控件字体: LayoutControl→Appearance→Control→Font→FontSize (Contr ...
- Xcode 7免证书真机调试
在Xcode 7中,苹果改变了自己在许可权限上的策略,此前Xcode只开放给注册开发者下载,但Xcode 7改变了这种惯有的做法,无需注册开发者账号,仅使用普通的Apple ID就能下载和上手体验.此 ...
- SQL Server优化常用SQL语句
--所有没有主键的表 select name from sysobjects where xtype='U' and id not in ( select i.parent_obj from syso ...
- Mac系统下显示和隐藏文件
在配置Maven的时候需要更改.m2文件,所以要将.m2显示出来,记录一下方便日后使用. 显示文件:在终端输入defaults write com.apple.finder AppleShowAllF ...
- c++共享内存(转载)
对于连个不同的进程之间的通信,共享内存是一种比较好的方式,一个进程把数据发送到共享内存中, 另一个进程可以读取改数据,简单记录一下代码 #define BUF_SIZE 256 TCHAR szNam ...
- About 滚存
滚存这个神奇的东西就比如DP现在这个状态是上一个状态转移过来的,但也只与上一个状态有关,所以就可以把原本的f[10000,10000]开成f[2,10000],就不会炸内存了.
- Sublime Text 配置记录
sublime userSetting sublime theme sublime plug sublime userSetting 对sublime的配置 { "color_scheme& ...
- 使用Angularjs的ng-cloak指令避免页面乱码
在使用Anguarjs进行web开发或者进行SPA(single page application)开发时,往往会遇到下面这样的问题. 刷新页面时,页面会出现一些乱码,这里的乱码具体是指`{{expr ...
- springmvc 解决跨域CORS
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import ja ...
- JQuery_事件基础
JavaScript 有一个非常重要的功能,就是事件驱动.当页面完全加载后,用户通过鼠标或键盘触发页面中绑定事件的元素即可触发. jQuery 为开发者更有效率的编写事件行为, 封装了大量有益的事件方 ...