Consumir datos de un Servicio OData desde Android usando MonoDroid/Xamarin/C#

octubre 25, 2013
By

OData es cada vez más popular como protocolo para publicar datos en la Web. Muchos sitios y proveedores de datos han implementado Servicios OData para permitir el acceso a sus datos basado en REST. OData surgió como una variante del protoco AtomPub basado en XML, pero es posible también consumir los datos en formato JSON, lo cual facilita su uso desde aplicaciones clientes ligeras, como puede ser una aplicación en una navegador usando JavaScript o una aplicación móvil multiplataforma. Por otra parte, implementar una Servicio OData es una tarea relativamente simple si se usan las facilidades que brinda la plataforma .NET.

Este artículo presenta una alternativa para consumir datos a través de un Servicio OData desde una aplicación Android desarrollada con MonoDroid. Xamarin es el entorno de desarrollo que permite crear aplicaciones .NET para Android usando MonoDroid y C#. Antes de comenzar es necesario configurar el entorno de trabajo para desarrollar aplicaciones móviles con MonoDroid y Xamarin. Para consumir los datos publicados vía OData usaremos la biblioteca de clases .NET RestSharp y para acceder a los datos que devuelve el servicio en formato JSON usaremos la biblioteca JSON.NET. Para el propósito de este artículo usaremos el servicio http://services.odata.org/V3/OData/OData.svc/ que se basa en la versión 3 del protocolo OData. Antes de comenzar con el desarrollo de la aplicación Android, se pueden consultar los datos que brinda este servicio a través de un navegador, o cualquier cliente OData, para tener una idea de la información que estaremos manejando.

Para comenzar creamos en Xamarin (puede usarse también Visual Studio 2012, aunque se han reportado algunos bugs con el plugin de Xamarin para Visual Studio) un proyecto de tipo “Android Application”.

Xamarin Android Application New Project Dialog

Luego añadimos las referencias a RestSharp (RestSharp.MonoDroid.dll)  y JSON.NET (Newtonsoft.Json.dll). Seguidamente vamos al código de la clase de la actividad principal (MainActivity.cs) y en lugar de heredar de Activity vamos a heredar de ListActivity. En esta pantalla principal se van a cargar todas la entidades expuestas por el servicio OData, y al heredar de ListActivity automáticamente tenemos disponible una propiedad ListAdapter para cargar en ella los datos que se van a mostrar, sin necesitar añadir ningún control a la vista, aunque esta sería también una alternativa válida.

Utilizar la biblioteca RestSharp para acceder al servicio tiene varias ventajas, entre ellas la simplicidad y la posibilidad de hacer el pedido de forma asíncrona, es decir sin bloquear la interfaz visual para esperar por los datos. Para ello se debe inicializar primeramente una instancia de la clase RestClient usando la URL del servicio OData. Luego, se inicia el pedido de forma asíncrona y se provee un delegado encargado de procesar los datos, cuando se reciben del servicio. Esta lógica la ubicamos dentro del método OnCreate de la clase MainActivity.

[Activity (Label = "OData Demo", MainLauncher = true)]
public class MainActivity : ListActivity
{
  private readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
  private RestClient restClient;
  List<string> entities = new List<string>();
  private void StartRestRequestAsync()
  {
    Task.Factory.StartNew(() => {
      var request = new RestRequest("/?$format=json");
      request.RequestFormat = DataFormat.Json;
      return this.restClient.Execute(request);
    })
    .ContinueWith(t => {
      var obj = Newtonsoft.Json.Linq.JObject.Parse(t.Result.Content);
      var results = obj["

value

"];
      foreach (var item in results)
        entities.Add(item.ToString());
      ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, entities);
    }, uiScheduler);
  }
  protected override void OnCreate (Bundle bundle)
  {
    base.OnCreate (bundle);
    restClient = new RestClient("http://services.odata.org/V3/OData/OData.svc/");
    StartRestRequestAsync();
  }
}

El delegado que se define mediante una expresión lambda en el método ContinueWith es el encargado de procesar los datos devueltos por el servicio. Para interpretar los datos en formato JSON se ha usado la clase JObject de la biblioteca JSON.NET para convertir el string resultante en un objeto al que luego se pueden acceder a sus propiedad usando la notación de indexers. Por último se cargan los nombres de las entidades en una lista y se asignan a la propiedad ListAdapter mediante una instancia de ArrayAdapter. Si se ejecuta la aplicación en este punto (en el emulador o en un teléfono real) se debe otener la lista de entidades expuesta por el servicio OData.

image

Seguidamente vamos a crear una nueva actividad para visualizar los elementos de cada tipo de entidad, de modo que seleccionar una entidad en la vista principal, se carguen los datos de esa entidad en la vista secundaria. Para ello añadimos al proyecto una nueva actividad que llamaremos EntityDetails. También hacemos heredar esta clase de ListActivity para asociar a la propiedad ListAdapter la lista de elementos devueltos por el servicio. Para mostrar la vista EntityDetails cuando se seleccione una entidad de la vista principal, añadimos a la clase MainActivity un manejador para el evento OnListItemClick que se encargará de iniciar la actividad EntityDetails y pasarle información sobre la entida seleccionada, para luego cargar los datos del servicio.

protected override void OnListItemClick(ListView l, View v, int position, long id)
{
  var resource = entities[position];
  var detailsActivity = new Intent (this, typeof(EntityDetails));
  detailsActivity.PutExtra ("EntityName", resource);
  StartActivity (detailsActivity);
}

En el código anterior se le pasa como parámetro a la actividad EntityDetails, el nombre de la entidad, para luego construir la URL adicionando este valor. Esto se logra a través del objeto Intent que luego se utiliza para iniciar la actividad. Luego, el código de la clase que representa la actividad EntityDetails quedaría como sigue:

[Activity (Label = "Entity List")]
public class EntityDetails : ListActivity
{
private readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
 private RestClient restClient;
  List<string> questions = new List<string>();
 private string entityName;

 private void StartRestRequestAsync()
  {
	Task.Factory.StartNew(() => {
		var request = new RestRequest(entityName);
		request.RequestFormat = DataFormat.Json;
		return this.restClient.Execute(request);
	})
	.ContinueWith(t => {
		var obj = Newtonsoft.Json.Linq.JObject.Parse(t.Result.Content);
		var results = obj["value"];
		foreach (var q in results) {
			questions.Add(q["Name"].ToString());
		}
		ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, questions);
	}, uiScheduler);
  }

 protected override void OnCreate (Bundle bundle)
  {
	base.OnCreate (bundle);
	entityName = Intent.GetStringExtra ("EntityName");
	this.Title = entityName;
	restClient = new RestClient ("http://services.odata.org/V3/OData/OData.svc/");
	StartRestRequestAsync ();
  }
}

Al ejecutar la aplicación, si se selecciona Products en la pantalla principal, debe mostrarse una vista similar a la siguiente figura.

image

En este artículo se ha mostrado una forma simple y efectiva de consumir datos desde un servicio OData, usando MonoDroid, Xamarin y C# para crear una aplicación Android. Además se ha mostrado cómo pasar información de una actividad a otra mediante el tipo Intent. La ventaja de OData es que facilita el autodescubrimiento de la información, por lo que pueden crearse aplicaciones basadas en este protcolo sin necesitar conocer los detalles de un esquema de datos subyacente. Se propone al lector crear una tercera actividad donde se muestren los detalles de cada elemento, al seleccionarlos en la vista de EntityDetails. Note que aunque cada tipo de elemento tiene propiedades diferentes, es posible crear una actividad genérica que muestre los valores que vienen como un objeto JSON, que puede explorarse usando la biblioteca JSON.NET.

Descargar código fuente del proyecto de ejemplo

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Acerca del autor...

Lester Sánchez

Web: http://www.linkedin.com/in/lestersanchez
Lester Sánchez
Profesor de la Facultad de Matemática y Computación de la Universidad de La Habana. Entusiasta de las tecnologías .NET y en especial de SharePoint. Webmaster de weboomania.comLeer completo