RxJava common Misunderstanding (a): excessive use of Subject

Source: Internet
Author: User
Tags emit

This article starts: http://prototypez.github.io/2016/04/10/rxjava-common-mistakes-1/

Reprint please indicate the source

Ready to write this article time to see the next RxJava on Github has 12000+ a star, visible popularity, their use of RxJava has been a short period of time. Originally in the community to RxJava a piece of praise, began to use RxJava to replace some of the project's simple asynchronous request, until later began to contact some advanced play, this middle reading code plus their own tread on the pit, slowly accumulated some experience, many are novice easy to make mistakes and RxJava A place that is easily misunderstood. This article is not finished, so I intend to write a series, this article is the first article of this series.

Careful use of subject

SubjectObservableIt is also Observer , because of itself, that it Observer can be called from anywhere in the project onNext (as long as the Subject reference is available). It looks good, doesn't it? Compared Observable.create to, Observable.from Observable.just more convenient, the three factory methods have a feature, that is, the built-in Observable emission elements are determined, even in many cases, the elements to be emitted as constants in the compilation period can be determined. When I first started learning these little examples of getting started, I was thinking about how simple it is: events that interact with the UI, changes in the network type of the mobile device (WiFi and cellular switching), the arrival of the server push message, when the event occurs and the number of times it is generated, is known at run time. How can you use these factory methods to simply emit a few fixed values.

Until I met Subject . I can start by creating a first element that doesn't emit Observable ( Subject Observable the subclass), and create the corresponding subscription at the same time, and Subscriber Observable then when I think of a ready time, call this Subject object's onNext method to its Subscriberemitting elements. The logic is concise and flexible enough, and the code looks like this:

PublishSubject<String> subject = PublishSubject.create();subject.map(String::length)    .subscribe(System.out::println);...// 在某个Ready的时机subject.onNext("Puppy");...// 当某个时刻subjcet已经完成了使命subject.onCompleted();
Using Subject may lead to missed events that are really concerned

At present, everything is logical, contrast Observable , Subject obvious advantages, can be on demand at the right time to launch elements, it seems to be Subject more able to meet the needs of daily tasks, more radical, simply use Subject to replace all the Observable bar. In fact, I did, but soon I got into trouble. For example, the code is as follows:

publishsubject<string> operation = Publishsubject.create (); operation. Subscribe (NewSubscriber<string> () {@Override     Public void oncompleted() {System.out.println ("Completed"); }@Override     Public void OnError(Throwable e) {    }@Override     Public void OnNext(String s)    {System.out.println (s); }}); Operation.onnext ("Foo"); Operation.onnext ("Bar"); operation.oncompleted ();

This code is very simple, as expected, its output is:

FooBarcompleted

Change it a little bit, using the RxJava Scheduler to Scheduler specify operation objects to emit elements from the IO thread, the code is as follows (the code in this article is main run from the start of the function):

publishsubject<string> operation = Publishsubject.create (); operation. Subscribeon (Schedulers.io ()). Subscribe (NewSubscriber<string> () {@Override     Public void oncompleted() {System.out.println ("Completed"); }@Override     Public void OnError(Throwable e) {    }@Override     Public void OnNext(String s)    {System.out.println (s); }}); Operation.onnext ("Foo"); Operation.onnext ("Bar"); operation.oncompleted (); Sleep ( -);

The result of the actual output of the above code is:

completed

In the above code, in addition to the scheduler, and finally added a line of code to keep the current thread dormant for 2 seconds, because the operation object is changed from the IO thread after the element is fired, the main thread is running to the last line directly exited, causing the entire process to end, the IO thread has not started firing elements, so this 2 seconds is used to wait for the IO thread to start up and finish the task.

The changed code is not received Foo and Bar , if the last line is sleep(2000) removed, then the Console will not output anything. This is the first reason why we need to be cautious Subject : using Subject can lead to missed events that are really concerned .

In RxJava , Observable can be divided into Hot Observable with Cold Observable , citing "learning reactive programming with Java 8" in an image of the metaphor (translated meaning):

We can assume that each Cold Observable time a subscription is sent for each of the Subscriber elements that are available for use, and always in the Hot Observable running state, when it is running, the element is emitted to its subscribers (sending broadcasts, events), and we can liken it to Hot Observable a radio station, Listeners listen to the station at some point and start to hear the show and then the show, but can't hear the radio show, and Cold Observable like a music CD, people buy CDs time may be a gap before and after, but listen to the CD is from the first track start playing. In other words, the same CD, everyone hears the same content, regardless of the listening time early or late.

SubjcetBelong Hot Observable to it. Cold Observablecan be converted to Hot Observable , but not in turn. Back to explain why the above example is only output completed : Because the operation object emitting element of the thread is assigned to the IO thread, the corresponding subscriber also work on the IO thread, and the IO thread is called by Scheduler for the first time, not yet up (initializing), The first two elements of the launch, the Foo Bar main thread, the main thread of these two elements to the IO thread forwarding process because the IO thread has not been up, it was discarded (radio station even if there is no listener, can still broadcast). completesignal is very special, in Reactive X the design, the signal priority is very high, so can always be a priority to capture, but this is another topic.

So Subject when using, we must carefully design the program, to ensure that the message is sent when the time is Subscriber ready, otherwise we can easily miss the events we care about, when the code is faced with refactoring in the future, other programmers must know this logic, otherwise it is easy to introduce Bug. If we do not want to miss any events, then we should use as much as possible Cold Observable , the above example if the operation object used Observable.just , Observable.from to construct, there is no such a problem.

In fact, a missed event typically occurs under critical conditions, such as I just declared one Subscriber and want to send an event to it immediately. It is best not to use it at this time Subject Observable.create(OnSubscribe) . The problem code above is changed to the following, it will work properly:

observable<string> operation = Observable.create (subscriber, {Subscriber.onnext ("Foo"); Subscriber.onnext ("Bar"); Subscriber.oncompleted ();}); O Peration. Subscribeon (Schedulers.io ()). Subscribe (NewSubscriber<string> () {@Override     Public void oncompleted() {System.out.println ("Completed"); }@Override     Public void OnError(Throwable e) {    }@Override     Public void OnNext(String s)    {System.out.println (s); }}); Sleep ( -);
Subjcet is not thread-safe

The second problem to use is that Subject it is not thread-safe , and if the method that calls it on different threads onNext is likely to cause a race condition (race conditions), we should try to avoid the occurrence of this situation, Because unless you write enough detailed comments in your code, programmers who maintain this code in the future are likely to step on the hole somehow. If you think you really need to use Subject it, then turn it into a SerializedSubject thread-safe way to ensure that multiple threads call the method at the same time onNext .

SerializedSubject<Integer,Integer> subject =      PublishSubject.<Integer>create().toSerialized();
Subject the sending of events becomes unpredictable

The last reason we should be cautious Subject is that it makes the sending of events unpredictable. Since Observable.create The example used above has been given, look at the other two factory methods Observable.just and Observable.from examples:

Observable<String> values = Observable.just("Foo""Bar");Observable myObservable = Observable.from(new String[]{"Foo","Bar"});

Either Observable.create , Observable.from or Observable.just , there is Cold Observable a significant advantage to the fact that the source of the data is predictable, and I know what data will be sent and what type of data it is. But Subject not the same, if I create one Subject , then anywhere in the code can get to this reference, you can freely use it to emit elements, the consequences of abuse caused the code more and more difficult to maintain, I do not know whether the other people in some I do not know the launch of the element I do not know, I don't believe anyone would want to maintain such a code. This is an anti-pattern, the same as the C language when the idea of modularity has not yet been rooted in the global variables brought about by the same disaster.

Perhaps see here you will think, said for a long while seems to return to the beginning, Subject with the flexibility of programming is not recommended, for these reasons and re-use the three inflexible factory method, really can not meet the demand ah. Let's look back at some of the most common realities of programming that we've mentioned before:

Events that the user interacts with the UI

Changes in the type of mobile device network (WiFi vs. cellular network switching)

Arrival of the server push message

In fact, these events are often provided to the programmer on the interface of the registered listener, and we can use Observable.create this factory method to create the observable:

FinalClass Viewclickonsubscribe implements Observable.onsubscribe<void> {FinalView view; Viewclickonsubscribe (view view) { This. view = view; }@Override  Public void Pager(Finalsubscriber<?Supervoid> subscriber) {verifymainthread (); View.onclicklistener listener =NewView.onclicklistener () {@Override  Public void OnClick(View v) {if(!subscriber.isunsubscribed ()) {Subscriber.onnext (NULL);        }            }        };        View.setonclicklistener (listener); Subscriber.add (NewMainthreadsubscription () {@Override protected void Onunsubscribe() {View.setonclicklistener (NULL);    }        }); }}

The above code comes from Jake Wharton's Android Project Rxbinding, which is designed to translate the events generated by user interaction with controls on the Android UI into a Observable programmer. The idea of the above code is simple, that is, when there is a Subscriber click event that you want to subscribe to View , it is a View callback () that registers a click in the Android Framework, which is view.setOnClickListener(listener) called Subscriber onNext whenever the Click event arrives. Method.

Let's compare another less-than-good notation:

new View.OnClickListener() {  @OverridepublicvoidonClick(View v) {      subject.onNext(null);  }};view.setOnClickListener(listener);

Here is subject just the entire project part of the code, we do not know whether other places to subject give the object, the potential risk is that we have just discussed may miss the critical situation of the event , thread insecurity , The event source is unpredictable.

Summarize

We've learned about the Subject flexibility and risk we have, so when it comes to real-world projects, I recommend using the Observable 3 factory methods provided, and using them sparingly Subject , 90% of the cases can be solved using the 3 factory methods, if you're sure you want to use Subject , then make sure: 1. This is one Hot Observable and you have a corresponding measure to ensure that the critical event is not missed; 2. There is a corresponding thread security; 3. Modular code to ensure that the source of the event is in control and the event is sent fully predictable. Yes, plus the necessary notes:)

RxJava common Misunderstanding (a): excessive use of Subject

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.