Introduction to Reactive Extensions (Rx.NET)

Reactive Extensions have been around for many years, and is available to most development environments. In this post, we are specifically going to look at Rx in terms of .NET development in Xamarin Forms. Rx is just a library for composing asynchronous, and event-based code with observables, and configuring it via LINQ. Now let’s break down that sentence. You have events, you create an observable to monitor that event. You then use LINQ to define criteria of when you want to perform an action, on the event. Rx can do more, but we will only look at the very basics in this post.

Just before we continue, I want to mention RxUI. This is another library that is an MVVM framework, based off Rx. I will not be looking at RxUI in this post.

Install

Download the NuGet package, Reactive Extensions – Query Library. I also have sample code in my ReactiveExtensionsXF repository, if you want to see a working example. In version 4.0, they have consolidated everything to a single package. The example in the repository uses 4.0, and you will need to use their MyGet feed, for their nightly build.

Create an Observable

For the first scenario, lets say we have an Event in a Model, that the ViewModel needs to know about. I will also add a timer to fire this event every second, with an updated count. In a real app, this could data streaming from a service, or maybe a database updating.

public class MainModel
{
    public event EventHandler UpdatedData;
    private int _count = 0;
    public MainModel()
    {
        Device.StartTimer(TimeSpan.FromSeconds(1), () =>
        {
            UpdatedData?.Invoke(this, new DataEventArgs() { Count = _count });
            _count++;
            return true;
        });
    }
}

public class DataEventArgs : EventArgs
{
    public int Count { get; set; }
}

Now, in the ViewModel, we can create an observable to attach to the event.

public class MainViewModel
{
    private MainModel _mainModel = new MainModel();

    public MainViewModel()
    {
        var eventAsObservable = Observable.FromEventPattern(ev => _mainModel.UpdatedData += ev,
                                                            ev => _mainModel.UpdatedData -= ev);
    }
}

Subscribe to an Observable

Now that we have an observable, we can subscribe to it. In this example I am just updating a Label with the count.

eventAsObservable.Subscribe(x => { 
    LabelText = $"Count: {((DataEventArgs)x.EventArgs).Count.ToString("N0")}"; 
});

So, at this point you are most likely wondering, why did I just do that, and why not just subscribe to the event directly? This is where the power of Observables comes in, by allowing you to get events, only when it meets certain conditions.

Filtering Events

We can decide on when we want to run the code block, depending upon a set of conditions. For example, if I only want this event to be raised when the count is greater than 5, I can do this, to our existing Observable.

eventAsObservable.Where(x=>((DataEventArgs)x.EventArgs).Count) > 5);

Now the subscribe, will only run, when these conditions are met.

Throttling, is another option. This will only allow a subscription to be fired at least once every X amount of time. This is designed for data that might be coming through at irregular times and needs to be dealt with in a regular manner.

.Throttle(TimeSpan.FromSeconds(2));

Lifecycle

To avoid memory leaks, you need to make sure you dispose of the subscription, to unsubscribe from observables when no longer necessary. When you initially subscribe to an observable, you can assign this to a variable. You can then dispose of this object, when you are finished with it.

var subscription = eventAsObservable.Subscribe( .... );

// To dispose of the subscription
subscription.Dispose();

Learn More

There are many more LINQ style conditions you can add to Observables, such as Delay, Timeout and Buffer. Now that you hopefully have a good basic understanding of Rx, Rx 101 Samples  is a great site to learn many different examples. The Rx.NET GitHub Readme, and Introduction to Rx, also has more information.


XAMARIN.FORMS MONTHLY NEWSLETTER

JOIN 1,200+ SUBSCRIBERS

  1. Don't miss out on updates
  2. The latest info from this site, Xamarin and the community
  3. Unsubscribe at any time*

* We use MailChimp, with double opt-in, and instant unsubscribe

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer |
Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts

6 Comments

  1. Clay McKinney

    Is “Reactive Extensions” singular or plural? In the first sentence you have it both ways.

    1. Adam Pedley

      Reactive Extensions are plural in the context of many extensions, but singular in the context of a package. Which a slight disclaimer there, the Rx.NET packages are currently several but Version 4.0 is consolidating them into a single package.

  2. Hugo Tessaro

    Nice, here is my snippet when I want to make a search entry:

    Observable
    .FromEventPattern<EventHandler, TextChangedEventArgs>(
    x => entry.TextChanged += x,
    x => entry.TextChanged -= x
    )
    .Throttle(TimeSpan.FromMilliseconds(300), TaskPoolScheduler.Default)
    .Select(args => args.EventArgs.NewTextValue)
    .ObserveOn(SynchronizationContext.Current)
    .Subscribe(text => MyFilteringCommand());

  3. Bhupesh Sharma

    Hi,

    Is there any necessity to Unsubscribe from observables?? because as far as I know as know about the life cycle of any activity the OnDestroy() is the final method that is called on an Activity instance before it’s destroyed and completely removed from memory.

    1. Adam Pedley

      You can dispose of them, when you need to. That may be when the ViewModel is destroyed or upon some other event. Or, if the VM is never destroyed, then there is no point in disposing of it.

      The note on disposing, is just to remind developers to clean up, if they no longer need to use it, as otherwise it will cause a memory leak.

      Just think of observables as events, and how you need to remove the reference to them, when you are cleaning up.