Introducción a ReactiveUI con Xamarin.Forms - Parte 1

Intro

Después de mi último post sobre Xamarin.Forms y Mvvm he decido crear uno nuevo sobre uno de los frameworks de Mvvm que más me gustan: ReactiveUI.

El desarrollo frontend es bastante complejo porque tenemos que lidiar con eventos, acciones de un usuario que no podemos prever de antemano.

Por mucho que intentes hacer una buena arquitectura desde el principio, si las necesidades del proyecto no te permiten hacer un refactoring apropiado, tus ViewModels pueden terminar siendo dificiles de gestionar.

ReactiveUI permite mantener un código limpio y testeable al mismo tiempo que implementamos funcionalidades complejas.

Functional Reactive Programming

ReactiveUI está basado en los principios de Functional Reactive Programming. Los principios fundamentales de FRP son los siguientes:

Para que todo esto sea posible FRP necesita Signals a los cuales nos podremos subscribir y reaccionar a estos dependiendo de las condiciones que nos aportan.

Para terminar de entender estos conceptos básicos de FRP es mejor utilizar un ejemplo: FRP example Como véis, lo primero que hacemos es indicar al sistema que hacer cuando se produzcan cambios. Definimos nuestra regla a través de una función que indica que C es la suma de A y B. Como véis una vez definidas las reglas dejamos al sistema que reaccione a las acciones del usuario.

Reactive Extensions

Reactive Extensions

Se trata de otro de los pilares en los que sustenta ReactiveUI. Tal y como hemos indicado FRP necesita de Signals para poder reaccionar a los cambios.

Reactive Extensions proporciona herramientas para construir programas asíncronos y basados en eventos, y la clave es la interfaz IObservable<T>. Con ReactiveX podemos observar los eventos que va generando un usuario en nuestra intefaz, podemos incluso filtrarlos, y reaccionar a una determinada combinación de los mismos.

No es la intención de este post explicar exactamente como funciona ReactiveX. Si queréis una buena introducción a los mismos, podéis echar un ojo a la siguiente serie de posts.

¿Qué es ReactiveUI?

ReactiveUI

Se trata de un framework MVVM que utiliza ReactiveX dando lugar a un código elegante y testeable. Su objetivo final es hacer código entendible por humanos que da la casualidad que una máquina puede compilar.

Es compatible con otros frameworks como Xamarin.Forms, MvvmCross, etc y está disponible en todas las tecnologías de UI de .Net: Xamarin, UWP, WPF, etc.

Como sabéis un framework MVVM tiene que implementar la interfaz INotifyPropertyChanged. Lo que crea esta interfaz no es más que un evento entre nuestro ViewModel y la Vista, y tal y como hemos dicho anteriormente los eventos se pueden observar a través de Observablesque proporcionan ReactiveX.

Esa es la clave de ReactiveUI. ¿Porqué no observar los eventos que lanzan nuestros ViewModels a la Vista y viceversa y reaccionar a ellos con una seríe de reglas definidas?

ViewModels

Para poder empezar a utilizar ReactiveUI nuestros ViewModels deben de heredar de ReactiveObject el cual implementa por nosotros la interfaz INotifyPropertyChanged.

Otra de las características de ReactiveUI es que la inicialización de nuestras propiedades y Commandsse realiza en el constructor de los ViewModels.

WhenAny / WhenAnyValue

Permiten observar cambios en las propiedades de nuestro ViewModel, es decir, crearemos un Observable que capture los eventos de cambio de una propiedad de nuestro ViewModel. Lo mejor para entederlos en ver como se utilizan:

// in the viewmodel
this.WhenAnyValue(x => x.SearchText)
    .Where(x => !String.IsNullOrWhiteSpace(x))
    .Throttle(TimeSpan.FromSeconds(.25))
    .InvokeCommand(SearchCommand)

Vamos a ir viendo sentencia a sentencia para entender que estamos definiendo en este ejemplo:

Como véis con 4 lineas de código hemos definido el comportamiento por ejemplo del serach bar de Google, que nos va mostrando sugerencias conforme escribimos. ¿Os imagináis como sería representar la misma lógica con el patrón tradicional de MVVM? Pues serían bastantes más lineas de código, eso seguro.

Propiedades

Existen tres tipos de propiedades que podemos utilizar en nuestros ViewModels en ReactiveUI. Veamos cuales son y cuando en combeniente utilizarlas en cada caso:

Read-Write properties

Se trata de una propiedad que lanza un evento cada vez que es actualizada con un valor nuevo:

string name;
public string Name {
    get { return name; }
    set { this.RaiseAndSetIfChanged(ref name, value); }
}

Read-Only properties

Como los Commands debemos de inicializarlos siempre en el constructor de nuestro ViewModel, es un buen candidato para este tipo de propiedad:

public ReactiveCommand<Object> PostTweet 
{ 
    get; 
    protected set; 
}

Output properties

Este es un nuevo tipo de propiedad que no existe en otros frameworks de MVVM. Se trata de una propiedad que solo puede ser informada por un Observable. Veamos como se define y se utiliza:

protected ObservableAsPropertyHelper<bool> _IsLoading;
public bool IsLoading
{
    get { return _IsLoading.Value; }
}

this.SearchCharacters.IsExecuting
	.ToProperty(this, x => x.IsLoading, out _IsLoading);

Como véis un flag que indica que se está ejecutando una búsqueda es perfecto para este tipo de propiedades. Fijaos que sencillo es indicar a nuestra vista que tiene que mostrar un ActivityIndicator.

ReactiveCommand

Es el tipo de Command que utilizaremos en ReactiveUI. Son el candidato perfecto para ser declarados como Read-Onlyproperties y se utilizan de la siguiente forma:

public ReactiveCommand SearchCharacters { get; protected set; }

this.SearchCharacters = ReactiveCommand
    .CreateFromTask<string>((text) => LoadData(text));

ReactiveCommand Handle Exceptions

El manejo de excepciones en ReactiveCommand lo realizaremos a través de ThrownExceptions. Así se utiliza:

// Handle erros
this.SearchCharacters.ThrownExceptions
    .Subscribe ((obj) => this.LogException(obj, "Error while getting Marvel characters"));

ReactiveCommand IsExecuting

Otra de las características que oferce ReactiveCommand es poder definir un comportamiento mientras un Command se encuentra en ejecución. Para esto utlizamos IsExecuting:

// Loading flag
this.SearchCharacters.IsExecuting
	.ToProperty(this, x => x.IsLoading, out _IsLoading);

Hemos cubierto el comportamiento básico que deben tener nuestros ViewModels con ReactiveUI. Veamos ahora los Bindings con nuestras vistas.

Binding

El Binding en ReactiveUI se realiza en el code-behind de nuestra Vista. Se que esto no les gustará demasiado a los amantes de XAML, pero tiene ciertas ventajas hacerlo así:

Los tipos de Bindings en ReactiveUI son los siguientes:

OneWayBinding

var disp = this.OneWayBind(ViewModel, x => x.Name, x => x.Name.Text);

TwoWay-Binding

this.Bind(ViewModel, x => x.Name, x => x.Name.Text);

BindCommand

this.BindCommand(ViewModel, x => x.OkCommand, x => x.OkButton);

Una de las cosas de este tipo de Binding a través de expresiones, es que no hace falta que creemos Converters, sino que podemos indicar la conversión de nuestro Binding, con una acción adicional:

// Binding with a converter
this.OneWayBind(ViewModel,
                vm => vm.Thumbnail,
                cell => cell.imageThumbnail.Source,
                (string arg) => ImageSource.FromUri(new Uri(arg)));

En este ejemplo estamos transformando la url de una imagen en un ImageSource de una imagen en Xamarin.Forms, con una simple expresión sin necesidad de crear una nueva clase, crear una recurso estático en nuestro archivo XAML e indicar su uso cuando asignamos el Binding.

WhenActivated

Como ya sabemos una de las principales causas de Memmry leaks durante el desarrollo de una app, son los eventos que quedan vivos entre dos objetos. ReactiveUI implementa una variante del patrón IDisposable que nos ayudará a que nuestros Bindings no generen Memory leaks haciendo uso del método WhenActivated:

this.WhenActivated((CompositeDisposable disposables) =>
{
    // Binding with a converter
    this.OneWayBind(ViewModel,
                    vm => vm.Thumbnail,
                    cell => cell.imageThumbnail.Source,
                    (string arg) => ImageSource.FromUri(new Uri(arg)))
        .DisposeWith(disposables);
    
    this.OneWayBind(ViewModel, 
                    vm => vm.Name, 
                    cell => cell.textName.Text)
        .DisposeWith(disposables);
});

Como véis cada uno de los Bindings es incluido en una colección CompositeDisposable. Eso nos asegura que cuando el GC se ejecute sepa de antemano que los Bindings pueden ser liberados en memoría.

Conclusión Parte 1

Hasta aquí los conceptos básicos de ReactiveUI necesarios para afrontar el desarrollo de una app con Xamarin.Forms. En el siguiente post veremos como integrar ReactiveUI con nuestra app revisando conceptos como el Routing, ReactiveList, etc.

Os dejo a continuación una seríe de recursos por si queréis seguir apliando conocimientos:

Share

Comments