我为何再也不推荐RxJava

距离上一次更新也有一段时间了,其实这篇文章我早就想写,碍于一直没来得及总结(懒)。因此一直没有成文。来总结一下我RxJava遇到的坑,或者说我为何不在推荐使用RxJava。 相信熟悉或者关注个人朋友,绝大多数都是由于RxJava。因此看到这个标题你已经会惊讶。 做为RxJava坚决的拥护者,或者说自干五?为何忽然再也不支持RxJava了呢?java

先讲讲历史

在个人文章中已经讲过不少次RxJava诞生之初就是由于异步。再后来借鉴LINQ的思想借用Monad的力量使得 Rx可使用操做符进行组合将各类复杂的请求简单化。 能够说,RxJava的设计初衷就是围绕着Asyhconization和Composition。当年的Netflix也是为了增长服务器的性能和吞吐量来编写RxJava并开源。才使得RxJava问世。详细关于这段能够参考个人知乎回答:你会在实际工做中使用 rxjava 吗?android

再聊聊异步

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

RxJava 门槛过高

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

投入高,收获少

虽然这点存疑,由于我本身钻研RxJava以后确实以为收获很大,尤为是经由RxJava窥探了函数式的大门。可是功利的看,RxJava在解决异步处理这个问题上,的确是投入高,收获少。 异步问题是Android开发必不可少的一个环节,能够说掌握异步应该是成为入门Android开发的敲门砖。而RxJava归根究竟是经过响应式的方式配合Monad来解决异步问题。可是仅仅为了解决异步问题,学习并精通RxJava并非必不可少的。相反,精通RxJava须要大量时间和精力,在如今异步编程逐步完善的状况下,彻底没有必要。数据库

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

上面几点可能有点抽象,而这点和接下来的几点都是我在实际工做中遇到的实际状况。首先就是你并不能预测或者要求你的同事RxJava到达什么样的水平。 我以前的公司使用了一个简单的类redux框架。其中RxJava是核心部分,他承载了中间render层和view层的链接。具体关于这个架构能够看我这里的项目实例:Twivy。 在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不会中断的时候,怎么继续下一个? 这些都几乎是要看源码或者作屡次实验对比才能得出结论的问题,而实际工做中并不想去由于这个工具而去浪费太多时间,得不偿失。可是若是不作,就像前文提到的定时炸弹同样。上线直接增长错误概率。redux

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推导,由主动拉取数据改成被动接受数据(可参考我以前的文章:一篇不太同样的RxJava介绍)。 可是在加入函数是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,他是一个利器,根本离不开。用很差,他就是你身边的定时炸弹,随时爆炸却又很难拆解。

相关文章
相关标签/搜索