浅谈 RxAndroid + Retrofit + Databinding
http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0131/3930.html
最近 RxAndroid 、MVP、MVVM 一直是 Android 程序猿茶余饭后的谈资,于是我也抱着凑热闹的态度试试了试水。这里就谈谈试水后的感受
什么是 RxAndroid ?
要说什么是 RxAndroid ,得从 RxJava 说起。RxJava 在 GitHub 主页上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。
RxJava 的本质可以压缩为异步这一个词。说到根上,它就是一个实现异步操作的库,而别的定语都是基于这之上的。
而RxAndroid是RxJava的一个针对Android平台的扩展,主要用于 Android 开发。
什么是 Retrofit ?
Retrofit 是一套 RESTful 架构的 Android(Java) 客户端实现,基于注解,提供 JSON to POJO(Plain Ordinary Java Object ,简单 Java 对象),POJO to JSON,网络请求(POST,GET, PUT,DELETE 等)封装。
既然只是一个网络请求封装库,现在已经有了那么多的大家已经耳熟能详的网络请求封装库了,为什么还要介绍它呢,原因在于 Retrofit 是一套注解形的网络请求封装库,让我们的代码结构更给为清晰。它可以直接解析JSON数据变成JAVA对象,甚至支持回调操作,处理不同的结果。主要是 Retrofit 能很好的与 RxAndroid 配合使用。
想更详细的了解 Retrofit,可以查看官方文档
什么是 MVVP ?
MVC(Model-View-Controller)和 MVP(Model-View-Presenter)是最常见的软件架构之一,业界有着广泛应用,大家一定不陌生。但知道什么事 MVVP 的就不多了,它本身很容易理解,但是要讲清楚,这几个架构的区别就不容易了。
MVVM(Model-View-ViewModel),它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。Angular 和 Ember 都采用这种模式。
而 Google 新推出的 Databinding 正是采用了这种模式。
RxAndroid + Retrofit + Databinding
上面已经分别介绍了 RxAndroid、Retrofit、Databinding ,想必大家也有了个初步的认识,那我们就看看 RxAndroid + Retrofit + Databinding 产生的“化学反应”。
- private void initActionBar() {
- setSupportActionBar(getBinding().toolbar);
- DrawerLayout drawer = getBinding().drawLayout;
- ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, getBinding().toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
- drawer.setDrawerListener(toggle);
- toggle.syncState();
- getBinding().navigationView.setNavigationItemSelectedListener(this);
- }
代码中不再充斥着 findViewById 这样的代码了,将 etContentView() 换成下面的方法。
- this.mBinding = DataBindingUtil.setContentView(context, layout_id);
系统会将我们的 layout 和 data 进行绑定并返回 bind 对象,bind.* 或者 bind.set 方法来取得控件或修改值。当然还有其它的方法,但是你此时再使用 findViewById() 方法不再有效了。
- public interface NewsApi {
- /**
- * 根据 ID 请求新闻列表
- * @param id
- * @return
- */
- @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7")
- @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByID(@Query("channelId") String id, @Query("page") int page);
- /**
- * 根据 ChannelName (标题)请求新闻列表
- * @param title
- * @return
- */
- @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7")
- @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByCName(@Query("channelName") String title, @Query("page") int page);
- /**
- * 根据 title (标题)请求新闻列表
- * @param title
- * @return
- */
- @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7")
- @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByTitle(@Query("title") String title, @Query("page") int page);
- }
-
- private void initObservables() {
- Observable.Transformer<List<News>, List<News>> networkingIndicator = RxNetworking.bindRefreshing(getBinding().refresher);
- observableRefresherNewsData = Observable.defer(() -> mNewApi.queryNewsByCName(getArguments().getString(BUNDLE_NAME), 1))
- .doOnUnsubscribe(() -> this.unsubcribe("observableNewsData"))
- .flatMap(data -> Observable.just(data.contentlist))
- .flatMap(list -> getApp().getDB().putList(Const.DB_NEWS_NAME, list, News.class))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .compose(networkingIndicator);
- observableLoadMoreNewsData = Observable.defer(() -> mNewApi.queryNewsByCName(getArguments().getString(BUNDLE_NAME), mCurrPage + 1))
- .doOnUnsubscribe(() -> this.unsubcribe("observableNewsData"))
- .map(data -> {
- mCurrPage = data.currentPage;
- return data.contentlist;
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .compose(networkingIndicator);
- // 刷新/加载更多
- RxSwipeRefreshLayout.refreshes(getBinding().refresher)
- .doOnUnsubscribe(() -> this.unsubcribe("SwipeRefreshLayout"))
- .flatMap(avoid -> observableRefresherNewsData)
- .compose(bindToLifecycle())
- .subscribe(RxList.prependTo(mNews, getBinding().content), this::showError);
- RxEndlessRecyclerView.reachesEnd(getBinding().content)
- .doOnUnsubscribe(() -> this.unsubcribe("Recycler"))
- .flatMap(avoid -> observableLoadMoreNewsData)
- .compose(bindToLifecycle())
- .subscribe(RxList.appendTo(mNews), this::showError);
- // 首次进入手动加载
- observableRefresherNewsData
- .map(list -> {
- mNews.clear();
- return list;
- })
- .compose(bindToLifecycle())
- .subscribe(RxList.prependTo(mNews, getBinding().content), this::showError);
- }
上面代码是使用 Retrofit 以 Get 形式从服务器中获取对应的新闻数据,大家可以看到代码的逻辑非常清晰,代码也很简洁(这里使用了 lambda 表达式,不使用的话,代码会长些,但是逻辑依然清晰),如果是按以前的写法的话,我们的代码会比这复杂的多,还涉及到复杂的线程之间的通信。而通过 RxJava ,我们只需要简单的使用 subscribeOn(Schedulers.io()) 和 observeOn(AndroidSchedulers.mainThread()) 就可以完成 IO 线程和 UI 线程的切换。
帅的简直不敢相信,原来还可以这样玩。
总结
优点:
代码逻辑更多加清晰。
线程之间的切换更加方便、自如。
代码可扩展性高,便于维护。
不再为 findViewById() 方法而烦,为 Activity 减负,整体结构更加清晰。
缺点:
代码出错时,由于 RxJava 的原因,将不太容易找到具体出错位置。
由于 RxJava 结构问题,部分需要捕捉的错误可能被 RxJava 消化掉。
Databinding 在部分情况使用不太如意,如 include 进来的 layout 里对应的 id 不会被关联起来。
需要一定的学习成本(当然这不是问题)。
广告
这里打个小广告,介绍下我最近开发的几个小应用
大家多支持下,如果下载达到 1000 的话,我会将其中一两个项目开源出来的哦。
扩展阅读
RxJava / RxAndroid
极力推荐的代码家干货:http://gank.io/post/560e15be2dca930e00da1083
Retrofit:
Retrofit 官方文档:http://square.github.io/retrofit/
Retrofit 使用介绍:http://www.cnblogs.com/angeldevil/p/3757335.html
Retrofit 离线缓存策略:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0115/3873.html
Databinding
MVC,MVP 和 MVVM 的图示:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
DataBinding 用户指南:http://segmentfault.com/a/1190000002876984
Github 上比较全面的:https://github.com/LyndonChin/MasteringAndroidDataBinding
浅谈 RxAndroid + Retrofit + Databinding的更多相关文章
- Android开发-浅谈架构(二)
写在前面的话 我记得有一期罗胖的<罗辑思维>中他提到 我们在这个碎片化 充满焦虑的时代该怎么学习--用30%的时间 了解70%该领域的知识然后迅速转移芳草鲜美的地方 像游牧民族那样.原话应 ...
- [转帖]浅谈响应式编程(Reactive Programming)
浅谈响应式编程(Reactive Programming) https://www.jianshu.com/p/1765f658200a 例子写的非常好呢. 0.9312018.02.14 21:22 ...
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- 浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- 浅谈WebService的版本兼容性设计
在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...
- 浅谈angular2+ionic2
浅谈angular2+ionic2 前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别. 1. 项目所用:angular2+ionic2 ...
- iOS开发之浅谈MVVM的架构设计与团队协作
今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
随机推荐
- (NO.00004)iOS实现打砖块游戏(一):素材的制作
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 本系列来实现一个儿时就很喜欢的打砖块游戏,我记得以前红白机上有一 ...
- Java进阶(三十) 判断字符串编码类型
java 判断字符串编码类型 public static String getEncoding(String str) { String encode = "GB2312"; tr ...
- 我眼中的Linux设备树(三 属性)
三 属性(property)device_type = "memory"就是一个属性,等号前边是属性,后边是值.节点是一个逻辑上相对独立的实体,属性是用来描述节点特性的,根据需要一 ...
- 视音频编解码学习工程:H.264分析器
=====================================================视音频编解码学习工程系列文章列表: 视音频编解码学习工程:H.264分析器 视音频编解码学习工 ...
- Java 截取中英文混合字符串
题目: 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串. 但是要保证汉字不被截半个,如"我ABC"4,应该截为"我AB",输入&q ...
- eclipse下出现奇怪字符的解决方法
eclipse在代码编辑界面出现了奇怪的字符,如下图: 其中包括:换行符,制表符等. 解决方法如下: 点击工具栏的显示空格字符即可.
- DB 查询分析器 6.03 ,遨游于任何Windows操作系统之上的最优秀的数据库客户端工具
DB 查询分析器 6.03 ,遨游于任何Windows操作系统之上的最优秀的数据库客户端工具 中国本土程序员马根峰(CSDN专访马根峰:海量数据处理与分析大师的中国本土程序员 .03版本已经完全兼容 ...
- Erlang cowboy 入门参考之现代Web的发展历史
Erlang cowboy 入门参考之现代Web发展史 原文: http://ninenines.eu/docs/en/cowboy/1.0/guide/modern_web/ 让我回顾一下web技术 ...
- ORACLE中用rownum分页并排序的SQL语句
ORACLE中用rownum分页并排序的SQL语句 以前分页习惯用这样的SQL语句: select * from (selectt.*,rownum row_num frommytable t ord ...
- Android FrameWork浅识
接收讯息及事件 储存共享数据 处理UI互动的事情 幕后服务(播放背景音乐) 在框架的手中,它的生命的周期完全由框架来控制,new也是由框架.它的逻辑调用则是自己实现,确保强龙的地位 框架反向来控制相应 ...