Reactive Programming Made Simple Part 3
Let’s do another quick recap on parts 1 and 2: Reactive programming revolves around streams. Streams have 3 key parts (Observables, Operators, and Observers). Observers subscribe to Observables and react to data events as they occur, and if there are operators in the stream they each take their action as data flows past them in the stream. Got it? Then on to the last step!
Threading: Our best friend and worst enemy
Last post we left off with a friendNetworkRequest that returns an Observable to us and an Observer that calls the function displayCountToScreen if a piece of data makes it to it. By this I mean if the data makes it past the filter operator checking if the number is higher than 100. Unfortunately, our set up doesn’t work right now because of one issue: Threading.
Threading is a complicated topic but using it properly can give us a lot of power. It’s the idea of not having just one chain of events, but instead dividing up work into multiple strains of thought and letting them each execute on their own time. Think of it like a railroad track that splits into multiple paths. Each path is still a place for trains (i.e. app logic) to flow, but if something is moving particularly slow we don’t want to make every train wait behind it. It’s better to have multiple paths and allow certain trains to speed by on open paths while their slower counterparts take time.
The UI Thread:
All applications have a main thread which we also call the UI thread. It’s what user’s interact with and by default what most of your app runs on. But since users are always interacting with this thread we need to make sure it doesn’t have any slow moving pieces. If it does do things like waiting for a response from a website apps will freeze up. A user doesn’t know why and may think things are broken, when in reality the app is just waiting for something to finish before it can take any new actions on the main thread.
Since networking is notorious for taking a while to complete (and is always out of an app’s control), network requests must take place on a background thread. Additionally anything we’re doing that is changing a user’s screen must take place on the UI thread. So now we see our issue: How can we have one reactive stream that both makes a request on a background thread and uses that threads result to update the UI thread?
A fourth component of reactive streams known as Schedulers is our answer. Schedulers let us specify what thread we want different parts of our stream to take place on. We can make them very complicated if we want, but in general it’s best to implement each of two methods once. These are subscribeOn and observeOn.
We add each of these onto our Marbleworks Observable the same way we add an extra operator or subscribe to it. And they each have an individual yet similar impact on the stream. subscribeOn specifies which thread the observable will operate, and observeOn specifies which thread the observer will observe.
That’s a very confusing way of putting it. Let’s try again: subscribeOn lets us choose a background thread to have most of the data’s transfer/manipulation take place (every operator that is called as data flows through the stream. While observeOn lets us choose the thread where the final step of observing data emissions takes place. In general data operators will take place on a background thread while the observer takes place on the UI thread. We do things with data, and only take up the UI thread when we need to update something for the user.
These Schedulers can be added to our Observable like so:
.filter(friendCount -> friendCount > 100)
.subscribe(friendCount -> displayCountToScreen(friendCount))
And now if we run our code again it will work! It’s a small (and easily implemented) change to our flow, but it makes all the difference with speed.
Threading is an incredibly powerful and incredibly difficult topic. It can be leveraged to maximize our app’s efficiency but can also be difficult to debug when things don’t go right. Luckily RxJava and RxSwift make implementing threading incredibly simple as we can see by the fact we only added two lines of code to our app. Now we’re ready to make many more network requests, and hopefully build something a little more exciting!