Retrofit与RXJava整合

Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API。下面我用对比的方式来介绍 Retrofit 的 RxJava 版 API 和传统版本的区别。

以获取一个 User 对象的接口作为例子。使用Retrofit 的传统 API,你可以用这样的方式来定义请求:

@GET("/user")
public void getUser(@Query("userId") String userId, Callback<User> callback);

在程序的构建过程中, Retrofit 会把自动把方法实现并生成代码,然后开发者就可以利用下面的方法来获取特定用户并处理响应:

getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...}
};

而使用 RxJava 形式的 API,定义同样的请求是这样的:

@GET("/user")
public Observable<User> getUser(@Query("userId") String userId);

使用的时候是这样的:

getUser(userId).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});

看到区别了吗?

当 RxJava 形式的时候,Retrofit 把请求封装进 Observable ,在请求结束后调用 onNext() 或在请求失败后调用 onError()。

对比来看, Callback 形式和 Observable 形式长得不太一样,但本质都差不多,而且在细节上 Observable 形式似乎还比 Callback 形式要差点。那 Retrofit 为什么还要提供 RxJava 的支持呢?

因为它好用啊!从这个例子看不出来是因为这只是最简单的情况。而一旦情景复杂起来, Callback 形式马上就会开始让人头疼。比如:

假设这么一种情况:你的程序取到的 User 并不应该直接显示,而是需要先与数据库中的数据进行比对和修正后再显示。使用 Callback 方式大概可以这么写:

getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {processUser(user); // 尝试修正 User 数据userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...}
};

有问题吗?

很简便,但不要这样做。为什么?因为这样做会影响性能。数据库的操作很重,一次读写操作花费 10~20ms 是很常见的,这样的耗时很容易造成界面的卡顿。所以通常情况下,如果可以的话一定要避免在主线程中处理数据库。所以为了提升性能,这段代码可以优化一下:

getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {new Thread() {@Overridepublic void run() {processUser(user); // 尝试修正 User 数据runOnUiThread(new Runnable() { // 切回 UI 线程@Overridepublic void run() {userView.setUser(user);}});}).start();}@Overridepublic void failure(RetrofitError error) {// Error handling...}
};

性能问题解决,但……这代码实在是太乱了,迷之缩进啊!杂乱的代码往往不仅仅是美观问题,因为代码越乱往往就越难读懂,而如果项目中充斥着杂乱的代码,无疑会降低代码的可读性,造成团队开发效率的降低和出错率的升高。

这时候,如果用 RxJava 的形式,就好办多了。 RxJava 形式的代码是这样的:

getUser(userId).doOnNext(new Action1<User>() {@Overridepublic void call(User user) {processUser(user);}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});

其中

doOnNext()的执行在onNext()之前,对数据进行相关处理。doOnNext在哪一个线程处理,暂时不明。

参考链接

RxJava操作符doOnNext - 享受技术带来的快乐! - 博客频道 - CSDN.NET

Rxjava中的doOnNext的作用和在哪里执行 - u010746364的博客 - 博客频道 - CSDN.NET

后台代码和前台代码全都写在一条链中,明显清晰了很多。

再举一个例子:假设 /user 接口并不能直接访问,而需要填入一个在线获取的 token ,代码应该怎么写?

Callback 方式,可以使用嵌套的 Callback:

@GET("/token")
public void getToken(Callback<String> callback);@GET("/user")
public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);...getToken(new Callback<String>() {@Overridepublic void success(String token) {getUser(token, userId, new Callback<User>() {@Overridepublic void success(User user) {userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...}};}@Overridepublic void failure(RetrofitError error) {// Error handling...}
});

倒是没有什么性能问题,可是迷之缩进毁一生,你懂我也懂,做过大项目的人应该更懂。

而使用 RxJava 的话,代码是这样的:

@GET("/token")
public Observable<String> getToken();@GET("/user")
public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);...getToken().flatMap(new Func1<String, Observable<User>>() {@Overridepublic Observable<User> onNext(String token) {return getUser(token, userId);}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});

用一个 flatMap() 就搞定了逻辑,依然是一条链。看着就很爽,是吧?

RxJava配合Retrofit2.0使用

新的Retrofit2.0简直就是设计模式的教科书典范,同时对Rx的支持也更加友好,本例子为查询ip获取地理信息,并过滤掉失败信息

//使用Rxjava配合Retrofit解析json数据,注意这里全是电脑运行的,没有分开线程订阅
public static void main(String[] args) throws Exception{
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new LoggingInterceptor());//log for okhttpRetrofit retrofit = new Retrofit.Builder().baseUrl(IPService.END).client(client).addConverterFactory(GsonConverterFactory.create())//对Response进行adapter转换.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//对转换后的数据进行再包装.build();retrofit.create(IPService.class)//动态代理生成class//直接操作json数据,这里可不是一个好的习惯,真正应该是DTO对象的.getIPInfo("58.19.239.11").filter(jsonObject -> jsonObject.get("code").getAsInt()==0)//转换数据类型.map(jsonObject1 -> jsonObject1.get("data"))//输出结果.subscribe(System.out::println);
}//retrofit定义的接口
interface IPService {String END = "http://ip.taobao.com";//建议写成dto对象,博主只是为了演示filter就把这里JsonObject了@GET("/service/getIpInfo.php") Observable<JsonObject> getIPInfo(@Query("ip") String ip);
}/**
* Retrofit2.0已经把网络部分剥离了,所以需要自己实现Log
*/
static class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {Request request = chain.request();long t1 = System.nanoTime();System.out.println(String.format("Sending request %s on %s%n%s", request.url(), chain.connection(),request.headers()));Response response = chain.proceed(request);long t2 = System.nanoTime();System.out.println(String.format("Received response for %s in %.1fms%n%s", response.request().url(),(t2 - t1) / 1e6d, response.headers()));return response;
}

源代码

rengwuxian RxJava Samples

参考链接

给 Android 开发者的 RxJava 详解

函数式编程RxJava操作实例 - 简书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

消除疑虑

这要从何说起?有时候我们觉得我们自已很强大,可以学会很多东西,可以做很多事情.无论从逻辑还是环境去考虑,都有可行性. 但是:"我们心中有疑虑" 这不是我们不够自信,而是还没有完全的把握可以战胜敌人,当然这个敌人是假想敌,或者说阻碍我们前进的东西.又或者我们感觉…

autotools入门笔记(一)

GNU autotools作用&#xff1a;收集系统配置信息并自动生成Makefile文件。 GNU autotools主要包括三个工具&#xff1a;autoconf、automake、libtool&#xff0c;还有很多辅助的工具&#xff0c;包括&#xff1a;autoheader、aclocal、autoscan。 ● autoscan检测源文件生成con…

本田、大众宣布智能路口研究新进展 以安全为重点

编译&#xff1a;网易智能摘要&#xff1a;每年&#xff0c;在十字路口发生的交通事故约占交通事故死亡人数的20%&#xff0c;这就是为什么汽车制造商和供应商都下定决心要创造出智能的十字路口&#xff0c;利用尖端技术来减少&#xff08;或者最好是能够避免&#xff09;在十字…

Volley学习总结

本文主要包括以下内容 volly基本操作(String与Json类型) volly图片操作 自定义volly volly源码分析 Volley简单易用&#xff0c;在性能方面也进行了大幅度的调整&#xff0c;它的设计目标就是非常适合去进行数据量不大&#xff0c;但通信频繁的网络操作&#xff0c;而对于大…

vimtutor

在shell命令行下输入vimtutor将出现本教程。 欢 迎 阅 读 《 V I M 教 程 》 —— 版本 1.5 vim 是一个具有很多命令的功能非常强大的编辑器。限于篇幅&#xff0c;在本教程当中 就不详细介绍了。本教程的设计目标是讲述一些必要…

智能连接:5G、AI和IoT的组合如何改变美洲

来源&#xff1a;199IT互联网数据中心摘要&#xff1a;GSMA发布了新报告“智能连接&#xff1a;5G、AI和IoT的组合如何改变美洲”&#xff0c;强调了该地区如何从这些科技中受益。GSMA Intelligence预测&#xff0c;到2025年全球5G连接数量将达到13亿&#xff0c;覆盖全球40%的…

刚刚,生物学横扫诺贝尔3大奖,两名女性获奖!化学奖授予试管中的“进化论”...

来源&#xff1a;Deeptech深科技北京时间 10 月 3 日下午 5 点 45 分&#xff0c;2018 诺贝尔化学奖揭晓——诺贝尔委员会宣布&#xff0c;将此奖项一半颁给女科学家Frances H. Arnold&#xff0c;另一半则由George P. Smith、 Gregory P. Winter两人共享。此次诺贝尔化学奖表彰…

MACIOS Socket编程

转自 https://github.com/kejinlu/objc-doc/blob/master/Socket%E7%BC%96%E7%A8%8B.md 大纲 一.Socket简介二.BSD Socket编程准备 1.地址2.端口3.网络字节序4.半相关与全相关5.网络编程模型三.socket接口编程示例四.使用select五.使用kqueue六.使用流注:文档中设计涉及的代码也…

Android缓存学习入门

本文主要包括以下内容 利用LruCache实现内存缓存 利用DiskLruCache实现磁盘缓存 LruCache与DiskLruCache结合实例 利用了缓存机制的瀑布流实例 内存缓存的实现 public class PhotoWallAdapter extends ArrayAdapter<String> implements OnScrollListener {/*** 记录…

2018年人工智能之自动驾驶研究报告

来源&#xff1a;AMiner未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#xff1b;开展互联网&#xf…

MyEclipse+Tomcat 启动时出现 configuration error occured during startup错误的解决方法

配置好Tomcat server&#xff0c;启动Tomcat&#xff0c;报如下错误&#xff1a; 解决方法如下&#xff1a; 选中Tomcat 6中的JDK一项&#xff0c;这里要特别注意&#xff0c;默认的是JRE的运行环境&#xff0c;这里要设定成JDK的&#xff0c;否则&#xff0c;MyEclipse无法正常…

硅谷首场AI硬件峰会干货报告:AI芯片井喷期即将到来

来源&#xff1a;智东西摘要&#xff1a;英特尔和英伟达对AI芯片的角逐&#xff0c;AI芯片行业的创业者机会。AI芯片不仅是未来十年半导体行业中最有希望的增长机会之一&#xff0c;而且还是有可能破坏传统计算市场的力量。现今 99&#xff05;的AI软件尚未编写&#xff0c;只有…

揭开神秘的“记忆”面纱!

来源&#xff1a;生物谷摘要&#xff1a;大脑记忆&#xff0c;对于我们每个人来说都是一种非常神奇的经历&#xff0c;近些年来&#xff0c;科学家们通过大量研究揭开了大脑记忆的奥秘&#xff0c;本文中&#xff0c;小编就对相关研究进行整理&#xff0c;分享给大家&#xff0…

数据结构之AVL树

AVL树是高度平衡的而二叉树。它的特点是&#xff1a;AVL树中任何节点的两个子树的高度最大差别为1。 旋转 如果在AVL树中进行插入或删除节点后&#xff0c;可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态&#xff1a;LL(左左)&#xff0c;LR(左右)&#xff0c;RR(右…

Javascript实现重力弹跳拖拽运动效果

声明&#xff1a; By&#xff1a;GenialX 个人主页&#xff1a;胡旭博客 - www.ihuxu.com QQ&#xff1a;2252065614 演示地址&#xff1a; http://www.ihuxu.com/project/gcdmove/ 调用示例&#xff1a; var GCDM gcdMove(oDiv,100,0); GCDM.startMove();//开始运动 GCDM.sto…

语义分割领域开山之作:Google提出用神经网络搜索实现语义分割

来源&#xff1a; AI科技评论1. Introduction在 arxiv 浏览论文的时候&#xff0c;单独看文章名不知道属于 CV 哪个领域&#xff0c;怀着对一作 Liang-Chieh 敬畏的心&#xff0c;在摘要中扫描到 PASCAL VOC 2012 (semantic image segmentation)&#xff0c;浏览全文才明白&…

美国发布《评估和强化制造与国防工业基础及供应链弹性》报告

来源&#xff1a;蓝海星智库10月5日&#xff0c;美国发布《评估和强化制造与国防工业基础及供应链弹性》非密版报告&#xff0c;这是特朗普第13806号行政令要求的&#xff0c;由国防部工业政策办公室领导&#xff0c;商务部、劳工部、能源部和国土安全部等多个政府部门参与&…

UVa10006-Carmichael Numbers

http://uva.onlinejudge.org/index.php?optioncom_onlinejudge&Itemid8&pageshow_problem&problem947 快速幂取模 code: #include <iostream> #include <cstring> #include <cmath> using namespace std; typedef long long LL; LL pow_mod(LL …

Android缓存学习入门(二)

本文主要包括以下内容 内存缓存策略 文件缓存策略 内存缓存策略 当有一个图片要去从网络下载的时候&#xff0c;我们并不会直接去从网络下载&#xff0c;因为在这个时代&#xff0c;用户的流量是宝贵的&#xff0c;耗流量的应用是不会得到用户的青睐的。那我们该怎么办呢&…

本届诺奖得主“牛”在哪儿?专业数据分析给出论文干货

来源&#xff1a;科技日报摘要&#xff1a;北京时间10月2日下午5时52分&#xff0c;2018年诺贝尔物理学奖揭晓。获奖者为美国科学家阿瑟阿什金&#xff08;Arthur Ashkin&#xff09;、法国科学家热拉尔穆鲁&#xff08;Gerard Mourou&#xff09;和加拿大科学家唐娜斯特里克兰…