乐趣区

我为什么不再推荐-RxJava

本文转自作者: 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,他是一个利器,基本离不开。用不好,他就是你身边的定时炸弹,随时爆炸却又很难拆解。

退出移动版