XAMARIN.FORMS + CLEAN ARCHITECTURE + RX.NET

Gonzalo Martin – febrero 8, 2018

Categories: AgileAutomotiveCommunicationsConsumer and RetailFinancial ServicesHealthcareManufacturing and IndustrialMediaTechnology

These days, ReactiveX is the most popular approach to take for asynchronous programming. Focusing on mobile development, it is the best way to call to any API and manage data using Observer pattern.

Light introduction to Rx

If you already have knowledge in Rx, jump to the next section of this article.

ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.

It extends the observer pattern to support sequences of data and/or events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O.

If you want to learn more about Rx, please check this post:

Observer’s implementation

One of the types more used is Observable. Then that observer reacts to whatever item or sequence of items the Observable emits. This pattern facilitates concurrent operations because it does not need to block while waiting for the Observable to emit objects, but instead it creates a sentry in the form of an observer that stands ready to react appropriately at whatever future time the Observable does so.

The Subscribe method is how you connect an observer to an Observable. Your observer implements some subset of the following methods:

  • onNext: An Observable calls this method whenever the Observable emits an item. This method takes as a parameter the item emitted by the Observable.
  • onError: An Observable calls this method to indicate that it has failed to generate the expected data or has encountered some other error. It will not make further calls to onNext or onCompleted. This method takes as its parameter an indication of what caused the error.
  • onCompleted: An Observable calls this method after it has called onNextfor the final time, if it has not encountered any errors.

Defining project structure

First of all, I want to share with you a basic project structure, taken from Android pattern:

Project structure

This structure has three folders that include all functionality

  • Data: contains the access to repositories, like databases, api calls, cache, entity. Also, includes the mappers to transform an entity to a model class
  • Domain: contains the business model, the use cases and expose the repositories (as interfaces)
  • Presentation: this is the UI. This contains the views and viewmodel or presenter classes (depending of the chosen pattern)

The communication flow should be:

Presentation <-> Domain <-> Data

Integrating Rx.NET in Xamarin

Up to here, we have learned about Rx in general. Now, we will focus in how we can implement this in Xamarin. For do that, we will need add Rx.NET plugin to our project (and all referenced projects)

Let’s think in a basic app that populates a data in a list view. So, the first step is call from our UI to retrieve data. I’ll base in a sample that shows a list of cities.

We call to our Presenter to retrieve the data

 void UpdateData(bool forced)
{
UpdateViewState(ViewState.Loading);
Presenter.LoadCities(forced);
}

Then, from our Presenter we need to call to our use case

public void LoadCities(bool forced)
{
var useCache = !forced;
UseCase.Execute(new CityListObserver { Presenter = this}, new Params { UseCache = useCache });

View.OnLoadingStart();
}

Keep in mind, we need to provide an Observer to listen any changes on data.

class CityListObserver : DefaultObserver<List<City>>
{
public CityPresenter Presenter { get; set; }

public override void OnCompleted()
{
// Do nothing for now…
}

public override void OnError(Exception error)
{
if (error.InnerException is HttpRequestException && !App.IsNetworkAvailable())
{
Presenter.View.OnNetworkDisabledError();
}
else
{
Presenter.View.RenderError(error);
}
}

public override void OnNext(List<City> value)
{
Presenter.View.Render(value);
}
}

So, the next step is our Use Case. This will call to repositories

public class GetAllCitiesUseCase : UseCase<List<City>, Params>
{
ICityRepository Repository = new CityRepository();

public override IObservable<List<City>> BuildUseCaseObservable(Params param)
{
return Repository.Cities(param.UseCache);
}
}

public class Params
{
public bool UseCache { get; set; }
}

A repository can be any datastore we have. This is the common repository class to ask to a concrete repository to retrieve the data:

public class CityRepository : ICityRepository
{
CityMapper Mapper = new CityMapper();
CityDataStoreFactory Factory = new CityDataStoreFactory();

public IObservable<List<City>> Cities(bool useCache)
{
var dataSource = Factory.Create(useCache);
var entities = dataSource.Cities();
return entities.Select(x => Mapper.TransformList(x));
}
}

In this repository, we create the concrete DataSource using a Factory. In addition, we are using the Select method to transform each elements of CityEntity list to City list, through to our Mapper. This is how we apply map operator in C#.

This is a local implementation of DataStore:

public class DiskCityDataStore : ICityDataStore
{
public ICityCache CityCache { get; set; }

public IObservable<List<CityEntity>> Cities()
{
return Observable.Create<List<CityEntity>>((emitter) =>
{
var list = CityCache.GetAll();
if (list != null)
{
emitter.OnNext(list);
emitter.OnCompleted();
}
else
{
emitter.OnError(new Exception(“Cities were not found”));
}

return () => { };
});
}
}

There, we create an Observable object from our local data.

And that is! We have created a basic flow using Rx.NET library. You can see the full sample in this repo. Feel free to contributefile issues or suggestions! Let’s make a better architecture 😉

Top Insights

Ciclos de vida BPM

Ciclos de vida BPM

AutomotiveCommunicationsConsumer and RetailFinancial ServicesHealthcareManufacturing and IndustrialMediaTechnology
Criterios de Aceptación

Criterios de Aceptación

AutomotiveCommunicationsConsumer and RetailFinancial ServicesHealthcareManufacturing and IndustrialMediaTechnology
Escribiendo User Stories en Agile

Escribiendo User Stories en Agile

AutomotiveCommunicationsConsumer and RetailFinancial ServicesHealthcareManufacturing and IndustrialMediaTechnology
What is TM Forum Frameworx and how to apply it to your business?

What is TM Forum Frameworx and how to...

UncategorizedAutomotiveCommunicationsConsumer and RetailFinancial ServicesHealthcareManufacturing and IndustrialMediaTechnology
Impact Mapping en Metodologías ágiles

Impact Mapping en Metodologías ágiles

AutomotiveCommunicationsConsumer and RetailFinancial ServicesHealthcareManufacturing and IndustrialMediaTechnology

Top Authors

Manuel Asenzo

Manuel Asenzo

Manager at GlobalLogic Latinoamérica

Rodrigo Paschetta

Rodrigo Paschetta

Manager at GlobalLogic Latinoamérica

Paola Lozada

Paola Lozada

Head of Marketing & Communications, LATAM & Mexico

Agustín Pelliza

Agustín Pelliza

Manager at Hexacta, a GlobalLogic Company

Blog Categories

  • URL copied!