RxJava 不是上帝,真不推荐再用了

  • 时间:2019-08-22 01:58 作者:Android技术干货分享 来源:Android技术干货分享 阅读:1186
  • 扫一扫,手机访问
摘要:距离上一次升级关于RxJava也有一段时间了,其实这篇文章我早就想写,碍于一直没来得及总结(懒)。所以一直没有成文,今天就来总结一下我RxJava遇到的坑,或者者说我为什么不在推荐使用RxJava。在我的文章中已经讲过很屡次RxJava诞生之初就是由于异步。再后来借鉴LINQ的思想借用Monad的力量

距离上一次升级关于RxJava也有一段时间了,其实这篇文章我早就想写,碍于一直没来得及总结(懒)。所以一直没有成文,今天就来总结一下我RxJava遇到的坑,或者者说我为什么不在推荐使用RxJava。

在我的文章中已经讲过很屡次RxJava诞生之初就是由于异步。再后来借鉴LINQ的思想借用Monad的力量使得 Rx可以使用操作符进行组合将各种复杂的请求简单化。 可以说,RxJava的设计初衷就是围绕着Asyhconization和Composition。当年的Netflix也是为了添加服务器的性能和吞吐量来编写RxJava并开源。才使得RxJava问世。

再聊聊异步

在那个RxJava刚刚火爆的年代,那是一个荒蛮的年代。我们在异步方面资源匮乏,手头仅有ThreadPool,AsyncTask和Handler这些基础封装的异步库。所以当我们看见RxJava这个新奇的小玩意,当我们看到异步还可以这么简单,轻而易举的处理Concurrency问题。我们当然如获至宝。 而我们现在选择就更多了,无论是Java 8本身提供的CompletableFuture。还是后起之秀Kotlin上的Coroutine,还有Android 上官方提供的LiveData(这里说下: 尽管本质上线程管理仍需客户自己,但是常见的比方Room数据库,Retrofit等等都有现成的LiveDataAdapter,实际上并不需要我们过多操心线程问题)。 相比之下,RxJava优势并不那么显著,相反劣势却很突出。

RxJava 门槛太高

相信多数Android开发者并没有理解过或者者说深入理解过(我自己也没深入理解过)函数式相关的知识。但是假如不理解这些,那么而几乎可以说不可能融会贯通RxJava的少量概念。 举个例子,一个很著名的Googler:Yigit Boyar。也就是每次IO的那个大胡子,他的代表作有很多。比方RecyclerView,再比方Architecture Component。这样一个Android界名人,水平怎样也有平均以上。但是他在实现LiveData和RxJava适配的时候,同样出现了因为了解上出的问题,造成错误的实现方式。 RxJava的门槛过于高,就连我自己推广这么久,自己也不敢说对RxJava理解有多深刻。经常在常见操作符的使用中出现了或者多或者少的unexpected behavior。 再者,无论国内国外的RxJava教程水平都参差不齐。新手很难鉴别哪些人说的是对的哪些人说的是错误的。在这样鱼龙混杂的条件下学好这个高门槛的异步库更是变得难上加难。很多教程在自己没有精通的情况下,很容易误导其余人(包括我自己的文章)。

投入高,收获少

尽管这点存疑,由于我自己钻研RxJava之后的确觉得收获很大,尤其是经由RxJava窥探了函数式的大门。但是功利的看,RxJava在处理异步解决这个问题上,确实是投入高,收获少。 异步问题是Android开发必不可少的一个环节,可以说掌握异步应该是成为入门Android开发的敲门砖。而RxJava归根究竟是通过响应式的方式配合Monad来处理异步问题。但是仅仅为理解决异步问题,学习并精通RxJava并不是必不可少的。相反,精通RxJava需要大量时间和精力,在现在异步编程逐渐完善的情况下,完全没有必要。

你永远无法预测你同事的RxJava水平

上面几点可能有点笼统,而这点和接下来的几点都是我在实际工作中遇到的实际情况。首先就是你并不能预测或者者要求你的同事RxJava到达什么样的水平。 我之前的公司使用了一个简单的类redux框架。其中RxJava是核心部分,他承载了中间render层和view层的连接。在Review同事的代码之后,我才发现RxJava还能这么玩?各种奇思妙想的作用让我不得不佩服法国同事的丰富想象力。而这些错误使用就像一颗颗定时炸弹一样埋在代码里。随时可能爆炸。 但是反过来一想,并不是所有人都像我一样喜欢研究RxJava。他们可能仅仅是由于使用了这个架构而接触Rx。而RxJava的掌握并不是一个Android开发的必要条件。他完全可以一点RxJava也不会也成为一个优秀的Android Developer。

RxJava的行为并不可预期

RxJava还有一大毛病就是光看方法名你很难知道他的真正意思。 在初学RxJava时候,两个一直纠缠不清的问题就是mapflatMap的区别。还有flatMapconcatMap的区别。 简单的讲map是一对一,flatMap是一对N的map而后在进行flatten操作。 还有些教程直接写出flatMap无序,concatMap有序。 其实这些都只是简单总结,而实际的行为照着相差甚远。 比方flatMap在第一个error的时候会不会继续继续触发第二个?假如我想继续,将如何操作? 再比方concatMap在遇到第一个Observable不会中断的时候,怎样继续下一个? 这些都几乎是要看源码或者者做屡次试验比照才能得出结论的问题,而实际工作中并不想去由于这个工具而去白费太多时间,得不偿失。但是假如不做,就像前文提到的定时炸弹一样。上线直接添加错误几率。

RxJava太容易出错

Uncle Ben 说过:

with great power comes great responsibility. RxJava就是这样。在简单易用的同时他太容易被滥用了。我在实际工作中碰到的例子:

val stationId = "5bCP6Iqx"val statoin:Observable<Station> = staionRepo.getStationById(stationId)val stationLine:Observable<StationLine> = station.flatMap{station ->stationRepo.getLine(station)}return Observable.merge(station.map{it.toUiModel()},stationLine.map{it.toUiModel()})

乍一看,这几行代码并没有错。这个Bug还是后端反馈给我的说为什么android每次都会发两个一模一样的请求? 其实问题就出在stationLine和station并没有共享结果。造成了每次请求都要发两次。 修改后的代码:

val stationId = "5bCP6bif"val statoin:Observable<Station> = staionRepo.getStationById(stationId)return station.publish{selector ->    Observable.merge(selector.map{it.toUiModel()},            selector.flatMap{station -> stationRepo.getLine(station)}                    .map{it.toUiModel()})}

RxJava还是过于理想化了

RxJava承诺出一个完美的异步世界,一切异步操作由上游控制,下游只要要思考如何解决,并不关心数据来源。 而实际过程中,这个过程还是过于理想化了。最直接的例子就是BackPressure的出现。 在数据量足够庞大时,缓存池并不能及时缓存所有生产的数据,造成越积越多最终OOM。也即是所谓的BackPressure。 再者,函数式中的Monad来包裹异步这个操作还是过于复杂了,看过RxJava的朋友都应该清楚。某些很简单的操作符在实现起来其实非常复杂。追踪数据十分困难,很容易掉入很难Debug的情况。 而且尽管RxJava的文档是我见过少有写的非常出色的库,但是很多操作符假如不读通源码,仅仅从Java Doc和Method Signature来观察,并不清楚期待的行为是什么。就算知道,在少量特殊情况如何解决,仍是一个未知结果。 同时RxJava尽管解放了上游控制权力的,也引入了不安全性。假如上游出现了非料想的问题,下游将很难解决。 其次,RxJava为了这个理想化的世界,引入了太多的overhead。无论是每个操作符都要生成一个新的Observable实例还是蹦床模式的异步处理方案。都生成了太多的Object在堆中存放。这种overhead在轻量级应用,或者者少量小型异步解决比方数据埋点等等行为中,都显得过于庞大。

RxJava起于异步,却也不单单是异步

Rx在被Erik Meijer 提出的时候,的确是由同步的Iterable推导,由主动拉取数据改为被动接受数据。 但是在加入函数是Monad的概念之后,RxJava作为响应式数据流,应用在了更多Callback base的场景中。在Android这种GUI平台下尤为出色。 多数基于Redux结构的Android架构都或者多或者少基于RxJava。或者者借鉴RxJava的思想。比方Airbnb推出的MvRx。 还有Google在18年io中当作Sample App做出的Sunflower,大量使用LiveData。而LiveData无疑也是大量借鉴了RxJava的思想。

总结:RxJava尽管优秀,但并不适合所有人

即便RxJava有且不仅限于我说的上述几个问题,但无疑RxJava仍是一个划时代的优秀的异步框架。 但是优秀并不代表适合所有人,我在之前推广RxJava,认为这样的异步基础应该是每一个Android开发者必不可少的知识点。但实际工作使用两年之后,我觉得这并不实际,也不必要。RxJava的水平并不能映射一个Android Dev的开发水平,反之,一个高水平的Android Dev也并不肯定对RxJava理解多少。 在这样的前提下,再加上入门门槛高,易出错,行为不好预期等等缺点下。在团队没有RxJava Expert的情况下我更倾向于直接弃用RxJava,转为更容易使用的异步框架和响应式数据流。 我在入职新公司的的时候,邮件里写了这样一句:

engineering is about trade off

RxJava便是这样一个库,甲之蜜糖,乙之砒霜。用的好RxJava,他是一个利器,根本离不开。用不好,他就是你身边的定时炸弹,随时爆炸却又很难拆解。

假如你看到了这里,觉得文章写得不错就给个赞呗?假如你觉得那里值得改进的,请给我留言。肯定会认真查询,修正不足。谢谢。

希望读到这的您能转发分享和关注一下我,以后还会升级技术干货,谢谢您的支持!

转发+点赞+关注,第一时间获取最新知识点

Android架构师之路很漫长,一起共勉吧!


以下墙裂推荐阅读!!!

  • Android学习笔记参考!
  • “寒冬未过”,阿里P9架构分享Android必备技术点,让你offer拿到手软!
  • 毕业3年,我是如何从年薪10W的拖拽工程师成为30W资深Android开发者!
  • 腾讯T3大牛带你理解 2019 Android开发趋势及必备技术点!
  • 八年Android开发,从码农到架构师分享我的技术成长之路,共勉!
  • 全部评论(0)
最新发布的资讯信息
【系统环境|】通义万相wan2.2本地部署要求有哪些?通义万相wan2.2怎么本地部署(2025-10-21 04:05)
【系统环境|】Vue3 页面卡顿严重?7 个实战技巧让渲染速度飙升 80%!(2025-10-21 04:01)
【系统环境|】前端小白 2 周 Vue3+TS+NaiveUI 学习计划大纲(2025-10-21 04:00)
【系统环境|】Vue3 入门指南: 深入理解 Setup 函数(2025-10-21 03:59)
【系统环境|】2024前端面试真题之—VUE篇(2025-10-21 03:58)
【系统环境|】搞懂Vue3的toRefs与toRef:响应式对象的解构(2025-10-21 03:55)
【系统环境|】三.不定词副词的用法(2025-10-21 03:53)
【系统环境|】歌曲中汉字的信息量真的是吊打英语(2025-10-21 03:52)
【系统环境|】跟着《肖申克的救赎》学英语(002)--安迪法庭受审(2025-10-21 03:52)
【系统环境|】词根词缀-前缀1-27: de-(2025-10-21 03:50)
手机二维码手机访问领取大礼包
返回顶部