Desarrollando Android #4 Parseando un XML
Ahora toca una parte muy importante de el proyecto: parsear un XML. Según lo definido inicialmente, la gracia de toda esta aplicación es que yo recibiré un archivo .xml y a partir de aquí mostraré en el mapa las posiciones. Para ello, vamos a parsear este archivo primero y luego vamos a utilizar los datos para insertar marcadores en nuestro mapa.
Parsear un XML
Antes de nada, qué significa «parsear». El parseo es un proceso de análisis y posterior transformación de un bloque en un lenguaje/estructura determinada en otro bloqueo de lenguaje/estructura diferente. Básicamente lo que quiero es que mi programa sepa entender el archivo que le paso, y me detecte lo que son posiciones geográficas, lo que son títulos o el indicador de si está libre o no un parking. Así que, antes de nada, he creado un archivo .xml que alamcena posiciones de parkings:
Parking UPC
41.387179
2.1125849
1
Parking Casa Adri
41.3845864
2.1392143
1
Parking Palau Reial
41.38575629197152
2.1175289154052734
0
Parking Liceo Frances
41.392059
2.117139
0
Este archivo no es nada más que un conjunto de objetos
Paso 1: La classe de objetos
El objetivo final del parseo es obtener una serie de objetos en el formato que queramos. Como yo quiero obtener parkings con los cuatro atributos mencionados anteriormente, lo primero que hay que hacer es crear la classe ParkingMarker:
Paso 2: El Handler
A medida que se parsea un documento se van produciendo eventos que se han de tratar. Estos eventos indican por ejemplo que se ha acabado una etiquetao que has llegado al final del documento entre otros. Los principales eventos son:
- startDocument(): comienza el documento XML.
- endDocument(): termina el documento XML.
- startElement(): comienza una etiqueta XML.
- endElement(): termina una etiqueta XML.
- characters(): fragmento de texto.
Así pues en nuestro código vamos a tratar todos ellos
Analicemos con detalle lo que hemos hecho. Primero hemos definido una lista de objetos parkings, un objeto parking y un objeto sbText. Este último sirve para ir almacenando el texto que se recupera del parseador. En el startDocument, tan solo hay que instanciar los dos tipos de objeto y en startElement decimos que si nos encontramos con la etiqueta <parking> significa que empieza un nuevo objeto. La función characters tan solo va acumulando el texto para luego tratarlo. Y la gracia de todo está en el endElement. Aquí definimos qué hay que hacer cuando llegas al final de un elemento. He definido en mi caso las siguientes situaciones:
- Si estaba en la etiqueta
, almacena el contenido en el apartado name del ParkingMarker. - Si estaba en una de las etiquetas de
o que lo almacene en su campo correspondiente - Si estaba en el campo
, que recoja el valor y si es un «1» entonces asignaremos el valor de TRUE al campo y FALSE si es el caso contrario. - He añadido un caso en el que si no viene ni un «1» o un «0» que indique que ha habido error en el parseo.
Paso 3. El Parser
Y finalmente el parseador. Esta clase recibe una URL con el XML y empieza a Parsearlo utilizando el ParkingHandler que hemos creado anteriormente.
Insertando el Parseador al proyecto y añadiendo puntos al mapa
Aquí hay un tema delicado que he aprendido a base de prueba y error. Desde la versión 3 de Android, no se permite a las aplicaciones ejecutar operaciones de larga duración en el hilo principal que puedan bloquear temporalmente la interfaz de usuario. Así pues, hay que crear una llamada asíncrona que lo hará en segundo plano. En resumen, lo que toca hacer ahora es lo siguiente. En el método onCreate añadimos las siguientes líneas:
RetrieveFeed task = new RetrieveFeed();
task.execute("https://dl.dropboxusercontent.com/u/123539/parkingpositions.xml");
Y al final de la MainActivity.java, justo antes de cerrarla creamos una clase que extienda AsyncTask Analicemos también con más detalle lo que pasa aquí. En el primer método doInBackground definimos lo que se realiza en segundo plano. En nuestro caso es crear un nuevo parseador con la URL dada y ejectuarlo. Y en onPostExecute ponemos lo que se ha de hacer a continuación: tratamos la lista y para cada elemento (parking) de ella
- recuperamos la latitud y la longitud
- si el parking está libre definimos el color verde y si está ocupado el color rojo
- finalmente añadimos un marcador en la posición recuperada, con el nombre (también recuperado) por título y el icono de un color u otro según su estado.
Como véis, no es excesivamente complicado pero os puedo asegurar que me estuve horas y horas para conseguir que funcionase. Ahora ya lo tenéis todo bien puesto y funcionando a la perfección.
Podéis ver el código del proyecto en gitHub
Ahora tenemos: Una aplicación que parsea un XML con posiciones y añade marcadores para cada una de ellas en un mapa. En la próxima sesión: Dividir la pantalla en dos, peripecias.