It has been a while since the last update. In fact, I wanted to write this article for a long time, but I haven’t had time to summarize it (lazy). So it hasn’t been written. To summarize the pitfalls I’ve encountered with RxJava, or why I don’t recommend using RxJava. I believe that most of my friends who are familiar or concerned with me are because of RxJava. So you’re already surprised to see this headline. As a staunch advocate of RxJava, or do five? Why is RxJava suddenly no longer supported?
Let’s start with the history
I’ve said many times in my articles that RxJava was born because of asynchrony. Later on, the idea of LINQ and the power of Monad allowed Rx to use operator combinations to simplify complex requests. RxJava was designed primarily around Asyhconization and Composition, so to speak. Netflix also wrote RxJava and opened source to increase server performance and throughput. RxJava was born. Will you use RxJava in your work?
Let’s talk about asynchrony
In that RxJava just hot time, it was a wild time. We are under-resourced in asynchrony, with only basic asynchronous libraries such as ThreadPool,AsyncTask and Handler at hand. So let’s look at RxJava as a fancy little thing, and let’s see how simple asynchrony can be to solve the Concurrency problem. Of course we took it. We now have more options, whether it’s the CompletableFuture provided by Java 8 itself. Coroutine on Kotlin and LiveData on Android (here: Although threads are still managed by the user, common ones such as Room database, Retrofit, etc., have LiveDataAdapter, so we don’t really need to worry too much about threads. In contrast, RxJava’s advantages are not so obvious, but its disadvantages are quite significant.
RxJava threshold is too high
I don’t think most Android developers have a lot of knowledge or a lot of knowledge (I don’t have a lot of knowledge myself) about functions. But it’s almost impossible to get through some of the concepts in RxJava without knowing them. Take, for example, a famous Googler: Yigit Boyar. That is, the beard of IO every time, his magnum opus has many. RecyclerView, for example, and Architecture Component. Such a famous person in the Android world, how the level also has above average. However, when he implemented the adaptation of LiveData and RxJava, there was also a problem in understanding, resulting in the wrong implementation. The threshold of RxJava is too high, even if I have been promoting RxJava for so long, I can’t say that I know much about RxJava. Unexpected behaviors occur more or less often in the use of common operators. Moreover, both domestic and foreign RxJava tutorial level is uneven. It is difficult for a novice to identify who is right and who is wrong. Learning this high threshold asynchronous library is even more difficult under such mixed conditions. Many tutorials can easily mislead others (including my own posts) if you haven’t mastered them yourself.
High investment, little harvest
I doubt it, though, because I did find it very rewarding to dig into RxJava myself, especially to peek into the functional door through RxJava. However, from a utilitarian point of view, RxJava is really a high investment in solving the problem of asynchronous processing, but little gain. Asynchrony is an essential part of Android development. It can be said that mastering asynchrony should be the stepping stone to Android development. After all, RxJava solves the asynchronous problem by working with Monad in a responsive manner. But learning and mastering RxJava is not essential just to solve the asynchronous problem. On the contrary, mastering RxJava requires a lot of time and effort, which is completely unnecessary in today’s progressive world of asynchronous programming.
You can never predict the RxJava level of your colleagues
The above points may be a bit abstract, but this and the following points are real situations that I have encountered in real work. The first is that you can’t predict or demand from your colleagues how good RxJava will be. My previous company used a simple class redux framework. RxJava is the core part, which hosts the connection between the render layer and the View layer. For details on this architecture, see my project example here: Twivy. After reviewing my colleague’s code, I found out that RxJava can still play this way? I have to admire the rich imagination of my French colleagues. These misuses are buried in the code like ticking time bombs. It could explode at any time. But on the flip side, not everyone likes studying RxJava as much as I do. They may touch Rx simply because they use the architecture. Mastery of RxJava is not a requirement for Android development. He could have done a little RxJava without also being a great Android Developer.
The behavior of RxJava is not predictable
Another problem with RxJava is that it’s hard to know what a method really means just by looking at its name. When you first started learning RxJava, two of the issues that have been tangled up is the difference between map and flatMap. There are also differences between flatMap and concatMap. FlatMap is a pair of N maps and then flatten. Some tutorials write flatMap in order and concatMap in order. In fact, these are simple summaries, and the actual behavior is quite different. For example, will the flatMap trigger a second error after the first error? What do I do if I want to continue? How does concatMap move on to the next Observable if the first Observable does not break? These are almost to look at the source code or do many experiments to come to a conclusion, and the actual work and do not want to waste too much time because of this tool, not worth the loss. But if you don’t, it’s like a ticking time bomb. Going online directly increases the chance of errors.
RxJava is too error-prone
Uncle Ben said:
With great power comes great responsibility. It’s easy to use and easy to abuse. Examples I have come across in practice:
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()})
Copy the code
At first glance, there is nothing wrong with these lines of code. This Bug is still coming back to me in the background saying why does Android send two identical requests every time? The problem was that the stationLine and Station didn’t share the results. The result is that each request has to be sent twice. Modified code:
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()})
}
Copy the code
RxJava is still too idealistic
RxJava promises a perfect asynchronous world, where all asynchronous operations are controlled by the upstream, and the downstream only needs to think about how to handle them, not where the data comes from. In practice, the process is too idealistic. The most direct example is the emergence of BackPressure. When the amount of data is large enough, the cache pool does not cache all the data produced in time, resulting in more and more data and eventually OOM. It’s called BackPressure. Moreover, the Monad function is too complicated to wrap asynchronous operations, as anyone who has seen RxJava should know. Some very simple operators can be very complicated to implement. Tracking data is difficult, and it’s easy to fall into situations that are hard to Debug. And while the documentation for RxJava is one of the few well-written libraries I’ve ever seen, it’s not clear what behavior to expect for many operators if you don’t read through the source code and just look at the Java Doc and Method Signature. And even if you do, what to do in some particular case is still an unknown result. While RxJava liberates upstream control power, it also introduces insecurity. If there is an unexpected problem upstream, it will be difficult to deal with downstream. Second, RxJava introduces too much overhead for this idealized world. Whether it’s generating a new Observable instance for each operator or an asynchronous solution to the trampoline pattern. Have generated too many objects to store in the heap. This overhead is often too large for lightweight applications, or for small asynchronous processes such as data burying.
RxJava started with asynchrony, but it’s not just asynchrony
Rx, when proposed by Erik Meijer, was indeed derived from synchronous Iterable, moving from actively pulling data to passively accepting data (see my previous article: a different introduction to RxJava). But with the addition of the concept that functions are Monad,RxJava is used as a responsive data stream in more Callback base scenarios. It’s especially good on GUI platforms like Android. Most Android architectures based on the Redux architecture are based on RxJava in one way or another. Or borrow ideas from RxJava. Take Airbnb’s MvRx. Also, Google’s Sunflower, which was used as a Sample App in 18 years of IO, used LiveData heavily. LiveData also borrows a lot from RxJava ideas.
Bottom line: RxJava, while excellent, is not for everyone
Even though RxJava has and is not limited to the issues I’ve mentioned, there is no doubt that RxJava is a great asynchronous framework for the ages. But good doesn’t mean it’s for everyone. I promoted RxJava earlier, arguing that such an asynchronous foundation should be an essential knowledge for every Android developer. But after two years of working on it, I decided it wasn’t practical or necessary. The level of RxJava does not necessarily map to the level of development of an Android Dev, and conversely, a high-level Android Dev does not necessarily know much about RxJava. In such a premise, plus the entry threshold is high, error prone, bad behavior expectations and other shortcomings. My preference is to abandon RxJava directly when my team doesn’t have RxJava Expert, and to switch to an easier to use asynchronous framework and responsive data flow. When I joined the new company, I wrote this in an email:
engineering is about trade off
RxJava is such a library, a honey, b arsenic. Use good RxJava, he is a sharp tool, can not be separated from. Don’t use it well, he’s a ticking time bomb around you, ready to go off but hard to disassemble.