A Simple Vocabulary App Using ReactiveUI and Xamarin Forms
These days, reactive programming and its supporting frameworks are a white-hot topic for companies and developers everywhere.
On the web, mobile, desktop or server - reactive programming is emerging as the answer for many new types of problems and use cases previously solved using traditional, imperative programming paradigms.
I'm not going to do a deep dive introduction here so if you're new to the concept of reactive programming I highly recommend you stop reading this and go check out Andre Staltz's excellent introduction before proceeding with this tutorial.
Here are two excerpts I pulled from Andre's tutorial that I found helpful to keep in mind when answering the What and Why behind reactive programming.
What is reactive programming?
Reactive programming is programming with asynchronous data streams.
In a way, this isn't anything new. Event buses or your typical click events are really an asynchronous event stream, on which you can observe and do some side effects. Reactive is that idea on steroids. You are able to create data streams of anything, not just from click and hover events. Streams are cheap and ubiquitous, anything can be a stream: variables, user inputs, properties, caches, data structures, etc. For example, imagine your Twitter feed would be a data stream in the same fashion that click events are. You can listen to that stream and react accordingly.
Get notified on new posts
Straight from me, no spam, no bullshit. Frequent, helpful, email-only content.
Why use reactive programming?
Apps nowadays have an abundance of real-time events of every kind that enable a highly interactive experience to the user. We need tools for properly dealing with that, and Reactive Programming is an answer.
Our app
We're going to build a simple app to help broaden our vocabulary. Similar in concept to flashcards but with some extra features like scoring to track our progress and a bit of a game effect to make it fun. Our implementation will be based on ReactiveUI, which is an MVVM framework that integrates with the Reactive Extensions for .net.
My setup
I'm running Visual Studio 2015 Professional, Update 3 on Windows 10.
Application architecture
I created a new app using the Xamarin Forms PCL project template (Xamarin.Forms.Portable) and structured it using MVVM. ReactiveUI plays very nicely within the MVVM architecture, hence its use in this application. I also implemented a data layer based on SQLite, navigation serivce and a DI-container using autofac to keep our app components nicely decoupled and injectable everywhere. To keep the focus on ReactiveUI I won't go into how I implemented these bits in this guide so please refer to the source code or drop a question in the comments if you'd like to know more.
The PCL project structure.
Data
To supply our app with an adequate list of words I've already provisioned our project with a sqlite database pre-populated with 1000 words. Note, as we're only targeting android for this tutorial I only added the DB to that project.
Let's get reactive
The core concept in reactive programming is the Observable. In a nutshell, observables represent a stream or sequence of data that may or may not have a beginning or an end. When we think about it, many different kinds of data can be modeled in this observable fashion.
- The classic example: a stock ticker constantly providing updates on fluctuating stock prices
- Twitter: a never-ending stream of data flows through twitter. Their status API is literally named firehose.
- Keyboard presses and mouse clicks: events are infinite and we can receive a new signal and piece of data for each one that occurs.
Great - we have a channel or stream to bring data into our application so now what? To make use of these observables we use Subscribers to receive interesting events from our observable like "new data arrived" or "error occurred" or "no more data". As these events occur, our subscriber(s) can react in any number of ways to handle that event accordingly in our program.
I'll mention at this point that it's simply impossible to fully describe such a broad topic like reactive extensions in a few sentences. But the observable/subscriber pattern is the most fundamental piece so a basic understanding will make it easier to follow along with the code we're about to write.
Some interesting code
Our app is so simple it's really just the single screen shown in the gif above. Users are challenged to pick the correct definition of the featured word within 10 seconds. Looking at the code you'll see this view is powered by the WordPickViewModel.cs
Looking at its constructor, we can see there's a fair bit happening here.
public WordPickViewModel(IWordRepository wordRepository)
{
_wordRepository = wordRepository;
WordOptions = new ObservableCollection();
CorrectPct = "0%";
var canRetrieve = this.WhenAnyValue(x => x.CanRetrieve).Select(x => x);
var canSelect = this.WhenAnyValue(x => x.CanRetrieve).Select(x => !x);
RetrieveWordCommand = ReactiveCommand.CreateAsyncTask(canRetrieve, async arg =>
{
var wordResults = await _wordRepository.GetWords(_rangeFloor,RangeCeiling);
return wordResults.Select(wr =>
new WordOption
{
Word = wr.Name,
Definition = wr.Definition,
WordId = wr.Id
}).ToList();
});
SelectAnswerCommand = ReactiveCommand.CreateAsyncTask(canSelect,async arg =>
{
await HandleItemSelectedAsync(arg);
});
RetrieveWordCommand
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(wordOptions =>
{
_timerCancellationToken = new CancellationTokenSource();
NextRange();
CanRetrieve = false;
WordOptions.Clear();
// randomly determine the word to challenge user with
var rand = new Random();
var challengeWord = wordOptions[rand.Next(wordOptions.Count)];
ChallengeWord = $"\"{challengeWord.Word}\"";
foreach (var item in wordOptions)
{
var isAnswer = item.WordId == challengeWord.WordId;
item.IsAnswer = isAnswer;
item.Image = isAnswer ? "check.png" : "x.png";
WordOptions.Add(item);
}
TimerCountdown = 10;
Device.StartTimer(new TimeSpan(0, 0, 1), () =>
{
if (_timerCancellationToken.IsCancellationRequested)
{
return false;
}
if (TimerCountdown == 0)
{
ProcessAnswer();
return false;
}
TimerCountdown--;
return true;
});
});
//Behaviors
this.WhenAnyValue(x => x.Begin).InvokeCommand(RetrieveWordCommand);
}
In fact, this is one of the biggest differences I noticed as I started exploring reactive programming. In MVVM, reactive is largely about describing relationships between data properties and adding bits of functional code to react to changes on those properties. As a result, a lot of the declarations for observables, subscribers, events and property changes are done in the constructor. If your requirements involve more heavy-duty logic used within your reactive components that code should be encapsulated in separate classes to keep things loosely coupled and testable. Our app is really small and simple so code for both my reactive declarations and actual functionality is contained in the view model.
Commands as observables
ReactiveUI offers a very rich command api which lets us bind our UI elements to functionality in our view model and do some powerful things. Thinking about our app, the most important command we need is the one to fetch new word definitions from our database when the user taps the "New Word" button. This is handled by the RetrieveWordCommand:
RetrieveWordCommand = ReactiveCommand.CreateAsyncTask(canRetrieve, async arg =>
{
var wordResults = await _wordRepository.GetWords(_rangeFloor,RangeCeiling);
return wordResults.Select(wr =>
new WordOption
{
Word = wr.Name,
Definition = wr.Definition,
WordId = wr.Id
}).ToList();
});
Pretty simple stuff here, we make a call to our repository to fetch and return a new list of words - cool. What's even cooler is that reactive commands are also observables meaning they return an observable of the result and not the result itself. This behavior makes them inherently asynchronous so while we do some IO or CPU-bound work our UI can respond accordingly once the task completes without blocking the main thread.
In our app, once we're done fetching some word definitions from our database we do some additional work to pick our target word, set up our view objects and start the countdown timer.
RetrieveWordCommand
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(wordOptions =>
{
_timerCancellationToken = new CancellationTokenSource();
NextRange();
CanRetrieve = false;
WordOptions.Clear();
// randomly determine the word to challenge user with
var rand = new Random();
var challengeWord = wordOptions[rand.Next(wordOptions.Count)];
ChallengeWord = $"\"{challengeWord.Word}\"";
foreach (var item in wordOptions)
{
var isAnswer = item.WordId == challengeWord.WordId;
item.IsAnswer = isAnswer;
item.Image = isAnswer ? "check.png" : "x.png";
WordOptions.Add(item);
}
TimerCountdown = 10;
Device.StartTimer(new TimeSpan(0, 0, 1), () =>
{
if (_timerCancellationToken.IsCancellationRequested)
{
return false;
}
if (TimerCountdown == 0)
{
ProcessAnswer();
return false;
}
TimerCountdown--;
return true;
});
});
Binding stuff
ReactiveUI offers a rich binding api that makes connecting our view model and UI elements very easy. In the code-behind for WordPickPage.xaml.cs you can see the data and command bindings in the OnAppearing() method.
...
//This is a one-way bind
this.OneWayBind(ViewModel, x => x.WordCount, c => c._wordCountBadge.Text).DisposeWith(_bindingsDisposable);
//This is a command binding
this.BindCommand(ViewModel, x => x.RetrieveWordCommand, c => c._nextWord).DisposeWith(_bindingsDisposable);
...
Another powerful tidbit related to commands is the CanExecute property. These are observables that perform a state check of our data to determine whether or not a command can run.
We use a couple of these checks to determine the proper states for our app to retrieve words and allow the user to select a definition. Both of these rely on the WhenAnyValue()
method which is again another thing that returns an observable (surprise!) and something I think of as being similar to INotifyPropertyChanged.
...
var canRetrieve = this.WhenAnyValue(x => x.CanRetrieve).Select(x => x);
var canSelect = this.WhenAnyValue(x => x.CanRetrieve).Select(x => !x);
...
Summary
Reactive programming is a deep topic and we're really just scratching the surface here. There are many important aspects I haven't covered here but some key points I hope you can take away are:
- Observables are the lifeblood of reactive applications and provide streams of data and events with which we can subscribe to and perform any number of additional actions on.
- In MVVM, commands are really important and ReactiveUI has a rich api with helper methods to keep our command-related code clean and concise.
- Reactive syntax is fluent and composable. At first sight, I've found it's often pretty easy to reason about the intent of reactive code and the composability of the extensions makes chaining together super-powerful bits of functionality almost too easy.
- Reactive isn't a be-all-end-all strategy. Carefully consider your functional and usability requirements when determining whether or not reactive is the right approach for your next project. If you're implementing traditional CRUD-based line-of-business apps chances are reactive likely won't offer you much. If you're dealing with real-time, streaming data and/or need to deliver a highly interactive user interface there's a good chance you can leverage reactive extensions to deliver a rich and performant experience for your users.
References
Source code
Thanks for reading!
Get notified on new posts
Straight from me, no spam, no bullshit. Frequent, helpful, email-only content.
Get notified on new posts
Straight from me, no spam, no bullshit. Frequent, helpful, email-only content.