By Ivan Morgillo, Sasa Sekulic, and Fabrizio Chignoli

This article is an excerpt from Grokking Rx that discusses the basics of state machines, using the example of a radio player.

Save 37% off Grokking Rx with code fccmorgillo at manning.com.

State machine basics

So, what is a state machine? We can define the state machine as an object that:

a)   has defined states;

b)   has defined transitions between the states (i.e. actions that bring the machine from one state to another).

Figure 1 shows a standard state diagram of a simple state machine with two states and two transitions.


Figure 1: state machine with two states (state 1 and state 2) and two transitions (action 1 and action 2)


Radio player as a state machine

We can present our radio player as a simple state machine. Let’s look at a basic state machine diagram in figure 1: it has two states and two possible actions that change the state from one to another.

Let’s see how we can do this: the stopped state represents the state 1, and the playing state is state 2; actions 1 and 2 are the same action (pressing the play/stop button) but the outcome depends on the player state (playing when it’s stopped and stopping when it’s playing).


Figure 2: player represented with a state machine diagram with two states (stopped and playing) and two transitions (start playing and stop playing)


With a pinch of reactive

How do we implement these two states (stopped, playing) and two transitions (stopped -> playing, playing -> stopped) using reactive programming?

We could store the player state in an Observable, and to be informed about the changes of the state we could use an Observer that would subscribe to this Observable to allow us to react to the changes in the Observer’s onNext() method. That way, when the Observable has a new state, for example PLAYING, in the Observer’s onNext() we could call the method that will start playing the song.

 

Note

Observable: an object which emits values and events to which an Observer can subscribe. Observer: subscribes to an Observable and receives new events through standardized interface (onNext(), onCompleted(), onError())

 

Figure 3


But can we do that? Can we send a new state to the Observer?

If you take a closer look at the diagram above, you’ll notice that the Observable has the arrows in the bottom right (which means that it emits the values), and the Observer has them in the top left (which means that it receives the values), but for the above to work, the Observable should be able to also receive the values.

Enter the Subject

Our reactive implementation of the radio player has encountered a problem: we have an Observable whose value should be updated when we press the button – we need an Observable creation method that lets us control the Observable’s value once it’s created.

 

Creating an Observable

The Observable’s value is decided in the creation methods and we cant touch the Observable outside of them.

 

A normal Observable doesn’t do what we need it to do because we can’t change the value at a later point in time, after we’ve created an Observable. If we want to be able to change the value of the Observable after its creation, we should use a Subject.


Figure 4


Introducing Subjects

The Subject is an object that has an Observable that exposes the Observer interface through which new values and events can be sent to the Observable (and received by the Observers subscribed to the Subject). It behaves both like an observer; it has accessible onNext(), onError()and onCompleted(), and like an observable (you can subscribe to it).

What does this mean for us and our radio player?

Now, when the button is pressed, we can call playerSubject.onNext(NEW_STATE) and the Observer subscribed to our Subject receives this new state.

Do more

Because this is a simple radio-like player, transitions between the states are executed only when the button is pressed. To make it like an ordinary music player, you can also change the state when the song finishes, and in case of an error call playerSubject.onError(CATASTROPHIC_ERROR).

Altogether now

Look at the updated diagram below, and you’ll notice that our newly placed Subject can both receive values and emit values to the Observer.

This is exactly what we need for our player!

Figure 5


The pieces that we need for our simple player to work are:

  • Button, with its associated listener, which checks the current state and sends the new state to the Subject;
  • Subject, that receives the new value from the button listener and emits it to its Observers;
  • Observer, which contains the business/UI logic of our player, and executes the transition, depending on the state that arrives from the Subject

We’ve made out radio player! Hopefully you found this article informative and interesting. For more, download the free first chapter of Grokking Rx and see this Slideshare presentation.