本文转自作者: W_BinaryTree 链接:juejin.im/post/5cd04b6e51882540e53fdfa2,如有侵权,可删除
间隔上一次更新也有一段时间了,其实这篇文章我早就想写,碍于始终没来得及总结(懒)。所以始终没有成文。来总结一下我RxJava遇到的坑,或者说我为什么不在举荐应用RxJava。置信相熟或者关注我的敌人,绝大多数都是因为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时候,两个始终纠缠不清的问题就是map和flatMap的区别。还有flatMap和concatMap的区别。简略的讲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,他是一个利器,基本离不开。用不好,他就是你身边的定时炸弹,随时爆炸却又很难拆解。