Skip to content

Subscribing to EventStreams

JordanMartinez edited this page Feb 22, 2018 · 3 revisions

This page assumes that the reader has already read EventStream Intro and Basic Usage and is thus familiar with basic EventStream knowledge.

Purpose

This page overviews the various ways one can subscribe to an EventStream.

Note: Subscriptions will not be managed in the following examples. It is assumed that the reader already understands how to manage Subscription objects returned from subscribe-related methods.

The following code will be used for the examples below. When needed, examples will provide additional content.

@Override
public void start(Stage primaryStage) {
    Pane pane = new Pane();
    Scene scene = new Scene(pane, 400, 400);
    primaryStage.setScene(scene);
    primaryStage.show();

    EventStream<MouseEvent> sceneClicks = EventStreams.eventsOf(scene, MouseEvent.MOUSE_CLICKED);
}

EventStreams are Lazy!

Let's say that sceneClicks was initialized. Then, for the rest of the life of the program, nothing ever subscribes to sceneClicks. If this occurs, there are no memory leaks. What? How!? Because sceneClicks only starts observing its inputs/dependencies when something subscribes to it. Thus, all EventStream objects observes their inputs/dependencies lazily!

Let's say the following dashes "---" represents an EventStream and "S" is used to show that something has subscribed, and "#" is used to show that an event should be emitted by the EventStream:

----1-----2-----3------4------S----5---6----7-8----9---->

EventStream objects are Cold Observables by default, so the subscriber will only get notified of events 5-9. It will never know about events 1-4. There are ways to make EventStream objects appear to be Hot Observables, but that will be covered elsewhere.

Subscribe-Related methods

These methods all return a Subscription object that should be managed and unsubscribed when no longer needed.

Basic Subscribe methods

The Humble subscribe method

  • subscribe(Consumer c): runs c whenever the EventStream emits a new event.
    // basic subscribe method
    sceneClicks.subscribe(click -> System.out.println("Mouse Event was: " + click.toString());

The Auto-Unsubscribe subscribeFor methods:

These methods unsubscribe after so many events have been emitted from the EventStream.

  • subscribeFor(int n, Consumer c): same as subscribe() except auto-unsubscribes after n times.
    // subscribe for 5 times
    sceneClicks.subscribeFor(5, click -> System.out.println("This message will be printed 5 times!");
  • subscribeForOne(Consumer c): shortcut for subscribeFor(1, c).
    // Only do once!
    sceneClicks.subscribeForOne(click -> System.out.println("I only want to display this message once!")

Special-Cases Subscribe methods

Feeding a value

Sometimes, one might want to write:

    Circle circle = new Circle();
    EventStream<Double> radiusValues = ...;
    radiusValues.subscribe(radius -> circle.setRadius(radius));

Rather than doing this, one should use the feedTo() method:

  • feedTo(): feeds the Event emitted from an EventStream to the WriteableProperty or EventSink
    Circle streamCircle = new Circle();
    Circle circle = new Circle();
    EventStream<Double> widthValues = EventStreams.nonNullValuesOf(streamCircle.widthProperty());
    // feed the widthValue to the other circle's radius.
    widthValues.feedTo(circle.radiusProperty());

Pinning an EventStream

Sometimes, one wants an EventStream to observe its inputs/dependencies even when one doesn't want any code to run when an EventStream emits an Event. This would probably be used in EventStream Composition, a topic that will be covered later. In this situation, one would use the pin() method.

  • pin(): forces the EventStream to observe its inputs/dependencies.
    Rectangle rectangle = new Rectangle(50, 50, Color.BLACK);
    EventStream<Double> layoutYValues = EventStreams.nonNullValuesOf(rectangle.layoutYProperty());
    // at this point, if rectangle's layoutY value changes, layoutYValues wouldn't emit an event
    //   because it's lazy.
    layoutYValues.pin();
    // now layoutYValues will emit an Event every time rectangle's layoutY value changes.