Está en la página 1de 156

Desarrollo en Android

Conceptos Generales
1. 2. 3. 4.

Entorno de desarrollo Android Estructura de un proyecto Android Componentes de una aplicacin Android Desarrollando una aplicacin Android sencilla

Interfaz de Usuario en Android


1. Interfaz de usuario en Android: Layouts 2. Interfaz de usuario en Android: Controles bsicos (I) 3. Interfaz de usuario en Android: Controles bsicos (II) 4. Interfaz de usuario en Android: Controles bsicos (III) 5. Interfaz de usuario en Android: Controles de seleccin (I) 6. Interfaz de usuario en Android: Controles de seleccin (II) 7. Interfaz de usuario en Android: Controles de seleccin (III) 8. Interfaz de usuario en Android: Controles de seleccin (IV) 9. Interfaz de usuario en Android: Controles personalizados (I) 10. Interfaz de usuario en Android: Controles personalizados (II) 11. Interfaz de usuario en Android: Controles personalizados (III)

Mens en Android
1. 2.

en!s en Android (I): en!s y "ubmen!s bsicos en!s en Android (II): en!s Conte#tuales

Widgets en Android
1. Interfaz de usuario en Android: $id%ets (I) 2. Interfaz de usuario en Android: $id%ets (II)

Gestin de Preferencias en Android


1. &referencias en Android I: "'ared&references

Tratamiento de XML en Android


1. 2. 3. 4.

(ratamiento de ) (ratamiento de ) (ratamiento de ) (ratamiento de )

L en Android (I): "A) L en Android (II): "A) simplicado L en Android (III): D* L en Android (IV): )ml&ull

http://www.sgoliver.net/ log/!p"1313 #$gina 1 de 156

Desarrollo en Android

ases de !atos en Android


1. +ases de datos en Android (I): &rimeros pasos con ",Lite 2. +ases de datos en Android (II): Insercin- actualizacin y eliminacin de re%istros 3. +ases de datos en Android (III): Consulta y recuperacin de re%istros

Localizacin Geogr"fica en Android


1. Localizacin %eo%rfica en Android (I) 2. Localizacin %eo%rfica en Android (II)

!epuracin de aplicaciones en Android


1. Depuracin en Android: Lo%%in%

http://www.sgoliver.net/ log/!p"1313 #$gina 2 de 156

Desarrollo en Android

#ntorno de desarrollo Android


A partir de a'ora .oy a publicar tambi/n al%unos art0culos sobre desarrollo paar la plataforma Android1 2 para empezar- .oy a describir los pasos bsicos para disponer en nuestro &C del entorno y las 'erramientas necesarias para comenzar a pro%ramar aplicaciones Android1 3o .oy a ser e#'austi.o- ya e#isten muy buenos tutoriales sobre la instalacin de Eclipse y Android- incluida al documentacin oficial de la plataforma1 Adems- si 'as lle%ado 'asta este blo% 4uiero suponer 4ue tienes unos conocimientos bsicos de Eclipse y 5a.a- por lo 4ue tan slo enumerar/ los pasos necesarios de instalacin y confi%uracin- y proporcionar/ los enlaces a las distintas 'erramientas1 Vamos all1 Paso $% !escarga e instalacin de #clipse% "i a!n no tienes instalado Eclipse- puedes descar%ar la .ersin 617 desde este enlace (*8o- la .ersin 619 parece 4ue a!n no se lle.a muy bien con Android)1 :ecomiendo descar%ar por e8emplo la .ersin Eclipse IDE for Java Developers1 La instalacin consiste simplemente en descomprimir el zip en la ubicacin deseada1 Paso &% !escargar el '!( de Android% El "D; de la plataforma Android se puede descar%ar desde a4u01 <na .ez descar%ado- de nue.o bastar con descomprimir el zip en cual4uier ubicacin1 Paso )% !escargar el plugin Android para #clipse% =oo%le pone a disposicin de los desarrolladores un plu%in para Eclipse llamado Android Development Tools (AD() 4ue facilita en %ran medida el desarrollo de aplicaciones para la plataforma1 &od/is descar%arlo mediante las opciones de actualizacin de Eclipse- accediendo al men! >Help / Install new software? e indicando la <:L de descar%a >'ttps:@@dlA ssl1%oo%le1com@android@eclipse@?1 "e debe seleccionar e instalar el pa4uete completo Developer Tools- formado por Android DDMS y Android Development Tools1

http://www.sgoliver.net/ log/!p"1313 #$gina 3 de 156

Desarrollo en Android

Paso *% Configurar el plugin A!T% En la .entana de confi%uracin de Eclipse- se debe acceder a la seccin de Android e indicar la ruta en la 4ue se 'a instalado el "D; (paso B)1

Paso +% !escargar los targets necesarios% Adems del "D; de Android comentado en el paso B- tambi/n debemos descar%ar los llamados SDK Targets de Android- 4ue no son ms 4ue las librer0as necesarias para desarrollar en cada una de las .ersiones concretas de Android1 As0- si 4ueremos desarrollar por e8emplo para Android C19 tendremos 4ue descar%ar su target correspondiente1 &ara ello- desde Eclipse debemos acceder al men! >Window / Android SDK and A D Manager>- y en la seccin Availa!le "ac#ages seleccionar e instalar todos los pa4uetes deseados1

http://www.sgoliver.net/ log/!p"1313 #$gina 4 de 156

Desarrollo en Android

Paso ,% Configurar un A-!% A la 'ora de probar y depurar aplicaciones Android no tendremos 4ue 'acerlo necesariamente sobre un dispositi.o f0sico- sino 4ue podremos confi%urar un emulador o dispositi.o .irtual (Android irt$al Device- o AVD) donde poder realizar fcilmente estas tareas1 &ara ello.ol.eremos a acceder al A D Manager- y en la seccin irt$al Devices podremos aDadir tantos AVD como se necesiten (por e8emplo- confi%urados para distintas .ersiones de Android)1 &ara confi%urar el AVD tan slo tendremos 4ue indicar un nombre descripti.o- el tar%et de Android 4ue utilizar- y las caracter0sticas de 'ardEare del dispositi.o .irtual- como por e8emplo su resolucin de pantalla- el tamaDo de la tar8eta "D- o la disponibilidad de =&"1

2 con este paso ya estamos preparados para crear nuestro primer proyecto para Android1

http://www.sgoliver.net/ log/!p"1313 #$gina 5 de 156

Desarrollo en Android

Paso .% /0ola Mundo1 en Android% Creamos un nue.o proyecto de tipo Android "ro%ect1 Indicamos su nombre- el tar%et deseado- el nombre de la aplicacin- el pa4uete 8a.a por defecto para nuestras clases y el nombre de la clase (Activit&) principal1

Esta accin crear toda la estructura de carpetas necesaria para compilar un proyecto para Android1 Fablaremos de ella ms adelante1 &ara e8ecutar el proyecto tal cual podremos 'acerlo como cual4uier otro proyecto 8a.a confi%urando una nue.a entrada de tipo Android Applications en la .entana de '$n (onfig$rations1 Al e8ecutar el proyecto- se abrir un nue.o emulador Android y se car%ar automticamente nuestra aplicacin1

http://www.sgoliver.net/ log/!p"1313 #$gina 6 de 156

Desarrollo en Android

#structura de un pro2ecto Android


"e%uimos con el Curso de &ro%ramacin Android1 &ara empezar a comprender cmo se construye una aplicacin Android .amos a ec'ar un .istazo a la estructura %eneral de un proyecto tipo1 Cuando creamos un nue.o proyecto Android en Eclipse se %enera automticamente la estructura de carpetas necesaria para poder %enerar posteriormente la aplicacin1 Esta estructura ser com!n a cual4uier aplicacin- independientemente de su tamaDo y comple8idad1 En la si%uiente ima%en .emos los elementos creados inicialmente para un nue.o proyecto Android:

Describamos los elementos principales1 Carpeta 3src3 Contiene todo el cdi%o fuente de la aplicacin- cdi%o de la interfaz %rfica- clases au#iliaresetc1 Inicialmente- Eclipse crear por nosotros el cdi%o bsico de la pantalla (Activit&) principal de la aplicacin- siempre ba8o la estructura del pa4uete 8a.a definido1

http://www.sgoliver.net/ log/!p"1313 #$gina 7 de 156

Desarrollo en Android

Carpeta 3res3 Contiente todos los fic'eros de recursos necesarios para el proyecto: im%enes- .0deos- cadenas de te#to- etc1 Los diferentes tipos de recursos de debern distribuir entre las si%uientes carpetas:

/res/drawable/1 Contienen las im%enes de la aplicacin1 "e puede di.idir en /drawable-ldpi- /drawable-mdpi y @drawable-hdpi para utilizar diferentes recursos dependiendo de la resolucin del dispositi.o1 /res/layout/1 Contienen los fic'eros de definicin de las diferentes pantallas de la interfaz %rfica1 "e puede di.idir en /layout y /layout-land para definir distintos layouts dependiendo de la orientacin del dispositi.o1 /res/anim/1 Contiene la definicin de las animaciones utilizadas por la aplicacin1 /res/menu/1 Contiene la definicin de los men!s de la aplicacin1 /res/values/1 Contiene otros recursos de la aplicacin como por e8emplo cadenas de te#to (strings.xml)- estilos (styles.xml)- colores (colors.xml)- etc1 /res/xml/1 Contiene los fic'eros ) L utilizados por la aplicacin1 /res/raw/1 Contiene recursos adicionales- normalmente en formato distinto a ) L4ue no se incluyan en el resto de carpetas de recursos1

Como e8emplo- para un proyecto nue.o Android- se crean los si%uientes recursos para la aplicacin:

http://www.sgoliver.net/ log/!p"1313 #$gina 8 de 156

Desarrollo en Android

Carpeta 3gen3 Contiene una serie de elementos de cdi%o %enerados automticamente al compilar el proyecto1 Cada .ez 4ue %eneramos nuestro proyecto- la ma4uinaria de compilacin de Android %enera por nosotros una serie de fic'eros fuente en 8a.a diri%idos al control de los recursos de la aplicacin1

El ms importante es el 4ue se puede obser.ar en la ima%en- el fic'ero R.java- y la clase R1 Esta clase R contendr en todo momento una serie de constantes con los ID de todos los recursos de la aplicacin incluidos en la carpeta /res/- de forma 4ue podamos acceder facilmente a estos recursos desde nuestro cdi%o a tra.es de este dato1 As0- por e8emplo- la constante R.drawable.icon contendr el ID de la ima%en icon.png contenida en la carpeta /res/drawable/1 Veamos como e8emplo la clase : creada por defecto para un proyecto nue.o:
package net.sgoliver; public inal class R ! public static inal class attr ! " public static inal class drawable ! public static inal int icon#$x% $&$$$$; " public static inal class layout ! public static inal int main#$x% $'$$$$; " public static inal class string ! public static inal int app(name#$x% $)$$$*; public static inal int hello#$x% $)$$$$; " "

http://www.sgoliver.net/ log/!p"1313 #$gina 9 de 156

Desarrollo en Android

Carpeta 3assets3 Contiene todos los dems fic'eros au#iliares necesarios para la aplicacin (y 4ue se incluirn en su propio pa4uete)- como por e8emplo fic'eros de confi%uracin- de datos- etc1 La diferencia entre los recursos incluidos en la carpeta /res/raw/ y los incluidos en la carpeta /assets/ es 4ue para los primeros se %enerar un ID en la clase R y se deber acceder a ellos con los diferentes m/todos de acceso a recursos1 &ara los se%undos sin embar%o no se %enerarn ID y se podr acceder a ellos por su ruta como a cual4uier otro fic'ero del sistema1 <saremos uno u otro se%!n las necesidades de nuestra aplicacin1 4ic5ero AndroidManifest%6ml Contiene la definicin en ) L de los aspectos principales de la aplicacin- como por e8emplo su identificacin (nombre- .ersin- icono- G)- sus componentes (pantallas- mensa8es- G)- o los permisos necesarios para su e8ecucin1 Veremos ms adelante ms detalles de este fic'ero1 En el si%uiente post .eremos los componentes softEare principales con los 4ue podemos construir una aplicacin Android1

http://www.sgoliver.net/ log/!p"1313 #$gina 10 de 156

Desarrollo en Android

Componentes de una aplicacin Android


En el post anterior .imos la estructura de un proyecto Android y aprendimos dnde colocar cada uno de los elementos 4ue componen una aplicacin- tanto elementos de softEare como recursos %rficos o de datos1 En /ste nue.o post .amos a centrarnos espec0ficamente en los primeros- es decir- .eremos los distintos tipos de componentes de softEare con los 4ue podremos construir una aplicacin Android1 En 5a.a o 13E( estamos acostumbrados a mane8ar conceptos como ventana- control- eventos o servicios como los elementos bsicos en la construccin de una aplicacin1 &ues bien- en Android .amos a disponer de esos mismos elementos bsicos aun4ue con un pe4ueDo cambio en la terminolo%0a y el enfo4ue1 :epasemos los componentes principales 4ue pueden formar parte de una aplicacin Android H&or claridad- y para e.itar confusiones al consultar documentacin en in%l/s- intentar/ traducir lo menos posible los nombres ori%inales de los componentesI1 Acti7it2 Las actividades (acti.ities) representan el componente principal de la interfaz %rfica de una aplicacin Android1 "e puede pensar en una actividad como el elemento anlo%o a una ventana en cual4uier otro len%ua8e .isual1 -ie8 Los ob8etos view son los componentes bsicos con los 4ue se construye la interfaz %rfica de la aplicacin- anlo%o por e8emplo a los controles de 5a.a o 13E(1 De inicio- Android pone a nuestra disposicin una %ran cantidad de controles bsicos- como cuadros de te#to- botoneslistas desple%ables o im%enes- aun4ue tambi/n e#iste la posibilidad de e#tender la funcionalidad de estos controles bsicos o crear nuestros propios controles personalizados1 'er7ice Los servicios son componentes sin interfaz %rfica 4ue se e8ecutan en se%undo plano1 En concepto- son e#actamente i%uales a los ser.icios presentes en cual4uier otro sistema operati.o1 Los ser.icios pueden realizar cual4uier tipo de acciones- por e8emplo actualizar datos- lanzar notificaciones- o incluso mostrar elementos .isuales (activities) si se necesita en al%!n momento la interaccin con del usuario1 Content Pro7ider
http://www.sgoliver.net/ log/!p"1313 #$gina 11 de 156

Desarrollo en Android

<n content provider es el mecanismo 4ue se 'a definido en Android para compartir datos entre aplicaciones1 ediante estos componentes es posible compartir determinados datos de nuestra aplicacin sin mostrar detalles sobre su almacenamiento interno- su estructura- o su implementacin1 De la misma forma- nuestra aplicacin podr acceder a los datos de otra a tra./s de los content provider 4ue se 'ayan definido1 roadcast 9ecei7er <n !roadcast receiver es un componente destinado a detectar y reaccionar ante determinados mensa8es o e.entos %lobales %enerados por el sistema (por e8emplo: >+ater0a ba8a?- >" " recibido?- >(ar8eta "D insertada?- G) o por otras aplicaciones (cual4uier aplicacin puede %enerar mensa8es (intents- en terminolo%0a Android) broadcast- es decir- no diri%idos a una aplicacin concreta sino a cual4uiera 4ue 4uiera esc$c)arlo)1 Widget Los widgets son elementos .isuales- normalmente interacti.os- 4ue pueden mostrarse en la pantalla principal ()ome screen) del dispositi.o Android y recibir actualizaciones peridicas1 &ermiten mostrar informacin de la aplicacin al usuario directamente sobre la pantalla principal1 Intent <n intent es el elemento bsico de comunicacin entre los distintos componentes Android 4ue 'emos descrito anteriormente1 "e pueden entender como los mensa%es o peticiones 4ue son en.iados entre los distintos componentes de una aplicacin o entre distintas aplicaciones1 ediante un intent se puede mostrar una actividad desde cual4uier otra- iniciar un ser.icioen.iar un mensa8e !roadcast- iniciar otra aplicacin- etc1

http://www.sgoliver.net/ log/!p"1313 #$gina 12 de 156

Desarrollo en Android

!esarrollando una aplicacin Android sencilla


Despu/s de instalar nuestro entorno de desarrollo para Android y comentar la estructura bsica de un proyecto y los diferentes componentes softEare 4ue podemos utilizar ya es 'ora de empezar a escribir al%o de cdi%o1 2 como siempre lo me8or es empezar por escribir una aplicacin sencilla1 En un principio me plante/ analizar en este post el clsico Hola M$ndo pero ms tarde me pareci 4ue se iban a 4uedar al%unas cosas bsicas en el tintero1 As0 4ue 'e .ersionado a mi manera el Hola M$ndo transformndolo en al%o as0 como un Hola *s$ario- 4ue es i%ual de sencilla pero aDade un par de cosas interesantes de contar1 La aplicacin constar de dos pantallas- por un lado la pantalla principal 4ue solicitar un nombre al usuario y una se%unda pantalla en la 4ue se mostrar un mensa8e personalizado para el usuario1 "encillo- in!til- pero aprenderemos muc'os conceptos bsicos- 4ue para empezar no est mal1

http://www.sgoliver.net/ log/!p"1313 #$gina 13 de 156

Desarrollo en Android

En primer lu%ar .amos a crear un nue.o proyecto Android tal como .imos al final del primer post de la serie1 Llamaremos al proyecto >Fola<suario?- indicaremos como tar%et por e8emplo >Android C19J- daremos un nombre a la aplicacin e indicaremos 4ue se cree una acti.idad llamada >Fola<suario?1

Como ya .imos esto nos crea la estructura de carpetas del proyecto y todos los fic'eros necesarios de un Hola M$ndo bsico- es decir- una sola pantalla donde se muestra !nicamente un mensa8e fi8o1 Lo primero 4ue .amos a 'acer es diseDar nuestra pantalla principal modificando la 4ue Eclipse nos 'a creado por defecto1 K&ero dnde y cmo se define cada pantalla de la aplicacinL En Android- el diseDo y la l%ica de una pantalla estan separados en dos fic'eros distintos1 &or un lado- en el fic'ero /res/layout/main.xml tendremos el diseDo puramente .isual de la pantalla definido como fic'ero ) L y por otro lado- en el fic'ero /src/pa+uetejava/,ola-suario.java- encontraremos el cdi%o 8a.a 4ue determina la l%ica de la pantalla1 Vamos a modificar en primer lu%ar el aspecto de la .entana principal de la aplicacin aDadiendo los controles (.ieEs) 4ue .emos en la primera captura de pantalla1 &ara ello- .amos a sustituir el contenido del fic'ero main.xml por el si%uiente:

http://www.sgoliver.net/ log/!p"1313 #$gina 14 de 156

Desarrollo en Android

./xml version#0*.$0 encoding#0ut -10/2 .3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4orientation#0vertical0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 2 .5ext6iew android4text#07string/nombre0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 /2 .8dit5ext android4id#079id/5xt:ombre0 android4layout(height#0wrap(content0 android4layout(width#0 ill(parent0 /2 .;utton android4id#079id/;tn,ola0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4text#07string/hola0 /2 ./3inear3ayout2

En este ) L se definen los elementos .isuales 4ue componen la interfaz de nuestra pantalla principal y se especifican todas sus propiedades1 3o nos detendremos muc'o en cada detalle por4ue /se ser tema de otro art0culo- pero e#pli4uemos un poco lo 4ue .emos en el fic'ero1 Lo primero 4ue nos encontramos es un elemento 3inear3ayout1 Los la&o$t son elementos no .isibles 4ue determinan cmo se .an a distribuir en el espacio los controles 4ue incluyamos en su interior1 Los pro%ramadores 8a.a- y ms concretamente de Swing- conocern este concepto perfectamente1 En este caso- un 3inear3ayout distribuir los controles uno tras otro y en la orientacin 4ue indi4ue su propiedad android4orientation1 Dentro del layout 'emos incluido 6 controles: una eti4ueta (5ext6iew)- un cuadro de te#to (8dit5ext)- y un botn (;utton)1 En todos ellos 'emos establecido las si%uientes propiedades:

android4id1 ID del control- con el 4ue podremos identificarlo ms tarde en nuestro cdi%o1Vemos 4ue el identificador lo escribimos precedido de >MNid@?1 Esto tendr como efecto 4ue al compilarse el proyecto se %enere automticamente una nue.a constante en la clase : para dic'o control HAprende ms sobre la clase : en el post anteriorI1 android4text1 (e#to del control1 El te#to de un control se puede especificar directamente o bien utilizar al%una de las cadenas de te#to definidas en los recursos del

http://www.sgoliver.net/ log/!p"1313 #$gina 15 de 156

Desarrollo en Android

proyecto (fic'ero strings+,ml)- en cuyo caso indicaremos su identificador precedido del prefi8o >Mstrin%@?1

android4layout(height y android4layout(width1 Dimensiones del control con respecto al layout 4ue lo contiene1 Esta propiedad tomar normalmente los .alores >wrap(content? para indicar 4ue las dimensiones del control se a8ustarn al contenido del mismo- o bien > ill(parent? para indicar 4ue el anc'o o el alto del control se a8ustar al anc'o o alto del layout contenedor respecti.amente1

Con esto ya tenemos definida la presentacin .isual de nuestra .entana principal de la aplicacin1 De i%ual forma definiremos la interfaz de la se%unda pantalla- creando un nue.o fic'ero llamado frmmensa%e+,ml- y aDadiendo esta .ez tan solo una eti4ueta (5ext6iew) para mostrar el mensa8e personalizado al usuario1 Veamos cmo 4uedar0a nuestra se%unda pantalla:
./xml version#0*.$0 encoding#0ut -10/2 .3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content02 .5ext6iew android4id#079id/5xt<ensaje0 android4layout(height#0wrap(content0 android4layout(width#0 ill(parent0 android4text#0=mensaje02./5ext6iew2 ./3inear3ayout2

<na .ez definida la interfaz de las pantallas de la aplicacin deberemos implementar la l%ica de la misma1 Como ya 'emos comentado- la l%ica de la aplicacin se definir en fic'eros 8a.a independientes1 &ara la pantalla principal ya tenemos creado un fic'ero por defecto llamado Hola*s$ario+%ava1 Empecemos por comentar su cdi%o por defecto:
public class ,ola-suario extends >ctivity ! /?? @alled when the activity is irst created. ?/ 7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; " "

Como ya .imos en un post anterior- las diferentes pantallas de una aplicacin Android se definen mediante ob8etos de tipo >ctivity1 &or tanto- lo primero 4ue encontramos en nuestro fic'ero 8a.a es la definicin de una nue.a clase ,ola-suario 4ue e#tiende a >ctivity1 El !nico
http://www.sgoliver.net/ log/!p"1313 #$gina 16 de 156

Desarrollo en Android

m/todo 4ue sobreescribiremos de esta clase ser el m/todo An@reate- llamado cuando se crea por primera .ez la acti.idad1 En este m/todo lo !nico 4ue encontramos en principio- adems de la llamada a su implementacin en la clase padre- es la llamada al m/todo set@ontent6iewBR.layout.mainE1 Con esta llamada estaremos indicando a Android 4ue debe establecer como interfaz %rfica de esta acti.idad la definida en el recurso R.layout.main- 4ue no es ms 4ue la 4ue 'emos especificado en el fic'ero /res/la&o$t/main+,ml1 <na .ez ms .emos la utilidad de las diferentes constantes de recursos creadas automticamente en la clase : al compilar el proyecto1 En principio .amos a crear una nue.a acti.idad para la se%unda pantalla de la aplicacin anlo%a a /sta primera- para lo 4ue crearemos una nue.a clase Frm<ensaje 4ue e#ienda de >ctivity y 4ue implemente el m/todo on@reate indicando 4ue utilice la interfaz definida en R.layout. rmmensaje1
public class Frm<ensaje extends >ctivity ! 7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout. rmmensajeE; " "

Como .emos- el cdi%o incluido por defecto en estas clases lo !nico 4ue 'ace es %enerar la interfaz de la acti.idad1 A partir de a4u0 nosotros tendremos 4ue incluir el resto de la l%ica de la aplicacin1 2 .amos a empezar con la acti.idad principal ,ola-suario- obteniendo una referencia a los diferentes controles de la interfaz 4ue necesitemos manipular- en nuestro caso slo el cuadro de te#to y el botn1 &ara ello utilizaremos el m/todo ind6iew;yCdBE indicando el ID de cada control- definidos como siempre en la clase ::
inal 8dit5ext txt:ombre # B8dit5extE ind6iew;yCdBR.id.5xt:ombreE; inal ;utton btn,ola # B;uttonE ind6iew;yCdBR.id.;tn,olaE;

<na .ez tenemos acceso a los diferentes controles- ya slo nos 4ueda implementar las acciones a tomar cuando pulsemos el botn de la pantalla1 &ara ello implementaremos el e.ento onClicO de dic'o botn- .eamos cmo:
btn,ola.setAn@lick3istenerBnew An@lick3istenerBE ! 7Averride public void on@lickB6iew arg$E ! Cntent intent # new CntentB,ola-suario.thisG Frm<ensaje.classE; ;undle bundle # new ;undleBE; bundle.putDtringB0:A<;R80G txt:ombre.get5extBE.toDtringBEE; intent.put8xtrasBbundleE; start>ctivityBintentE;

http://www.sgoliver.net/ log/!p"1313 #$gina 17 de 156

Desarrollo en Android

" "E;

Como ya indicamos en el art0culo anterior- la comunicacin entre los distintos componentes y aplicaciones en Android se realiza mediante intents- por lo 4ue el primer paso ser crear un ob8eto de este tipo1 E#isten .arias .ariantes del constructor de la clase Cntent- cada una de ellas diri%ida a unas determinadas acciones- pero en nuestro caso particular .amos a utilizar el intent para llamar a una acti.idad desde otra de la misma aplicacin- para lo 4ue pasaremos al constructor una referencia a la propia acti.idad llamadora (,ola-suario.this)- y la clase de la acti.idad llamada (Frm<ensaje.class)1 "i 4uisi/ramos tan slo mostrar una nue.a acti.idad ya tan slo nos 4uedar0a llamar a start>ctivityBE pasndole como parmetro el intent creado1 &ero en nuestro e8emplo 4ueremos tambi/n pasarle cierta informacin a la acti.idad- concretamente el nombre 4ue introduzca el usuario en el cuadro de te#to1 &ara 'acer esto .amos a crear un ob8eto ;undle4ue puede contener una lista de pares cla.eA.alor con toda la informacin a pasar entre las acti.idades1 En nuestro caso slo aDadiremos un dato de tipo Dtring mediante el m/todo putDtringBclaveG valorE1 (ras esto aDadiremos la informacin al intent mediante el m/todo put8xtrasBbundleE1 Pinalizada la acti.idad principal de la aplicacin pasamos ya a la secundaria1 Comenzaremos de forma anlo%a a la anterior- ampliando el m/todo on@reate obteniendo las referencias a los ob8etos 4ue manipularemos- esta .ez slo la eti4ueta de te#to1 (ras esto .iene lo ms interesantedebemos recuperar la informacin pasada desde la acti.idad principal y asi%narla como te#to de la eti4ueta1 &ara ello accederemos en primer lu%ar al intent 4ue 'a ori%inado la acti.idad actual mediante el m/todo getCntentBE y recuperaremos su informacin asociada (ob8eto ;undle) mediante el m/todo get8xtrasBE1 Fec'o esto tan slo nos 4ueda construir el te#to de la eti4ueta mediante su m/todo set5extBtextoE y recuperando el .alor de nuestra cla.e almacenada en el ob8eto ;undle mediante getDtringBclaveE1
public class Frm<ensaje extends >ctivity ! 7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout. rmmensajeE; 5ext6iew txt<ensaje # B5ext6iewE ind6iew;yCdBR.id.5xt<ensajeE; ;undle bundle # getCntentBE.get8xtrasBE;

http://www.sgoliver.net/ log/!p"1313 #$gina 18 de 156

Desarrollo en Android

txt<ensaje.set5extB0,ola 0 9 bundle.getDtringB0:A<;R80EE; " "

Con esto 'emos concluido la l%ica de las dos pantallas de nuestra aplicacin y tan slo nos 4ueda un paso importante para finalizar nuestro desarrollo1 Como indicamos en uno de los art0culos anteriores- cual4uier aplicacin Android utiliza un fic'ero especial en formato ) L (AndroidManifest+,ml) para definir- entre otras cosas- los diferentes elementos 4ue la componen1 &or tanto- todas las acti.idades de nuestra aplicacin deben 4uedar con.enientemente reco%idas en este fic'ero1 La acti.idad principal ya debe aparecer puesto 4ue se cre de forma automtica al crear el nue.o proyecto Android- por lo 4ue debemos aDadir tan slo la se%unda1 &ara este e8emplo nos limitaremos a incluir la acti.idad en el ) L- ms adelante .eremos 4ue opciones adicionales podemos especificar1

./xml version#0*.$0 encoding#0ut -10/2 .mani est xmlns4android#0http4//schemas.android.com/apk/res/android0 package#0net.sgoliver0 android4version@ode#0*0 android4version:ame#0*.$02 .application android4icon#07drawable/icon0 android4label#07string/app(name02 .activity android4name#0.,ola-suario0 android4label#07string/app(name02 .intent- ilter2 .action android4name#0android.intent.action.<>C:0 /2 .category android4name#0android.intent.category.3>-:@,8R0 /2 ./intent- ilter2 ./activity2 .activity android4name#0.Frm<ensaje02./activity2 ./application2 .uses-sdk android4minDdk6ersion#0)0 /2 ./mani est2

<na .ez lle%ado a4u0- si todo 'a ido bien- deber0amos poder e8ecutar el proyecto sin errores y probar nuestra aplicacin en el emulador1 Descar%a el cdi%o fuente de este art0culo1 Espero 4ue esta aplicacin de e8emplo os 'aya ser.ido para aprender temas bsicos en el desarrollo para Android- como por e8emplo la definicin de la interfaz %rfica- el cdi%o 8a.a necesario para acceder y manipular los elementos de dic'a interfaz- o la forma de comunicar diferentes acti.idades de Android1 En los art0culos si%uientes .eremos al%unos de estos temas de forma ms espec0fica y ampliaremos con al%unos temas ms a.anzados1
http://www.sgoliver.net/ log/!p"1313 #$gina 19 de 156

Desarrollo en Android

Interfaz de usuario en Android: La2outs


En el art0culo anterior del curso- donde desarrollamos una sencilla aplicacin Android desde cero- ya 'icimos al%unos comentarios sobre los la&o$ts1 Como ya indicamos- los la&o$ts son elementos no .isuales destinados a controlar la distribucin- posicin y dimensiones de los controles 4ue se insertan en su interior1 Estos componentes e#tienden a la clase base 6iewHroup- como muc'os otros componentes contenedores- es decir- capaces de contener a otros controles1 En el post anterior conocimos la e#istencia de un tipo concreto de layout3inear3ayout- aun4ue Android nos proporciona al%unos otros1 Vemos cuntos y cules1 4rameLa2out Qste es el ms simple de todos los layouts de Android1 <n Frame3ayout coloca todos sus controles 'i8os alineados con su es4uina superior iz4uierda- de forma 4ue cada control 4uedar oculto por el control si%uiente (a menos 4ue /ste !ltimo ten%a transparencia)1 &or ello- suele utilizarse para mostrar un !nico control en su interior- a modo de contenedor (place)older) sencillo para un slo elemento sustituible- por e8emplo una ima%en1 Los componentes incluidos en un Frame3ayout podrn establecer sus propiedades android4layout(width y android4layout(height- 4ue podrn tomar los .alores > ill(parent? (para 4ue el control 'i8o tome la dimensin de su layout contenedor) o >wrap(content? (para 4ue el control 'i8o tome la dimensin de su contenido)1 E8emplo:
.Frame3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent02 .8dit5ext android4id#079id/5xt:ombre0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 /2 ./Frame3ayout2

LinearLa2out

http://www.sgoliver.net/ log/!p"1313 #$gina 20 de 156

Desarrollo en Android

El si%uiente layout Android en cuanto a ni.el de comple8idad es el 3inear3ayout1 Este layout apila uno tras otro todos sus elementos 'i8os de forma 'orizontal o .ertical se%!n se establezca su propiedad android4orientation1

Al i%ual 4ue en un Frame3ayout- los elementos contenidos en un 3inear3ayout pueden establecer sus propiedades android4layout(width y android4layout(height para determinar sus dimensiones dentro del layout1 &ero en el caso de un 3inear3ayouttendremos otro parmetro con el 4ue 8u%ar- la propiedad android4layout(weight1
.3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4orientation#0vertical02 .8dit5ext android4id#079id/5xt:ombre0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 /2 .;utton android4id#079id/;tn>ceptar0 android4layout(width#0wrap(content0 android4layout(height#0 ill(parent0 /2 ./3inear3ayout2

Esta propiedad nos .a a permitir dar a los elementos contenidos en el layout unas dimensiones proporcionales entre ellas1 Esto es ms dificil de e#plicar 4ue de comprender con un e8emplo1 "i incluimos en un 3inear3ayout .ertical dos cuadros de te#to (8dit5ext) y a uno de ellos le establecemos un layout(weight#*I y al otro un layout(weight#&I conse%uiremos como efecto 4ue toda la superficie del layout 4uede ocupada por los dos cuadros de te#to y 4ue adems el se%undo sea el doble (relacin entre sus propiedades weight) de alto 4ue el primero1
.3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4orientation#0vertical02 .8dit5ext android4id#079id/5xtJato*0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4layout(weight#0*0 /2

http://www.sgoliver.net/ log/!p"1313 #$gina 21 de 156

Desarrollo en Android

.8dit5ext android4id#079id/5xtJato&0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4layout(weight#0&0 /2 ./3inear3ayout2

As0 pues- a pesar de la simplicidad aparente de este layout resulta ser lo suficiente .erstil como para sernos de utilidad en muc'as ocasiones1 Ta;leLa2out <n 5able3ayout permite distribuir sus elementos 'i8os de forma tabular- definiendo las filas y columnas necesarias- y la posicin de cada componente dentro de la tabla1 La estructura de la tabla se define de forma similar a como se 'ace en F( L- es decir- indicando las filas 4ue compondrn la tabla (ob8etos 5ableRow)- y dentro de cada fila las columnas necesarias- con la sal.edad de 4ue no e#iste nin%!n ob8eto especial para definir una columna (al%o as0 como un Ta!le(ol$mn) sino 4ue directamente insertaremos los controles necesarios dentro del 5ableRow y cada componente insertado (4ue puede ser un control sencillo o incluso otro 6iewHroup) corresponder a una columna de la tabla1 De esta forma- el n!mero final de filas de la tabla se corresponder con el n!mero de elementos (able:oE insertados- y el n!mero total de columnas 4uedar determinado por el n!mero de componentes de la fila 4ue ms componentes conten%a1 &or norma %eneral- el anc'o de cada columna se corresponder con el anc'o del mayor componente de dic'a columna- pero e#isten una serie de propiedades 4ue nos ayudarn a modificar este comportamiento:

android4stretch@olumns1 Indicar las columnas 4ue pueden e#pandir para absor.er el espacio libre de8ado por las dems columnas a la derec'a de la pantalla1 android4shrink@olumns1 Indicar las columnas 4ue se pueden contraer para de8ar espacio al resto de columnas 4ue se puedan salir por la derec'a de la palntalla1 android4collapse@olumns1 Indicar las columnas de la tabla 4ue se 4uieren ocultar completamente1

(odas estas propiedades del 5able3ayout pueden recibir una lista de 0ndices de columnas separados por comas (e8emplo: android4stretch@olumns#*G&G'I) o un asterisco para indicar 4ue debe aplicar a todas las columnas (e8emplo: android4stretch@olumns#?)1 *tra caracter0stica importante es la posibilidad de 4ue una celda determinada pueda ocupar el espacio de .arias columnas de la tabla (anlo%o al atributo colspan de F( L)1 Esto se indicar mediante la propiedad android4layout(span del componente concreto 4ue deber tomar dic'o espacio1
http://www.sgoliver.net/ log/!p"1313 #$gina 22 de 156

Desarrollo en Android

Veamos un e8emplo con .arios de estos elementos:


.5able3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4stretch@olumns#0*0 2 .5ableRow2 .5ext6iew android4text#0@elda *.*0 /2 .5ext6iew android4text#0@elda *.&0 /2 ./5ableRow2 .5ableRow2 .5ext6iew android4text#0@elda &.*0 /2 .5ext6iew android4text#0@elda &.&0 /2 ./5ableRow2 .5ableRow2 .5ext6iew android4text#0@elda '0 android4layout(span#0&0 /2 ./5ableRow2 ./5able3ayout2

9elati7eLa2out El !ltimo tipo de layout 4ue .amos a .er es el Relative3ayout1 Este layout permite especificar la posicin de cada elemento de forma relati.a a su elemento padre o a cual4uier otro elemento incluido en el propio layout1 De esta forma- al incluir un nue.o elemento ) podremos indicar por e8emplo 4ue debe colocarse de!a%o del elemento - y alineado a la derec)a del la&o$t padre1 Veamos esto en el e8emplo si%uiente:
.Relative3ayout xmlns4android#0http4//schemas.android.com/apk/res/androi d android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 2

http://www.sgoliver.net/ log/!p"1313 #$gina 23 de 156

Desarrollo en Android

.8dit5ext android4id#079id/5xt:ombre0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 /2 .;utton android4id#079id/;tn>ceptar0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4layout(below#07id/5xt:ombre0 android4layout(alignKarentRight#0true0 /2 ./Relative3ayout2

En el e8emplo- el botn ;tn>ceptar se colocar deba8o del cuadro de te#to 5xt:ombre (android4layout(below#7id/5xt:ombre) y alineado a la derec'a del layout padre (android4layout(alignKarentRight#true)- adems de de8ar un mar%en a su iz4uierda de CR pi#eles (android4layout(margin3e t#*$px)1 Al i%ual 4ue estas tres propiedades- en un :elati.eLayout tendremos un sinf0n de propiedades para colocar cada control 8usto donde 4ueramos1 Veamos las principales Hcreo 4ue sus propios nombres e#plican perfectamente la funcin de cada unaI: &osicin relati.a a otro control:

android:layoutSabo.e1 android:layoutSbeloE1 android:layoutStoLeft*f1 android:layoutSto:i%'t*f1 android:layoutSali%nLeft1 android:layoutSali%n:i%'t1 android:layoutSali%n(op1 android:layoutSali%n+ottom1 android:layoutSali%n+aseline1

&osicin relati.a al layout padre:


android:layoutSali%n&arentLeft1 android:layoutSali%n&arent:i%'t1 android:layoutSali%n&arent(op1 android:layoutSali%n&arent+ottom1 android:layoutScenterForizontal1 android:layoutScenterVertical1 android:layoutScenterIn&arent1

*pciones de mar%en (tambi/n disponibles para el resto de layouts):

android:layoutSmar%in1

http://www.sgoliver.net/ log/!p"1313 #$gina 24 de 156

Desarrollo en Android

android:layoutSmar%in+ottom1 android:layoutSmar%in(op1 android:layoutSmar%inLeft1 android:layoutSmar%in:i%'t1

*pciones de espaciado o paddin% (tambi/n disponibles para el resto de layouts):


android:paddin%1 android:paddin%+ottom1 android:paddin%(op1 android:paddin%Left1 android:paddin%:i%'t1

En pr#imos art0culos .eremos otros elementos comunes 4ue e#tienden a 6iewHroup- como por e8emplo las .istas de tipo lista (3ist6iew)- de tipo %rid (Hrid6iew)- y en pestaDas (5ab,ost@5abLidget)1

http://www.sgoliver.net/ log/!p"1313 #$gina 25 de 156

Desarrollo en Android

Interfaz de usuario en Android: Controles ;"sicos <II=


Despu/s de 'aber 'ablado en el art0culo anterior de los controles de tipo botn- en esta nue.a entre%a nos .amos a centrar en otros tres componentes bsicos imprescindibles en nuestras aplicaciones: las im%enes (Cmage6iew)- las eti4uetas (5ext6iew) y por !ltimo los cuadros de te#to (8dit5ext)1 Control Image-ie8 >API? El control Ima%eVieE permite mostrar im%enes en la aplicacin1 La propiedad ms interesante es android4src- 4ue permite indicar la ima%en a mostrar1 3ue.amente- lo normal ser indicar como ori%en de la ima%en el identificador de un recurso de nuestra carpeta /res/drawablepor e8emplo android4src#7drawable/unaimagen1 Adems de esta propiedade#isten al%unas otras !tiles en al%unas ocasiones como las destinadas a establecer el tamaDo m#imo 4ue puede ocupar la ima%en- android4maxLidth y android4max,eight1
.Cmage6iew android4id#079id/CmgFoto0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content 0 android4src#07drawable/icon0 /2

En la l%ica de la aplicacin- podr0amos establecer la ima%en mediante el m/todo setCmageResorceBME- pasndole el ID del recurso a utilizar como contenido de la ima%en1
Cmage6iew img# BCmage6iewE ind6iew;yCdBR.id.CmgFotoE; img.setCmageResourceBR.drawable.iconE;

Control Te6t-ie8 >API? El control 5ext6iew es otro de los clsicos en la pro%ramacin de =<Is- las eti4uetas de te#to- y se utiliza para mostrar un determinado te#to al usuario1 Al i%ual 4ue en el caso de los botones- el te#to del control se establece mediante la propiedad android4text1 A parte de esta propiedad- la naturaleza del control 'ace 4ue las ms interesantes sean las 4ue establecen el formato del te#to mostrado- 4ue al i%ual 4ue en el caso de los botones son las si%uientes: android4background (color de fondo)- android4text@olor (color del te#to)http://www.sgoliver.net/ log/!p"1313 #$gina 26 de 156

Desarrollo en Android

android4textDiNe (tamaDo de la fuente) y android4type ace (estilo del te#to: ne%rita- cursi.a- G)1
.5ext6iew android4id#079id/3bl8ti+ueta0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content 0 android4text#08scribe algo40 android4background#0O>>))FF0 android4type ace#0monospace0 /2

De i%ual forma- tambi/n podemos manipular estas propiedades desde nuestro cdi%o1 Como e8emplo- en el si%uiente fra%mento recuperamos el te#to de una eti4ueta con get5extBE- y posteriormente le concatenamos unos n!meros- actualizamos su contenido mediante set5extBE y le cambiamos su color de fondo con set;ackground@olorBE1
inal 5ext6iew lbl8ti+ueta # B5ext6iewE ind6iew;yCdBR.id.3bl8ti+uetaE; Dtring texto # lbl8ti+ueta.get5extBE.toDtringBE; texto 9# 0*&'0; lbl8ti+ueta.set5extBtextoE;

Control #ditTe6t >API? El control 8dit5ext es el componente de edicin de te#to 4ue proporciona la plataforma Android1 &ermite la introduccin y edicin de te#to por parte del usuario- por lo 4ue en tiempo de diseDo la propiedad ms interesante a establecer- adems de su posicin@tamaDo y formato- es el te#to a mostrar- atributo android4text1
.8dit5ext android4id#079id/5xt5exto0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4layout(below#07id/3bl8ti+ueta0 / 2

De i%ual forma- desde nuestro cdi%o podremos recuperar y establecer este te#to mediante los m/todos get5extBE y set5extBnuevoTextoE respecti.amente:
inal 8dit5ext txt5exto # B8dit5extE ind6iew;yCdBR.id.5xt5extoE; Dtring texto # txt5exto.get5extBE.toDtringBE; txt5exto.set5extB0,ola mundoP0E;

<n detalle 4ue puede 'aber pasado desapercibido1 K*s 'ab/is fi8ado en 4ue 'emos tenido 4ue 'acer un toDtringBE sobre el resultado de get5extBEL La e#plicacin para esto es 4ue el m/todo get5extBE no de.uel.e un Dtring sino un ob8eto de tipo 8ditable- 4ue a su .ez implementa la interfaz Dpannable1 2 esto nos lle.a a la caracter0stica ms interesante del control 8dit5ext- y es 4ue no slo nos permite editar te,to plano sino tambi/n te,to
http://www.sgoliver.net/ log/!p"1313 #$gina 27 de 156

Desarrollo en Android

enri.$ecido o con formato1 Veamos cmo y 4u/ opciones tenemos- y para empezar comentemos al%unas cosas sobre los ob8etos Dpannable1 Interfaz 'panned <n ob8eto de tipo Dpanned es al%o as0 como una cadena de caracteres (deri.a de la interfaz @harDe+uence) en la 4ue podemos insertar otros ob8etos a modo de marcas o eti4uetas (spans) asociados a ran%os de caracteres1 De esta interfaz deri.a la interfaz Dpannable- 4ue permite la modificacin de estas marcas- y a su .ez de /sta !ltima deri.a la interfaz 8ditable4ue permite adems la modificacin del te#to1 Aun4ue en el apartado en el 4ue nos encontramos nos interesaremos principalmente por las marcas de formato de te#to- en principio podr0amos insertar cual4uier tipo de ob8eto1 E#isten muc'os tipos de spans predefinidos en la plataforma 4ue podemos utilizar para dar formato al te#to- entre ellos:

5ype aceDpan1 odifica el tipo de fuente1 DtyleDpan1 odifica el estilo del te#to (ne%rita- cursi.a- G)1 Foregroud@olorDpan1 odifica el color del te#to1 >bsoluteDiNeDpan1 odifica el tamaDo de fuente1

De esta forma- para crear un nue.o ob8eto Editable e insertar una marca de formato podr0amos 'acer lo si%uiente:
//@reamos un nuevo objeto de tipo 8ditable 8ditable str # 8ditable.Factory.getCnstanceBE.new8ditableB08sto es un simulacro.0E; //<arcamos cono uente negrita la palabra 0simulacro0 str.setDpanBnew DtyleDpanBandroid.graphics.5ype ace.;A3JEG **G *QG Dpannable.DK>:(8R@3-DC68(8R@3-DC68E;

En este e8emplo estamos insertando un span de tipo DtyleDpan para marcar un fra%mento de te#to con estilo negrita1 &ara insertarlo utilizamos el m/todo setDpanBE- 4ue recibe como parmetro el ob8eto Dpan a insertar- la posicin inicial y final del te#to a marcar- y un fla% 4ue indica la forma en la 4ue el span se podr e#tender al insertarse nue.o te#to1 Te6to con formato en controles Te6t-ie8 2 #ditTe6t Femos .isto cmo crear un ob8eto Editable y aDadir marcas de formato al te#to 4ue contienepero todo esto no tendr0a nin%!n sentido si no pudi/ramos .isualizarlo1 Como ya pod/is ima%inar- los controles (e#tVieE y Edit(e#t nos .an a permitir 'acer esto1 Vemos 4u/ ocurre si asi%namos al nuestro control Edit(e#t el ob8eto Editable 4ue 'emos creado antes:
txt5exto.set5extBstrE ;

http://www.sgoliver.net/ log/!p"1313 #$gina 28 de 156

Desarrollo en Android

(ras e8ecutar este cdi%o .eremos como efecti.amente en el cuadro de te#to aparece el mensa8e con el formato esperado:

2a 'emos .isto cmo asi%nar te#to con y sin formato a un cuadro de te#to- pero K4u/ ocurre a la 'ora de recuperar te#to con formato desde el controlL1 2a .imos 4ue la funcin get5extBE de.uel.e un ob8eto de tipo 8ditable y 4ue sobre /ste pod0amos 'acer un toDtringBE1 &ero con esta solucin estamos perdiendo todo el formato del te#to- por lo 4ue no podr0amos por e8emplo sal.arlo a una base de datos1 La solucin a esto !ltimo pasa ob.iamente por recuperar directamente el ob8eto 8ditable y serializarlo de al%!n modo- me8or a!n si es en un formato estandar1 &ues bien- en Android este traba8o ya nos .iene 'ec'o de fbrica a tra./s de la clase ,tml HA&II- 4ue dispone de m/todos para con.ertir cual4uier ob8eto Dpanned en su representacin F( L e4ui.alente1 Veamos cmo1 :ecuperemos el te#to de la .entana anterior y utilicemos el m/todo ,tml.to,tmlBDpannableE para con.ertirlo a formato F( L:
http://www.sgoliver.net/ log/!p"1313 #$gina 29 de 156

Desarrollo en Android
//Abtiene el texto del control con eti+uetas de ,5<3 Dtring aux& # ,tml.to,tmlBtxt5exto.get5extBEE; ormato

Faciendo esto- obtendr0amos una cadena de te#to como la si%uiente- 4ue ya podr0amos por e8emplo almacenar en una base de datos o publicar en cual4uier Eeb sin perder el formato de te#to establecido:
.p28sto es un .b2simulacro./b2../p2

La operacin contraria tambi/n es posible- es decir- car%ar un cuadro de te#to de Android (8dit5ext) o una eti4ueta (5ext6iew) a partir de un fra%mento de te#to en formato F( L1 &ara ello podemos utilizar el m/todo ,tml. rom,tmlBDtringE de la si%uiente forma:
//>signa texto con ormato ,5<3 txt5exto.set5extB ,tml. rom,tmlB0.p28sto es un .b2simulacro./b2../p20EG ;u er5ype.DK>::>;38E;

Des%raciadamente- aun4ue es de a%radecer 4ue este traba8o .en%a 'ec'o de casa- 'ay 4ue decir 4ue tan slo funciona de forma completa con las opciones de formato ms bsicas- como ne%ritas- cursi.as- subrayado o colores de te#to- 4uedando no soportadas otras sorprendentemente bsicas como el tamaDo del te#to- 4ue aun4ue s0 es correctamente traducido por el m/todo to,tmlBE- es descartado por el m/todo contrario rom,tmlBE1 "0 se soporta la inclusin de im%enes- aun4ue esto lo de8amos para un art0culo aparte (prometidoT) ya 4ue re4uiere al%o ms de e#plicacin1

http://www.sgoliver.net/ log/!p"1313 #$gina 30 de 156

Desarrollo en Android

Interfaz de usuario en Android: Controles ;"sicos <III=


(ras 'ablar de .arios de los controles indispensables en cual4uier aplicacin Android- como son los botones y los cuadros de te#to- en este art0culo .amos a .er cmo utilizar otros dos tipos de controles bsicos en muc'as aplicaciones- los c)ec#!o,es y los radio !$ttons1 Control C5ec@ o6 >API? <n control c)ec#!o, se suele utilizar para marcar o desmarcar opciones en una aplicacin- y en Android est representado por la clase del mismo nombre- C'ecO+o#1 La forma de definirlo en nuestra interfaz y los m/todos disponibles para manipularlos desde nuestro cdi%o son anlo%os a los ya comentados para el control 5oggle;utton1 De esta forma- para definir un control de este tipo en nuestro la&o$t podemos utilizar el cdi%o si%uiente- 4ue define un c)ec#!o, con el te#to > rcame?:
.@heck;ox android4id#079id/@hk<arcame0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content 0 android4text#0<SrcameP0 /2

En cuanto a la personalizacin del control podemos decir 4ue /ste e#tiende HindirectamenteI del control (e#tVieE- por lo 4ue todas las opciones de formato ya comentadas en art0culos anteriores son .lidas tambi/n para este control1 En el cdi%o de la aplicacin podremos 'acer uso de los m/todos is@heckedBE para conocer el estado del control- y set@heckedBestadoE para establecer un estado concreto para el control1
i Bcheck;ox.is@heckedBEE ! check;ox.set@heckedB alseE

http://www.sgoliver.net/ log/!p"1313 #$gina 31 de 156

Desarrollo en Android
; "

En cuanto a los posibles e.entos 4ue puede lanzar este control- el ms interesante es sin duda el 4ue informa de 4ue 'a cambiado el estado del control- 4ue recibe el nombre de on@hecked@hanged1 &ara implementar las acciones de este e.ento podr0amos utilizar por tanto la si%uiente l%ica:
inal @heck;ox cb # B@heck;oxE ind6iew;yCdBR.id.chk<arcameE; cb.setAn@hecked@hange3istenerB new @heck;ox.An@hecked@hange3istenerBE ! public void on@hecked@hangedB@ompound;utton button6iewG boolean is@heckedE ! i Bis@heckedE ! cb.set5extB0@heckbox marcadoP0E; " else ! cb.set5extB0@heckbox desmarcadoP0E; " " "E;

Control 9adio utton >API? Al i%ual 4ue los controles c)ec#!o,- un radio!$tton puede estar marcado o desmarcado- pero en este caso suelen utilizarse dentro de un %rupo de opciones donde una- y slo una- de ellas debe estar marcada obli%atoriamente- es decir- 4ue si se marca una de ellas se desmarcar automticamente la 4ue estu.iera acti.a anteriormente1 En Android- un %rupo de botones radio!$tton se define mediante un elemento RadioHroup- 4ue a su .ez contendr todos los elementos Radio;utton necesarios1 Veamos un e8emplo de cmo definir un %rupo de dos controles radio!$tton en nuestra interfaz:
.RadioHroup android4id#079id/gruporb0 android4orientation#0vertical0

http://www.sgoliver.net/ log/!p"1313 #$gina 32 de 156

Desarrollo en Android

android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 2 .Radio;utton android4id#079id/radio*0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content android4text#0ApciTn *0 /2 .Radio;utton android4id#079id/radio&0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content 0 android4text#0ApciTn &0 /2

./RadioHroup2

En primer lu%ar .emos cmo podemos definir el %rupo de controles indicando su orientacin (.ertical u 'orizontal) al i%ual 4ue ocurr0a por e8emplo con un /inear/a&o$t1 (ras esto- se aDaden todos los ob8etos :adio+utton necesarios indicando su ID mediante la propiedad android4id y su te#to mediante android4text1 <na .ez definida la interfaz podremos manipular el control desde nuestro cdi%o 8a.a 'aciendo uso de los diferentes m/todos del control RadioHroup- los ms importantes: checkBidE para marcar una opcin determinada mediante su ID- clear@heckBE para desmarcar todas las opciones- y get@heckedRadio;uttonCdBE 4ue como su nombre indica de.ol.er el ID de la opcin marcada (o el .alor AC si no 'ay nin%una marcada)1 Veamos un e8emplo:
inal RadioHroup rg # BRadioHroupE ind6iew;yCdBR.id.gruporbE; rg.clear@heckBE; rg.checkBR.id.radio*E; int idDeleccionado # rg.get@heckedRadio;uttonCdBE;

En cuanto a los e.entos lanzados- al i%ual 4ue en el caso de los c'ecObo#es- el ms importante ser el 4ue informa de los cambios en el elemento seleccionado- llamado tambi/n en este caso on@hecked@hange1 Vemos cmo tratar este e.ento del ob8eto RadioHroup:
inal RadioHroup rg # BRadioHroupE ind6iew;yCdBR.id.gruporbE; rg.setAn@hecked@hange3istenerB new RadioHroup.An@hecked@hange3istenerBE ! public void on@hecked@hangedBRadioHroup groupG int checkedCdE ! lbl<ensaje.set5extB0CJ opcion seleccionada4 0 9 checkedidE; " "E;

http://www.sgoliver.net/ log/!p"1313 #$gina 33 de 156

Desarrollo en Android

Veamos finalmente una ima%en del aspecto de estos dos nue.os tipos de controles bsicos 4ue 'emos comentado en este art0culo:

http://www.sgoliver.net/ log/!p"1313 #$gina 34 de 156

Desarrollo en Android

Interfaz de usuario en Android: Controles de seleccin <I=


<na .ez repasados los controles bsicos (I- II- III) 4ue podemos utilizar en nuestras aplicaciones Android- .amos a dedicar los pr#imos art0culos a describir los diferentes controles de seleccin disponibles en la plataforma1 Al i%ual 4ue en otros framewor#s Android dispone de di.ersos controles 4ue nos permiten seleccionar una opcin dentro de una lista de posibilidades1 As0podremos utilizar listas desple%ables (Dpinner)- listas fi8as (3ist6iew)- tablas (Hrid6iew) y otros controles espec0ficos de la plataforma como por e8emplo las %aler0as de im%enes (Hallery)1 En este primer art0culo dedicado a los controles de seleccin .amos a describir un elemento importante y com!n a todos ellos- los adaptadores- y lo .amos a aplicar al primer control de los indicados- las listas desple%ables1 Adaptadores en Android <adapters= &ara los desarrolladores de 8a.a 4ue 'ayan utilizado frameEorOs de interfaz %rfica como Swingel concepto de adaptador les resultar familiar1 <n adaptador representa al%o as0 como una interfaz com!n al modelo de datos 4ue e#iste por detrs de todos los controles de seleccin 4ue 'emos comentado1 Dic'o de otra forma- todos los controles de seleccin accedern a los datos 4ue contienen a tra./s de un adaptador1 Adems de pro.eer de datos a los controles .isuales- el adaptador tambi/n ser responsable de %enerar a partir de estos datos las .istas espec0ficas 4ue se mostrarn dentro del control de seleccin1 &or e8emplo- si cada elemento de una lista estu.iera formado a su .ez por una ima%en y .arias eti4uetas- el responsable de %enerar y establecer el contenido de todos estos >s$!0 elementos? a partir de los datos ser el propio adaptador1

http://www.sgoliver.net/ log/!p"1313 #$gina 35 de 156

Desarrollo en Android

Android proporciona de serie .arios tipos de adaptadores sencillos- aun4ue podemos e#tender su funcionalidad facilmente para adaptarlos a nuestras necesidades1 Los ms comunes son los si%uientes:

>rray>dapter1 Es el ms sencillo de todos los adaptadores- y pro.ee de datos a un control de seleccin a partir de un array de ob8etos de cual4uier tipo1 Dimple>dapter1 "e utiliza para mapear datos sobre los diferentes controles definidos en un fic'ero ) L de layout1 Dimple@ursor>dapter1 "e utiliza para mapear las columnas de un cursor sobre los diferentes elementos .isuales contenidos en el control de seleccin1

&ara no complicar e#cesi.amente los tutoriales- por a'ora nos .amos a conformar con describir la forma de utilizar un >rray>dapter con los diferentes controles de seleccin disponibles1 s adelante aprenderemos a utilizar el resto de adaptadores en conte#tos ms espec0ficos1

Veamos cmo crear un adaptador de tipo ArrayAdapter para traba8ar con un array %en/rico de 8a.a:
inal DtringUV datos # new DtringUV !08lem*0G08lem&0G08lem'0G08lem)0G08lemW0"; >rray>dapter.Dtring2 adaptador # new >rray>dapter.Dtring2BthisG android.R.layout.simple(spinner(itemG datosE;

Comentemos un poco el cdi%o1 "obre la primera l0nea no 'ay nada 4ue decir- es tan slo la definicin del array 8a.a 4ue contendr los datos a mostrar en el control- en este caso un array sencillo con cinco cadenas de caracteres1 En la se%unda l0nea creamos el adaptador en s0- al 4ue pasamos 6 parmetros:
1. El conte,to- 4ue normalmente ser simplemente una referencia a la acti.idad donde se

crea el adaptador1
2. El ID del la&o$t sobre el 4ue se mostrarn los datos del control1 En este caso le pasamos

el ID de un layout predefinido en Android (android.R.layout.simple(spinner(item)- formado !nicamente por un control 5ext6iew- pero podr0amos pasarle el ID de cual4uier layout de nuestro proyecto con cual4uier estructura y con8unto de controles- ms adelante .eremos cmo1 3. El arra& 4ue contiene los datos a mostrar1 Con esto ya tendr0amos creado nuestro adaptador para los datos a mostrar y ya tan slo nos 4uedar0a asi%nar este adaptador a nuestro control de seleccin para 4ue /ste mostrase los datos en la aplicacin1 Control 'pinner >API?
http://www.sgoliver.net/ log/!p"1313 #$gina 36 de 156

Desarrollo en Android

Las listas desple%ables en Android se llaman Dpinner1 Puncionan de forma similar al de cual4uier control de este tipo- el usuario selecciona la lista- se muestra una especie de lista emer%ente al usuario con todas las opciones disponibles y al seleccionarse una de ellas /sta 4ueda fi8ada en el control1 &ara aDadir una lista de este tipo a nuestra aplicacin podemos utilizar el cdi%o si%uiente:
.Dpinner android4id#079id/@mbApciones0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 / 2

&oco .amos a comentar de a4u0 ya 4ue lo 4ue nos interesan realmente son los datos a mostrar1 En cual4uier caso- las opciones para personalizar el aspecto .isual del control (fondo- color y tamaDo de fuente- G) son las mismas ya comentadas para los controles bsicos1

&ara enlazar nuestro adaptador (y por tanto nuestros datos) a este control utilizaremos el si%uiente cdi%o 8a.a:
inal Dpinner cmbApciones # BDpinnerE ind6iew;yCdBR.id.@mbApcionesE; adaptador.setJropJown6iewResourceB android.R.layout.simple(spinner(dropdown(itemE; cmbApciones.set>dapterBadaptadorE;

Comenzamos como siempre por obtener una referencia al control a tra./s de su ID1 2 en la !ltima l0nea asi%namos el adaptador al control mediante el m/todo set>dapterBE1 K2 la se%unda l0nea para 4u/ esL Cuando indicamos en el apartado anterior cmo construir un adaptador .imos cmo uno de los parmetros 4ue le pasbamos era el ID del layout 4ue utilizar0amos para .isualizar los elementos del control1 "in embar%o- en el caso del control Dpinner- este layout tan slo se aplicar al elemento seleccionado en la lista- es decir- al 4ue se muestra directamente sobre el propio control cuando no est desple%ado1 "in embar%o- antes indicamos 4ue el funcionamiento normal del control Dpinner incluye entre otras cosas mostrar una lista emer%ente con todas las opciones disponibles1 &ues bien- para personalizar tambi/n el aspecto de cada elemento en dic'a lista emer%ente tenemos el m/todo setJropJown6iewResourceBID_layoutE- al 4ue podemos pasar otro ID de layout distinto al primero sobre el 4ue se mostrarn los elementos de la lista emer%ente1 En este caso 'emos utilizado otro layout predefinido an Android para las listas desple%ables (android.R.layout.simple(spinner(dropdown(item)1 Con estas simples lineas de cdi%o conse%uiremos mostrar un control como el 4ue .emos en las si%uientes im%enes:

http://www.sgoliver.net/ log/!p"1313 #$gina 37 de 156

Desarrollo en Android

Como se puede obser.ar en las im%enes- la representacin del elemento seleccionado (primera ima%en) y el de las opciones disponibles (se%unda ima%en) es distinto- incluyendo el se%undo de ellos incluso al%!n elemento %rfico a la derec'a para mostrar el estado de cada opcin1 Como 'emos comentado- esto es debido a la utilizacin de dos layouts diferentes para uno y otros elementos1 En cuanto a los e.entos lanzados por el control Dpinner- el ms comunmente utilizado ser el %enerado al seleccionarse una opcin de la lista desple%able- onCtemDelected1 &ara capturar este e.ento se proceder de forma similar a lo ya .isto para otros controles anteriormenteasi%nadole su controlador mediante el m/todo setAnCtemDelected3istenerBE:
cmbApciones.setAnCtemDelected3istenerB new >dapter6iew.AnCtemDelected3istenerBE ! public void onCtemDelectedB>dapter6iew./2 parentG android.view.6iew vG int positionG long idE ! lbl<ensaje.set5extB0Deleccionado4 0 9 datosUpositionVE; " public void on:othingDelectedB>dapter6iew./2 parentE ! lbl<ensaje.set5extB00E; "

"E;

&ara este e.ento definimos dos m/todos- el primero de ellos (onCtemDelected) 4ue ser llamado cada .ez 4ue se selecciones una opcin en la lista desple%able- y el se%undo (on:othingDelected) 4ue se llamar cuando no 'aya nin%una opcin seleccionada (esto puede ocurrir por e8emplo si el adaptador no tiene datos)1
http://www.sgoliver.net/ log/!p"1313 #$gina 38 de 156

Desarrollo en Android

En el si%uiente art0culo describiremos el uso de controles de tipo lista (3ist6iew)1

Interfaz de usuario en Android: Controles de seleccin <II=


En el art0culo anterior ya comenzamos a 'ablar de los controles de seleccin en Androidempezando por e#plicar el concepto de adaptador y describiendo el control Dpinner1 En este nue.o art0culo nos .amos a centrar en el control de seleccin ms utilizado de todos- el 3ist6iew1 <n control 3ist6iew muestra al usuario una lista de opciones seleccionables directamente sobre el propio control- sin listas emer%entes como en el caso del control Dpinner1 En caso de e#istir ms opciones de las 4ue se pueden mostrar sobre el control se podr por supuesto 'acer scroll sobre la lista para acceder al resto de elementos1 &ara empezar- .eamos como podemos aDadir un control ListVieE a nuestra interfaz de usuario:
.3ist6iew android4id#079id/3stApciones0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 / 2

<na .ez ms- podremos modificar el aspecto del control utilizando las propiedades de fuente y color ya comentadas en art0culos anteriores1 &or su parte- para enlazar los datos con el control podemos utlizar por e8emplo el mismo cdi%o 4ue ya .imos para el control Dpinner1 Definiremos primero un array con nuestros datos de prueba- crearemos posteriormente el adaptador de tipo >rray>dapter y lo asi%naremos finalmente al control mediante el m/todo set>dapterBE:
inal DtringUV datos # new DtringUV!08lem*0G08lem&0G08lem'0G08lem)0G08lemW0";

http://www.sgoliver.net/ log/!p"1313 #$gina 39 de 156

Desarrollo en Android

>rray>dapter.Dtring2 adaptador # new >rray>dapter.Dtring2BthisG android.R.layout.simple(list(item(*G datosE; 3ist6iew lstApciones # B3ist6iewE ind6iew;yCdBR.id.3stApcionesE; lstApciones.set>dapterBadaptadorE;

En este caso- para mostrar los datos de cada elemento 'emos utilizado otro layout %en/rico de Android para los controles de tipo 3ist6iew (android.R.layout.simple(list(item(*)- formado !nicamente por un 5ext6iew con unas dimensiones determinadas1 La lista creada 4uedar0a como se muestra en la ima%en si%uiente:

Como pod/is comprobar el uso bsico del control 3ist6iew es completamente anlo%o al ya comentado para el control Dpinner1
http://www.sgoliver.net/ log/!p"1313 #$gina 40 de 156

Desarrollo en Android

"i 4uisi/ramos realizar cual4uier accin al pulsarse sobre un elemento de la lista creada tendremos 4ue implementar el e.ento onCtem@lick1 Veamos cmo con un e8emplo:
lstApciones.setAnCtem@lick3istenerBnew AnCtem@lick3istenerBE ! 7Averride public void onCtem@lickB>dapter6iew./2 aG 6iew vG int positionG long idE ! //>cciones necesarias al hacer click " "E;

Fasta a4u0 todo sencillo1 &ero- Ky si necesitamos mostrar datos ms comple8os en la listaL K4u/ ocurre si necesitamos 4ue cada elemento de la lista est/ formado a su .ez por .arios elementosL &ues .amos a pro.ec'ar este art0culo dedicado a los 3ist6iew para .er cmo podr0amos conse%uirlo- aun4ue todo lo 4ue comentar/ es e#tensible a otros controles de seleccin1 &ara no complicar muc'o el tema .amos a 'acer 4ue cada elemento de la lista muestre por e8emplo dos l0neas de te#to a modo de t0tulo y subt0tulo con formatos diferentes (por supuesto se podr0an aDadir muc'os ms elementos- por e8emplo im%enes- c)ec#!o,es- etc)1 En primer lu%ar .amos a crear una nue.a clase 8a.a para contener nuestros datos de prueba1 Vamos a llamarla 5itular y tan slo .a a contener dos atributos- t0tulo y subt0tulo1
package net.sgoliver; public class 5itular ! private Dtring titulo; private Dtring subtitulo; public 5itularBDtring titG Dtring subE ! " titulo # tit; subtitulo # sub;

public Dtring get5ituloBE! return titulo; " public Dtring getDubtituloBE! return subtitulo; " "

En cada elemento de la lista 4ueremos mostrar ambos datos- por lo 4ue el si%uiente paso ser crear un layout ) L con la estructura 4ue deseemos1 En mi caso .oy a mostrarlos en dos
http://www.sgoliver.net/ log/!p"1313 #$gina 41 de 156

Desarrollo en Android

eti4uetas de te#to (5ext6iew)- la primera de ellas en ne%rita y con un tamaDo de letra un poco mayor1 Llamaremos a este layout >listitem1tit$lar+,ml>:

./xml version#0*.$0 encoding#0ut -10/2 .3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4orientation#0vertical02 .5ext6iew android4id#079id/3bl5itulo0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4textDtyle#0bold0 android4textDiNe#0&$px0 /2 .5ext6iew android4id#079id/3blDub5itulo0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4textDtyle#0normal0 android4textDiNe#0*&px0 /2 ./3inear3ayout2

A'ora 4ue ya tenemos creados tanto el soporte para nuestros datos como el layout 4ue necesitamos para .isualizarlos- lo si%uiente 4ue debemos 'acer ser indicarle al adaptador cmo debe utilizar ambas cosas para %enerar nuestra interfaz de usuario final1 &ara ello .amos a crear nuestro propio adaptador e#tendiendo de la clase >rray>dapter1
class >daptador5itulares extends >rray>dapter ! >ctivity context; >daptador5itularesB>ctivity contextE ! superBcontextG R.layout.listitem(titularG datosE; this.context # context; " public 6iew get6iewBint positionG 6iew convert6iewG 6iewHroup parentE 3ayoutCn later in later # context.get3ayoutCn laterBE; 6iew item # in later.in lateBR.layout.listitem(titularG nullE; 5ext6iew lbl5itulo # B5ext6iewEitem. ind6iew;yCdBR.id.3bl5ituloE; lbl5itulo.set5extBdatosUpositionV.get5ituloBEE; 5ext6iew lblDubtitulo #

http://www.sgoliver.net/ log/!p"1313 #$gina 42 de 156

Desarrollo en Android
B5ext6iewEitem. ind6iew;yCdBR.id.3blDub5ituloE; lblDubtitulo.set5extBdatosUpositionV.getDubtituloBEE; returnBitemE;

" "

Analicemos el cdi%o anterior1 Lo primero 4ue encontramos es el constructor para nuestro adaptador- al 4ue slo pasaremos el conte#to (4ue ser la acti.idad desde la 4ue se crea el adaptador)1 En este constructor tan slo %uardaremos el conte#to para nuestro uso posterior y llamaremos al constructor padre tal como ya .imos al principio de este art0culo- pasndole el ID del layout 4ue 4ueremos utilizar (en nuestro caso el nue.o 4ue 'emos creado- >listitemStitular?) y el array 4ue contiene los datos a mostrar1 &osteriormente- redefinimos el m/todo encar%ado de %enerar y rellenar con nuestros datos todos los controles necesarios de la interfaz %rfica de cada elemento de la lista1 Este m/todo es get6iewBE1

El m/todo %etVieE() se llamar cada .ez 4ue 'aya 4ue mostrar un elemento de la lista1 Lo primero 4ue debe 'acer es >inflar? el layout ) L 4ue 'emos creado1 Esto consiste en consultar el ) L de nuestro layout y crear e inicializar la estructura de ob8etos 8a.a e4ui.alente1 &ara ellocrearemos un nue.o ob8eto 3ayoutCn later y %eneraremos la estructura de ob8etos mediante su m/todo in lateBid_layoutE1 (ras esto- tan slo tendremos 4ue obtener la referencia a cada una de nuestras eti4uetas como siempre lo 'emos 'ec'o y asi%nar su te#to correspondiente se%!n los datos de nuestro array y la posicin del elemento actual (parmetro position del m/todo get6iewBE)1 <na .ez tenemos definido el comportamiento de nuestro adaptador la forma de proceder en la acti.idad principal ser anlo%a a lo ya comentado- definiremos el array de datos de pruebacrearemos el adaptador y lo asi%naremos al control mediante set>dapterBE:
private 5itularUV datos # new 5itularUV! new 5itularB05Xtulo new 5itularB05Xtulo new 5itularB05Xtulo new 5itularB05Xtulo new 5itularB05Xtulo //... //... >daptador5itulares adaptador # new >daptador5itularesBthisE; 3ist6iew lstApciones #

*0G &0G '0G )0G W0G

0DubtXtulo 0DubtXtulo 0DubtXtulo 0DubtXtulo 0DubtXtulo

largo largo largo largo largo

*0EG &0EG '0EG )0EG W0E";

http://www.sgoliver.net/ log/!p"1313 #$gina 43 de 156

Desarrollo en Android

B3ist6iewE ind6iew;yCdBR.id.3stApcionesE; lstApciones.set>dapterBadaptadorE;

Fec'o esto- y si todo 'a ido bien- nuestra nue.a lista deber0a 4uedar como .emos en la ima%en si%uiente:

&od/is descar%ar el cdi%o de este art0culo desde este enlace1 Aun4ue ya sabemos utilizar y personalizar las listas en Android- en el pr#imo art0culo daremos al%unas indicaciones para utilizar de una forma muc'o ms eficiente los controles de este tipoal%o 4ue los usuarios de nuestra aplicacin a%radecern enormemente al me8orarse la respuesta de la aplicacin y reducirse el consumo de bater0a1
http://www.sgoliver.net/ log/!p"1313 #$gina 44 de 156

Desarrollo en Android

Interfaz de usuario en Android: Controles de seleccin <III=


En el art0culo anterior ya .imos cmo utilizar los controles de tipo ListVieE en Android1 "in embar%o- acabamos comentando 4ue e#ist0a una forma ms eficiente de 'acer uso de dic'o control- de forma 4ue la respuesta de nuestra aplicacin fuera ms a%il y se reduciese el consumo de bater0a- al%o 4ue en plataformas m.iles siempre es importante1 Como base para este art0culo .amos a utilizar como cdi%o 4ue ya escribimos en el art0culo anterior- por lo 4ue si 'as lle%ado 'asta a4u0 directamente te recomiendo 4ue leas primero el primer post dedicado al control ListVieE1 Cuando comentamos cmo crear nuestro propio adaptador- e#tendiendo de >rray>dapterpara personalizar la forma en 4ue nuestros datos se iban a mostrar en la lista escribimos el si%uiente cdi%o:
class >daptador5itulares extends >rray>dapter ! >ctivity context; >daptador5itularesB>ctivity contextE ! superBcontextG R.layout.listitem(titularG datosE; this.context # context; " public 6iew get6iewBint positionG 6iew convert6iewG 6iewHroup parentE ! 3ayoutCn later in later # context.get3ayoutCn laterBE; 6iew item # in later.in lateBR.layout.listitem(titularG nullE;

http://www.sgoliver.net/ log/!p"1313 #$gina 45 de 156

Desarrollo en Android
5ext6iew lbl5itulo # B5ext6iewEitem. ind6iew;yCdBR.id.3bl5ituloE; lbl5itulo.set5extBdatosUpositionV.get5ituloBEE; 5ext6iew lblDubtitulo # B5ext6iewEitem. ind6iew;yCdBR.id.3blDub5ituloE; lblDubtitulo.set5extBdatosUpositionV.getDubtituloBEE; returnBitemE; " "

Centrndonos en la definicin del m/todo get6iewBE .imos 4ue la forma normal de proceder consist0a en primer lu%ar en >inflar? nuestro layout ) L personalizado para crear todos los ob8etos correspondientes (con la estructura descrita en el ) L) y posteriormente acceder a dic'os ob8etos para modificar sus propiedades1 "in embar%o- 'ay 4ue tener en cuenta 4ue esto se 'ace todas y cada una de las .eces 4ue se necesita mostrar un elemento de la lista en pantalla- se 'aya mostrado ya o no con anterioridad- ya 4ue Android no >%uarda? los elementos de la lista 4ue desaparecen de pantalla (por e8emplo al 'acer scroll sobre la lista)1 El efecto de esto es ob.io- dependiendo del tamaDo de la lista y sobre todo de la comple8idad del layout 4ue 'ayamos definido esto puede suponer la creacin y destruccin de cantidades in%entes de ob8etos (4ue puede 4ue ni si4uiera nos sean necesarios)- es decir- 4ue la accin de inflar un layout ) L puede ser bastante costosa- lo 4ue podr0a aumentar muc'o- y sin necesidad- el uso de C&<- de memoria- y de bater0a1 &ara ali.iar este problema- Android nos propone un m/todo 4ue permite reutilizar al%!n layout 4ue ya 'ayamos inflado con anterioridad y 4ue ya no nos 'a%a falta por al%!n moti.o- por e8emplo por4ue el elemento correspondiente de la lista 'a desaparecido de la pantalla al 'acer scroll1 De esta forma e.itamos todo el traba8o de crear y estructurar todos los ob8etos asociados al layout- por lo 4ue tan slo nos 4uedar0a obtener la referencia a ellos mediante ind6iew;yCdBE y modificar sus propiedades1 K&ero cmo podemos reutilizar estos layouts >obsoletos?L &ues es bien sencillo- siempre 4ue e#ista al%!n layout 4ue pueda ser reutilizado /ste se .a a recibir a tra./s del parmetro convert6iew del m/todo get6iewBE1 De esta forma- en los casos en 4ue /ste no sea null podremos ob.iar el traba8o de inflar el layout1 Veamos cmo 4uedar0a el m/tod get6iewBE tras esta optimizacin:
public 6iew get6iewBint positionG 6iew convert6iewG 6iewHroup parentE ! 6iew item # convert6iew; i Bitem ## nullE ! 3ayoutCn later in later # context.get3ayoutCn laterBE; item # in later.in lateBR.layout.listitem(titularG nullE; " 5ext6iew lbl5itulo # B5ext6iewEitem. ind6iew;yCdBR.id.3bl5ituloE; lbl5itulo.set5extBdatosUpositionV.get5ituloBEE;

http://www.sgoliver.net/ log/!p"1313 #$gina 46 de 156

Desarrollo en Android

5ext6iew lblDubtitulo # B5ext6iewEitem. ind6iew;yCdBR.id.3blDub5ituloE; lblDubtitulo.set5extBdatosUpositionV.getDubtituloBEE; returnBitemE; "

"i aDadimos ms elementos a la lista y e8ecutamos a'ora la aplicacin podemos comprobar 4ue al 'acer scroll sobre la lista todo si%ue funcionando con normalidad- con la diferencia de 4ue le estamos a'orrando %ran cantidad de traba8o a la C&<1

&ero .amos a ir un poco ms all1 Con la optimizacin 4ue acabamos de implementar conse%uimos a'orrarnos el traba8o de inflar el layout definido cada .ez 4ue se muestra un nue.o elemento1 &ero a!n 'ay otras dos llamadas relati.amente costosas 4ue se si%uen e8ecutando en todas las llamadas1 e refiero a la obtencin de la referencia a cada uno de los ob8etos a modificar mediante el m/todo ind6iew;yCdBE1 La b!s4ueda por ID de un control determinado dentro del rbol de ob8etos de un layout tambi/n puede ser una tarea costosa
http://www.sgoliver.net/ log/!p"1313 #$gina 47 de 156

Desarrollo en Android

dependiendo de la comple8idad del propio layout1K&or 4u/ no apro.ec'amos 4ue estamos >%uardando? un layout anterior para %uardar tambi/n la referencia a los controles 4ue lo forman de forma 4ue no ten%amos 4ue .ol.er a buscarlosL &ues eso es e#actamente lo 4ue .amos a 'acer mediante lo 4ue en los e8emplos de Android llaman un 6iew,older1 La clase 6iew,older tan slo .a a contener una referencia a cada uno de los controles 4ue ten%amos 4ue manipular de nuestro layout- en nuestro caso las dos eti4uetas de te#to1 Definamos por tanto esta clase de la si%uiente forma:
static class 6iew,older ! 5ext6iew titulo; 5ext6iew subtitulo; "

La idea ser por tanto crear e inicializar el ob8eto 6iew,older la primera .ez 4ue inflemos un elemento de la lista y asociarlo a dic'o elemento de forma 4ue posteriormente podamos recuperarlo fcilmente1 K&ero dnde lo %uardamosL Pcil- en Android todos los controles tienen una propiedad llamada 5ag (podemos asi%narla y recuperarla mediante los m/todos set5agBE y get5agBE respecti.amente) 4ue puede contener cual4uier tipo de ob8eto- por lo 4ue resulta ideal para %uardar nuestro ob8eto 6iew,older1 De esta forma- cuando el parmetro convert6iew lle%ue informado sabremos 4ue tambi/n tendremos disponibles las referencias a sus controles 'i8os a tra./s de la propiedad 5ag1 Veamos el cdi%o modificado de get6iewBE para apro.ec'ar esta nue.a optimizacin:
public 6iew get6iewBint positionG 6iew convert6iewG 6iewHroup parentE ! 6iew item # convert6iew; 6iew,older holder; i Bitem ## nullE ! 3ayoutCn later in later # context.get3ayoutCn laterBE; item # in later.in lateBR.layout.listitem(titularG nullE; holder # new 6iew,olderBE; holder.titulo # B5ext6iewEitem. ind6iew;yCdBR.id.3bl5ituloE; holder.subtitulo # B5ext6iewEitem. ind6iew;yCdBR.id.3blDub5ituloE; item.set5agBholderE; " else ! " holder.titulo.set5extBdatosUpositionV.get5ituloBEE; holder.subtitulo.set5extBdatosUpositionV.getDubtituloBEE; returnBitemE;

holder # B6iew,olderEitem.get5agBE;

http://www.sgoliver.net/ log/!p"1313 #$gina 48 de 156

Desarrollo en Android

"

Con estas dos optimizaciones 'emos conse%uido 4ue la aplicacin sea muc'o ms respetuosa con los recursos del dispositi.o de nuestros usuarios- al%o 4ue sin duda nos a%radecern1

Interfaz de usuario en Android: Controles de seleccin <I-=


(ras 'aber .isto en art0culos anteriores los dos controles de seleccin ms comunes en cual4uier interfaz %rfica- como son las listas desple%ables (Dpinner) y las listas >fi8as? (3ist6iew)tanto en su .ersin bsica como optimizada- en este nue.o art0culo .amos a terminar de comentar los controles de seleccin con otro menos com!n pero no por ello menos !til- el control Hrid6iew1 El control Hrid6iew de Android presenta al usuario un con8unto de opciones seleccionables distribuidas de forma tabular- o dic'o de otra forma- di.ididas en filas y columnas1 Dada la naturaleza del control ya pod/is ima%inar sus propiedades ms importantes- 4ue paso a enumerar a continuacin:

android4num@olumns- indica el n!mero de columnas de la tabla o >auto( it? si 4ueremos 4ue sea calculado por el propio sistema operati.o a partir de las si%uientes propiedades1 android4columnLidth- indica el anc'o de las columnas de la tabla1 android4horiNontalDpacing- indica el espacio 'orizontal entre celdas1 android4verticalDpacing- indica el espacio .ertical entre celdas1 android4stretch<ode- indica 4u/ 'acer con el espacio 'orizontal sobrante1 "i se establece al .alor >columnLidth? este espacio ser absorbido a partes i%uales por las columnas de la tabla1 "i por el contrario se establece a >spacingLidth? ser absorbido a partes i%uales por los espacios entre celdas1

http://www.sgoliver.net/ log/!p"1313 #$gina 49 de 156

Desarrollo en Android

Veamos cmo definir0amos un Hrid6iew de e8emplo en nuestra aplicacin:


.Hrid6iew android4id#079id/HridApciones0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4num@olumns#0auto( it0 android4columnLidth#01$px0 android4horiNontalDpacing#0Wpx0 android4verticalDpacing#0*$px0 android4stretch<ode#0columnLidth0 / 2

<na .ez definida la interfaz de usuario- la forma de asi%nar los datos desde el cdi%o de la aplicacin es completamente anlo%a a la ya comentada tanto para las listas desple%ables como para las listas estticas: creamos un array %en/rico 4ue conten%a nuestros datos de pruebadeclaramos un adaptador de tipo ArrayAdapter pasndole en este caso un layout %en/rico (simple(list(item(*- compuesto por un simple 5ext6iew) y asociamos el adaptador al control Hrid6iew mediante su m/todo set>dapterBE:

private DtringUV datos # new DtringU&WV; //... orBint i#*; i.#&W; i99E datosUi-*V # 0Jato 0 9 i; >rray>dapter.Dtring2 adaptador # new >rray>dapter.Dtring2BthisG android.R.layout.simple(list(item(*G datosE; inal Hrid6iew grdApciones # BHrid6iewE ind6iew;yCdBR.id.HridApcionesE; grdApciones.set>dapterBadaptadorE;

&or defecto- los datos del array se aDadirn al control Hrid6iew ordenados por filas- y por supuesto- si no caben todos en la pantalla se podr 'acer scroll sobre la tabla1 Vemos en una ima%en cmo 4ueda nuestra aplicacin de prueba:

http://www.sgoliver.net/ log/!p"1313 #$gina 50 de 156

Desarrollo en Android

En cuanto a los e.entos disponibles- el ms interesante .uel.e a ser el lanzado al seleccionarse una celda determinada de la tabla: onCtemDelected1 Este e.ento podemos capturarlo de la misma forma 4ue 'ac0amos con los controles Dpinner y 3ist6iew1 Veamos un e8emplo de cmo 'acerlo:
grdApciones.setAnCtemDelected3istenerB new >dapter6iew.AnCtemDelected3istenerBE ! public void onCtemDelectedB>dapter6iew./2 parentG android.view.6iew vG int positionG long idE ! lbl<ensaje.set5extB0Deleccionado4 0 9 datosUpositionVE; " public void on:othingDelectedB>dapter6iew./2 parentE ! lbl<ensaje.set5extB00E; " "E;

(odo lo comentado 'asta el momento se refiere al uso bsico del control Hrid6iew- pero por supuesto podr0amos aplicar de forma practicamente directa todo lo comentado para las listas en los dos art0culos anteriores- es decir- la personalizacin de las celdas para presentar datos comple8os creando nuestro propio adaptador- y las distintas optimizaciones para me8orar el rendiemiento de la aplicacin y el %asto de bater0a1 2 con esto finalizamos todo lo 4ue ten0a pre.isto contar sobre los distintos controles disponibles >de serie? en Android para construir nuestras interfaces de usuario1 E#isten muc'os ms- y es posible 4ue los comentemos ms adelante en al%!n otro art0culo- pero por el momento nos .amos a conformar con los ya .istos1 En el pr#imo art0culo- y para terminar con la serie dedicada a los controles Android- .eremos las distintas formas de crear controles de usuario personalizados1

http://www.sgoliver.net/ log/!p"1313 #$gina 51 de 156

Desarrollo en Android

Interfaz de usuario en Android: Controles personalizados <I=


En art0culos anteriores de la serie 'emos conocido y aprendido a utilizar muc'os de los controles 4ue proporciona Android en su "D;1 Con la ayuda de estos controles podemos diseDar interfaces %rficas de lo ms .ariopinto pero en ocasiones- si 4ueremos dar un to4ue especial y ori%inal a nuestra aplicacin- o simplemente si necesitamos cierta funcionalidad no presente en los componentes estandar de Android- nos .emos en la necesidad de crear nuestros propios controles personalizados- diseDados a medida de nuestros re4uisitos1 Android admite por supuesto crear controles personalizados- y permite 'acerlo de diferentes formas: C1 E#tendiendo la funcionalidad de un control ya e#istente1 B1 Combinando .arios controles para formar un otro ms comple8o1 61 DiseDando desde cero un nue.o control1

http://www.sgoliver.net/ log/!p"1313 #$gina 52 de 156

Desarrollo en Android

En este primer art0culo sobre el tema .amos a 'ablar de la primera opcin- es decir- .amos a .er cmo podemos crear un nue.o control partiendo de la base de un control ya e#istente1 A modo de e8emplo- .amos a e#tender el control 8dit5ext (cuadro de te#to) para 4ue muestre en todo momento el n!mero de caracteres 4ue contiene a medida 4ue se escribe en /l1 Intentar0amos emular al%o as0 como el editor de mensa8es " " del propio sistema operati.o- 4ue nos a.isa del n!mero de carateres 4ue contiene el mensa8e1 En nuestro caso- como resultado obtendremos un control como el 4ue se muestra en la si%uiente ima%en:

Como .emos- en la es4uina superior derec'a del cuadro de te#to .amos a mostrar el n!mero de caracteres del mensa8e de te#to introducido- 4ue ira actualizndose a medida 4ue modificamos el te#to1 &ara empezar- .amos a crear una nue.a clase 8a.a 4ue e#tienda del control 4ue 4ueremos utilizar como base- en este caso 8dit5ext1
public class 8xtended8dit5ext extends 8dit5ext ! //... "

(ras esto- sobreescribiremos siempre los tres constructores 'eredados- donde por el momento nos limitaremos a llamar al mismo constructor de la clase padre1
public 8xtended8dit5extB@ontext contextG >ttributeDet attrsG int de DtyleE ! superBcontextG attrsGde DtyleE; " public 8xtended8dit5extB@ontext contextG >ttributeDet attrsE ! superBcontextG attrsE;

http://www.sgoliver.net/ log/!p"1313 #$gina 53 de 156

Desarrollo en Android

" public 8xtended8dit5extB@ontext contextE ! superBcontextE; "

&or !ltimo el paso ms importante1 Dado 4ue 4ueremos modificar el aspecto del control para aDadir el contador de caracteres tendremos 4ue sobreescribir el e.ento onJrawBE- 4ue es llamado por Android cada .ez 4ue 'ay 4ue redibu8ar el control en pantalla1 Este m/todo recibe como parmetro un ob8eto @anvas- 4ue no es ms 4ue el >lienzo? sobre el 4ue podemos dibu8ar todos los elementos e#tra necesarios en el control1 El ob8eto Can.as- proporciona una serie de m/todos para dibu8ar cual4uier tipo de elemento (lineas- rectn%ulos- elipses- te#to- bitmaps- G) sobre el espacio ocupado por el control1 En nuestro caso tan slo .amos a necesitar dibu8ar sobre el control un rectn%ulo 4ue sir.a de fondo para el contador y el te#to del contador con el n!mero de caracteres actual del cuadro de te#to1 3o .amos a entrar en muc'os detalles sobre la forma de dibu8ar %rficos ya 4ue /se ser tema de otro art0culo- pero .amos a .er al menos las acciones principales1 En primer lu%ar definiremos los >pinceles? (ob8etos Kaint) 4ue utilizaremos para dibu8ar- uno de ellos (p*) de color ne%ro y relleno slido para el fondo del contador- y otro (p&) de color blanco para el te#to1
Kaint p* # new KaintBKaint.>:5C(>3C>D(F3>HE; p*.set@olorB@olor.;3>@YE; p*.setDtyleBDtyle.FC33E; Kaint p& # new KaintBKaint.>:5C(>3C>D(F3>HE; p&.set@olorB@olor.L,C58E;

Dado 4ue estos elementos tan slo 'ar falta crearlos la primera .ez 4ue se dibu8e el control- para e.itar traba8o innecesario no incluiremos su definicin en el m/todo onJrawBE- sino 4ue los definiremos como atributos de la clase y los inicializaremos en el constructor del control (en los tres)1 <na .ez definidos los diferentes pinceles necesarios- dibu8aremos el fondo y el te#to del contador mediante los m/todos drawRectBE y draw5extBE- respecti.amente- del ob8eto can.as recibido en el e.ento1
7Averride public void onJrawB@anvas canvasE ! //3lamamos al mZtodo de la clase base B8dit5extE super.onJrawBcanvasE; //Jibujamos el ondo negro del contador canvas.drawRectBthis.getLidthBE-'$G WG

http://www.sgoliver.net/ log/!p"1313 #$gina 54 de 156

Desarrollo en Android

this.getLidthBE-WG &$G p*E; //Jibujamos el n[mero de caracteres sobre el contador canvas.draw5extB00 9 this.get5extBE.toDtringBE.lengthBEG this.getLidthBE-&1G *%G p&E; "

Como puede comprobarse- a estos m/todos se les pasar como parmetro las coordenadas del elemento a dibu8ar relati.as al espacio ocupado por el control y el pincel a utilizar en cada caso1 Fec'o esto- ya tenemos finalizado nuestro cuadro de te#to personalizado con contador de caracteres1 &ara aDadirlo a la interfaz de nuestra aplicacin lo incluiremos en el layout ) L de la .entana tal como 'ar0amos con cual4uier otro control- teniendo en cuenta 4ue deberemos 'acer referencia a /l con el nombre completo de la nue.a clase creada (incluido el pa4uete 8a.a)4ue en mi caso particular ser0a net.sgoliver.8xtended8dit5ext1
.net.sgoliver.8xtended8dit5ext android4id#079id/5xtKrueba0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 / 2

En el si%uiente art0culo .eremos cmo crear un control personalizado utilizando la se%unda de las opciones e#puestas- es decir- combinando .arios controles ya e#istentes1 Comentaremos adems como aDadir e.entos y propiedades personalizadas a nuestro control y cmo 'acer referencia a dic'as propiedades desde su definicin ) L1

Interfaz de usuario en Android: Controles personalizados <II=


s%oli.er .iles- &ro%ramacin BRCRACBAB6 2a .imos cmo Android ofrece tres formas diferentes de crear controles personalizados para nuestras aplicaciones y dedicamos el art0culo anterior a comentar la primera de las posibilidades4ue consist0a en e#tender la funcionalidad de un control ya e#istente1 En este se%undo art0culo sobre el tema .amos a centrarnos en la creacin de controles compuestos- es decir- controles personalizados construidos a partir de .arios controles estandarcombinando la funcionalidad de todos ellos en un slo control reutilizable en otras aplicaciones1

http://www.sgoliver.net/ log/!p"1313 #$gina 55 de 156

Desarrollo en Android

Como e8emplo ilustrati.o .amos a crear un control de identificacin (lo%in) formado por .arios controles estandar de Android1 La idea es conse%uir un control como el 4ue se muestra la si%uiente ima%en es4uemtica:

A efectos didcticos- y para no complicar ms el e8emplo- .amos a aDadir tambi/n a la derec'a del botn /ogin una eti4ueta donde mostrar el resultado de la identificacin del usuario (lo%in correcto o incorrecto)1 A este control aDadiremos adems e7entos personalizados- .eremos como aDadirlo a nuestras aplicaciones- y 'aremos 4ue se pueda personalizar su aspecto desde el layout ) L de nuestra interfaz utilizando tambi/n atri;utos XML personalizados1 Empecemos por el principio1 Lo primero 4ue .amos a 'acer es construir la interfaz de nuestro control a partir de controles sencillos: eti4uetas- cuadros de te#to y botones1 &ara ello .amos a crear un nue.o layout ) L en la carpeta \res\layout con el nombre >control1login+,ml>1 En este fic'ero .amos a definir la estructura del control como ya 'emos .isto en muc'os art0culos anteriores- sin nin%una particularidad destacable1 &ara este caso 4uedar0a como si%ue:

.3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4orientation#0vertical0 android4padding#0*$dip02 .5ext6iew android4id#079id/5ext6iew$*0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4text#0-suario40 android4textDtyle#0bold0 /2 .8dit5ext android4id#079id/5xt-suario0

http://www.sgoliver.net/ log/!p"1313 #$gina 56 de 156

Desarrollo en Android
android4layout(height#0wrap(content0 android4layout(width#0 ill(parent0 /2 .5ext6iew android4id#079id/5ext6iew$&0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4text#0@ontrase]a40 android4textDtyle#0bold0 /2 .8dit5ext android4id#079id/5xtKassword0 android4layout(height#0wrap(content0 android4layout(width#0 ill(parent0 /2 .3inear3ayout android4orientation#0horiNontal0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 2 .;utton android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4id#079id/;tn>ceptar0 android4text#03ogin0 android4padding3e t#0&$dip0 android4paddingRight#0&$dip0 /2 .5ext6iew android4id#079id/3bl<ensaje0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4padding3e t#0*$dip0 android4textDtyle#0bold0 /2 ./3inear3ayout2 ./3inear3ayout2

Visualmente- nuestro control ya 4uedar0a como se obser.a en la si%uiente ima%en:

http://www.sgoliver.net/ log/!p"1313 #$gina 57 de 156

Desarrollo en Android

A continuacin crearemos su clase 8a.a asociada donde definiremos toda la funcionalidad de nuestro control1 Dado 4ue nos 'emos basado en un LinearLayout para construir el control- esta nue.a clase deber 'eredar tambi/n de la clase 8a.a LinearLayout de Android1 %ede&inire'os
ade'$s los dos (onstr)(tores $si(os:
public class @ontrol3ogin extends 3inear3ayout ! public @ontrol3oginB@ontext contextE ! superBcontextE; inicialiNarBE; " public @ontrol3oginB@ontext contextG >ttributeDet attrsE superBcontextG attrsE; inicialiNarBE; "

"

Como se puede obser.ar- todo el traba8o lo de8amos para el m/todo inicializar()1 En este m/todo inflaremos el layout ) L 4ue 'emos definido- obtendremos las referencias a todos los controles y asi%naremos los e.entos necesarios1 (odo esto ya lo 'emos 'ec'o en otras ocasiones- por lo 4ue tampoco nos .amos a detener muc'o1 *ea'os (o'o +)eda el ',todo (o'pleto:
private void inicialiNarBE ! //-tiliNamos el layout ^control(login^ como inter aN del control Dtring in Dervice # @ontext.3>_A-5(C:F3>58R(D8R6C@8; 3ayoutCn later li # B3ayoutCn laterEget@ontextBE.getDystemDerviceBin DerviceE; li.in lateBR.layout.control(loginG thisG trueE; //Abtenemoslas re erencias a los distintos control txt-suario # B8dit5extE ind6iew;yCdBR.id.5xt-suarioE; txtKassword # B8dit5extE ind6iew;yCdBR.id.5xtKasswordE; btn3ogin # B;uttonE ind6iew;yCdBR.id.;tn>ceptarE; lbl<ensaje # B5ext6iewE ind6iew;yCdBR.id.3bl<ensajeE; //>sociamos los eventos necesarios asignar8ventosBE; "

De8aremos por a'ora a un lado el m/todo asignar8ventosBE- .ol.eremos sobre /l ms tarde1 Con esto ya tenemos definida la interfaz y la funcionalidad bsica del nue.o control por lo 4ue ya podemos utilizarlo desde otra acti.idad como si se tratase de cual4uier otro control predefinido1 &ara ello 'aremos referencia a /l utilizando la ruta completa del pa4uete 8a.a utilizado- en nuestro caso 4uedar0a como net.sgoliver.@ontrol3ogin1 Vamos a insertar nuestro nue.o control en la acti.idad principal de la aplicacin:
.3inear3ayout

http://www.sgoliver.net/ log/!p"1313 #$gina 58 de 156

Desarrollo en Android
xmlns4android#0http4//schemas.android.com/apk/res/android android4orientation#0vertical0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4padding#0*$dip0 2 .net.sgoliver.@ontrol3ogin android4id#079id/@tl3ogin0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4background#0O$$$$>>0 /2 ./3inear3ayout2

Dado 4ue estamos 'eredando de un 3inear3ayout podemos utilizar en principio cual4uier atributo permitido para dic'o tipo de controles- en este caso 'emos establecido por e8emplo los atributos layout(width- layout(height y background1 "i e8ecutamos a'ora la aplicacin .eremos cmo ya 'emos conse%uido %ran parte de nuestro ob8eti.o:

Vamos a aDadir a'ora al%o ms de funcionalidad1 En primer lu%ar- podemos aDadir al%!n m/todo p!blico e#clusi.o de nuestro control1 Como e8emplo podemos aDadir un m/todo 4ue permita modificar el te#to de la eti4ueta de resultado del lo%in1 -sto no tiene ning)na di&i()ltad:
public void set<ensajeBDtring msgE ! lbl<ensaje.set5extBmsgE; "

http://www.sgoliver.net/ log/!p"1313 #$gina 59 de 156

Desarrollo en Android

En se%undo lu%ar- todo control 4ue se precie debe tener al%unos e.entos 4ue nos permitan responder a las acciones del usuario de la aplicacin1 As0 por e8emplo- los botones tienen un e.ento An@lick- las listas un e.ento AnCtemDelected- etc1 &ues bien- nosotros .amos a dotar a nuestro control de un e.ento personalizado- llamado An3ogin- 4ue se lance cuando el usuario introduce sus credenciales de identificacin y pulsa el botn >Lo%in?1 &ara ello- lo primero 4ue .amos a 'acer es concretar los detalles de dic'o e.ento- creando una interfaz 8a.a para definir su listener1 Esta interfaz tan slo tendr un m/todo llamado onLo%in() 4ue de.ol.er los dos datos introducidos por el usuario (usuario y contraseDa)1 *e'os (.'o
+)eda:
package net.sgoliver; public inter ace An3ogin3istener ! void on3oginBDtring usuarioG Dtring passwordE; "

A continuacin- deberemos aDadir un nue.o miembro de tipo An3ogin3istener a la clase @ontrol3ogin- y un m/todo p!blico 4ue permita suscribirse al nue.o e.ento1
public class @ontrol3ogin extends 3inear3ayout ! private An3ogin3istener listener; //... public void setAn3ogin3istenerBAn3ogin3istener ! listener # l; "

lE

"

Con esto- la aplicacin principal ya puede suscribirse al e.ento An3ogin y e8ecutar su propio cdi%o cuando /ste se %enere1 K&ero cundo se %enera e#actamenteL Di8imos antes 4ue 4ueremos lanzar el e.ento An3ogin cuando el usuario pulse el botn >Lo%in? de nuestro control1 &ues bien- para 'acerlo- .ol.amos al m/todo asignar8ventosBE 4ue antes de8amos aparcado1 En este m/todo .amos a implementar el e.ento An@lick del botn de Lo%in para lanzar el nue.o
http://www.sgoliver.net/ log/!p"1313 #$gina 60 de 156

Desarrollo en Android

e.ento An3ogin del control1 KConfundidoL1 Intento e#plicarlo de otra forma1 Vamos a apro.ec'ar el e.ento An@lickBE del botn Lo%in (4ue es un e.ento interno a nuestro controlno se .er desde fuera) para lanzar 'acia el e#terior el e.ento An3oginBE (4ue ser el 4ue debe capturar y tratar la aplicacin 4ue 'a%a uso del control)1

&ara ello- implementaremos el e.ento An@lick como ya 'emos 'ec'o en otras ocasiones y como acciones %eneraremos el e.ento An3ogin de nuestro listener pasndole los datos 4ue 'a introducido el usuario en los cuadros de te#to ><suario? y >ContraseDa?:
private void asignar8ventosBE ! btn3ogin.setAn@lick3istenerBnew An@lick3istenerBE ! 7Averride public void on@lickB6iew vE ! listener.on3oginBtxt-suario.get5extBE.toDtringBE G txtKassword.get5extBE.toDtringBEE; " "E; "

Con todo esto- la aplicacin principal ya puede implementar el e.ento *nLo%in de nuestro control- 'aciendo por e8emplo la .alidacin de las credenciales del usuario y modificando con.enientemente el te#to de la eti4ueta de resultado:

7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE;

http://www.sgoliver.net/ log/!p"1313 #$gina 61 de 156

Desarrollo en Android

ctl3ogin # B@ontrol3oginE ind6iew;yCdBR.id.@tl3oginE; ctl3ogin.setAn3ogin3istenerBnew An3ogin3istenerBE ! 7Averride public void on3oginBDtring usuarioG Dtring passwordE ! //6alidamos el usuario y la contrase]a i Busuario.e+ualsB0demo0E `` password.e+ualsB0demo0EE ctl3ogin.set<ensajeB03ogin correctoP0E; else ctl3ogin.set<ensajeB06uelva a intentarlo.0E; " "E; "

Veamos lo 4ue ocurre al e8ecutar a'ora la aplicacin principal e introducir las credenciales correctas:

3uestro control est ya completo- en aspecto y funcionalidad1 Femos personalizado su interfaz y 'emos aDadido m/todos y e.entos propios1 K&odemos 'acer al%o msL &ues s01 Cuando .imos cmo aDadir el control de lo%in al layout de la aplicacin principal di8imos 4ue pod0amos utilizar cual4uier atributo #ml permitido para el contenedor 3inear3ayout- ya 4ue nuestro control deri.aba de /ste1 &ero .amos a ir ms all y .amos a definir tambi/n atributos #ml e#clusi.os para nuestro control1 Como e8emplo- .amos a definir un atributo llamado login(text 4ue permita establecer el te#to del botn de Lo%in desde el propio layout #ml- es decir- en tiempo de diseDo1
http://www.sgoliver.net/ log/!p"1313 #$gina 62 de 156

Desarrollo en Android

&rimero .amos de declarar el nue.o atributo y lo .amos a asociar al control @ontrol3ogin1 Esto debe 'acerse en el fic'ero \res\values\attrs.xml1 &ara ello- aDadiremos una nue.a seccin Udeclare-styleable2 asociada a @ontrol3ogin dentro del elemento .resourcesV- donde indicaremos el nombre (name) y el tipo ( ormat) del nue.o atributo1
.resources2 .declare-styleable name#0@ontrol3ogin02 .attr name#0login(text0 ormat#0string0/2 ./declare-styleable2 ./resources2

En nuestro caso- el tipo del atributo ser string- dado 4ue contendr una cadena de te#to con el mensa8e a mostrar en el botn1 Con esto ya tendremos permitido el uso del nue.o atributo dentro del layout de la aplicacin principal1 A'ora nos falta procesar el atributo desde nuestro control personalizado1 Este tratamiento lo podemos 'acer en el construtor de la clase ControlLo%in1 &ara ello- obtendremos la lista de atributos asociados a @ontrol3ogin mediante el m/todo obtainDtyled>ttributesBE del conte#to de la aplicacin- obtendremos el .alor del nue.o atributo definido (mediante su ID- 4ue estar formado por la concatenacin del nombre del control y el nombre del atributo- en nuestro caso >@ontrol3ogin(login(text>) y modificaremos el te#to por defecto del control con el nue.o te#to1
public @ontrol3oginB@ontext contextG >ttributeDet attrsE ! superBcontextG attrsE; inicialiNarBE; // Krocesamos los atributos R<3 personaliNados 5yped>rray a # get@ontextBE.obtainDtyled>ttributesBattrsG R.styleable.@ontrol3oginE; Dtring texto;oton # a.getDtringB R.styleable.@ontrol3ogin(login(textE; btn3ogin.set5extBtexto;otonE; a.recycleBE; "

http://www.sgoliver.net/ log/!p"1313 #$gina 63 de 156

Desarrollo en Android

2a slo nos 4ueda utilizarlo1 &ara ello debemos primero declarar un nue.o espacio de nombres (namespace) local para el pa4uete 8a.a utilizado- 4ue en nuestro caso 'e llamado >s%o?: Cxmlns4sgo#0http4//schemas.android.com/apk/res/net.sgoliver0 (ras esto- slo 4ueda asi%nar el .alor del nue.o atributo precedido del nue.o namespace- por e8emplo con el te#to >Entrar?:
.3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android0 xmlns4sgo#0http4//schemas.android.com/apk/res/net.sgoliver 0 android4orientation#0vertical0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4padding#0*$dip0 2 .net.sgoliver.@ontrol3ogin android4id#079id/@tl3ogin0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4background#0O$$$$>>0 sgo4login(text#08ntrar0 /2 ./3inear3ayout2

Pinalmente- si e8ecutamos de nue.o la aplicacin principal .eremos cmo el botn de lo%in se inicializa con el te#to definido en el atributo login(text y 4ue todo contin!a funcionando correctamente1

Como resumen- en este art0culo 'emos .isto cmo construir un control android personalizado a partir de otros controles estandar- componiendo su interfaz- aDadiendo m/todos y e.entos
http://www.sgoliver.net/ log/!p"1313 #$gina 64 de 156

Desarrollo en Android

personalizados- e incluso aDadiendo nue.as opciones en tiempo de diseDo aDadiendo atributos #ml e#clusi.os1

Interfaz de usuario en Android: Controles personalizados <III=


En art0culos anteriores del curso ya comentamos dos de las posibles .0as 4ue tenemos para crear controles personalizados en Android: la primera de ellas e#tendiendo la funcionalidad de un control ya e#istente- y como se%unda opcin creando un nue.o control compuesto por otros ms sencillos1 En este nue.o art0culo .amos a describir la tercera de las posibilidades 4ue ten0amos disponibles4ue consiste en crear un control completamente desde cero- sin utilizar como base otros controles e#istentes1 Como e8emplo- .amos a construir un control 4ue nos permita seleccionar un color entre .arios disponibles1 Los colores disponibles .an a ser slo cuatro- 4ue se mostrarn en la fran8a superior del control1 En la parte inferior se mostrar el color seleccionado en cada momento- o permanecer ne%ro si a!n no se 'a seleccionado nin%!n color1 Val%a la si%uiente ima%en como muestra del aspecto 4ue tendr nuestro control de seleccin de color:

&or supuesto este control no tiene muc'a utilidad prctica dada su sencillez- pero creo 4ue puede ser.ir como e8emplo para comentar los pasos necesarios para construir cual4uier otro control ms comple8o1 Empecemos1 En las anteriores ocasiones .imos cmo el nue.o control creado siempre 'eredaba de al%!n otro control o contenedor ya e#istente1 En este caso sin embar%o- .amos a 'eredar nuestro contro directamente de la clase 6iew (clase padre de la %ran mayor0a de elementos .isuales de
http://www.sgoliver.net/ log/!p"1313 #$gina 65 de 156

Desarrollo en Android

Android)1 Esto implica- entre otras cosas- 4ue por defecto nuestro control no .a a tener nin%!n tipo de interfaz %rfica- por lo 4ue todo el traba8o de >dibu8ar? la interfaz lo .amos a tener 4ue 'acer nosotros1 Adems- como paso pre.io a la representacin %rfica de la interfaz- tambi/n .amos a tener 4ue determinar las dimensiones 4ue nuestro control tendr dentro de su elemento contenedor1 Como .eremos a'ora- ambas cosas se lle.arn a cabo redefiniendo dos e.entos de la clase 6iew- onJrawBE para el dibu8o de la interfaz- y on<easureBE para el clculo de las dimensiones1 &or lle.ar un orden cronol%ico- empecemos comentando el e.ento on<easureBE1 Este e.ento se e8ecuta automticamente cada .ez 4ue se necesita recalcular el tamaDo de un control1 &ero como ya 'emos .isto en .arias ocasiones- los elementos %rficos incluidos en una aplicacin Android se distribuyen por la pantalla de una forma u otra dependiendo del tipo de contenedor o la&o$t utilizado1 &or tanto- el tamaDo de un control determinado en la pantalla no depender slo de /l- sino de ciertas restricciones impuestas por su elemento contenedor o elemento padre1 &ara resol.er esto- en el e.ento on<easureBE recibiremos como parmetros las restricciones del elemento padre en cuanto a anc'o y alto del control- con lo 4ue podremos tenerlas en cuenta a la 'ora de determinar el anc'o y alto de nuestro control personalizado1 Estas restricciones se reciben en forma de ob8etos <easureDpec- 4ue contiene dos campos: modo y tama2o1 El si%nificado del se%undo de ellos es ob.io- el primero por su parte sir.e para matizar el si%nificado del se%undo1 e e#plico1 Este campo modo puede contener tres .alores posibles:

>5(<AD5: indica 4ue el control podr tener como m#imo el tama2o especificado1 8R>@53_: indica 4ue al control se le dar e#actamente el tama2o especificado1 -:DK8@CFC8J: indica 4ue el control padre no impone nin%una restriccin sobre el tamaDo1

Dependiendo de esta pare8a de datos- podremos calcular el tamaDo deseado para nuestro control1 &ara nuestro control de e8emplo- apuraremos siempre el tamaDo m#imo disponible (o un tamaDo por defecto de BRRWCRR en caso de no recibir nin%una restriccin)- por lo 4ue en todos los casos ele%iremos como tamaDo de nuestro control el tamaDo recibido como parmetro:

http://www.sgoliver.net/ log/!p"1313 #$gina 66 de 156

Desarrollo en Android

7Averride protected void on<easureBint width<easureDpecG int height<easureDpecE ! int ancho # calcular>nchoBwidth<easureDpecE; int alto # calcular>ltoBheight<easureDpecE; set<easuredJimensionBanchoG altoE;

"

private int calcular>ltoBint limitesDpecE ! int res # *$$; //>lto por de ecto int modo # <easureDpec.get<odeBlimitesDpecE; int limite # <easureDpec.getDiNeBlimitesDpecE; i Bmodo ## <easureDpec.>5(<AD5E ! res # limite; " else i Bmodo ## <easureDpec.8R>@53_E ! res # limite; " return res; " private int calcular>nchoBint limitesDpecE ! int res # &$$; //>ncho por de ecto int modo # <easureDpec.get<odeBlimitesDpecE; int limite # <easureDpec.getDiNeBlimitesDpecE; i Bmodo ## <easureDpec.>5(<AD5E ! res # limite; " else i Bmodo ## <easureDpec.8R>@53_E ! res # limite; " return res;

"

Como nota importante- al final del e.ento on easure() siempre debemos llamar al m/todo set<easuredJimensionBE pasando como parmetros el anc'o y alto calculados para nuestro control1
http://www.sgoliver.net/ log/!p"1313 #$gina 67 de 156

Desarrollo en Android

Con esto ya 'emos determinado las dimensiones del control- por lo 4ue tan slo nos 4ueda dibu8ar su interfaz %rfica1 Como 'emos indicado antes- esta tarea se realiza dentro del e.ento onJrawBE1 Este e.ento recibe como parmetro un ob8eto de tipo @anvas- sobre el 4ue podremos e8ecutar todas las operaciones de dibu8o de la interfaz1 3o .oy a entrar en detalles de la clase @anvas- por4ue /se ser tema central de un pr#imo art0culo1 &or a'ora nos .amos a conformar sabiendo 4ue es la clase 4ue contiene la mayor parte de los m/todos de dibu8o en interfaces Android- por e8emplo drawRectBE para dibu8ar rectn%ulos- draw@ircleBE para c0rculos- draw;itmapBE para ima%enes- draw5extBE para te#to- e infinidad de posibilidades ms1 &ara consultar todos los m/todos disponibles puedes diri%irte a la documentacin oficial de la clase Can.as de Android1 Adems de la clase @anvas- tambi/n me %ustar0a destacar la clase Kaint- 4ue permite definir el estilo de dibu8o a utilizar en los metodos de dibu8o de @anvas- por e8emplo el anc'o de trazado de las l0neas- los colores de relleno- etc1 &ara nuestro e8emplo no necesitar0amos conocer nada ms- ya 4ue la interfaz del control es relati.amente sencilla1 Vemos primero el cdi%o y despu/s comentamos los pasos realizados:
7Averride protected void onJrawB@anvas canvasE ! //Abtenemos las dimensiones del control int alto # get<easured,eightBE; int ancho # get<easuredLidthBE; //@olores Jisponibles Kaint pRelleno # new KaintBE; pRelleno.setDtyleBDtyle.FC33E; pRelleno.set@olorB@olor.R8JE; canvas.drawRectB$G $G ancho/)G alto/&G pRellenoE; pRelleno.set@olorB@olor.HR88:E; canvas.drawRectBancho/)G $G &?Bancho/)EG alto/&G pRellenoE; pRelleno.set@olorB@olor.;3-8E; canvas.drawRectB&?Bancho/)EG $G '?Bancho/)EG alto/&G pRellenoE; pRelleno.set@olorB@olor._833ALE; canvas.drawRectB'?Bancho/)EG $G )?Bancho/)EG alto/&G pRellenoE; //@olor Deleccionado pRelleno.set@olorBcolorDeleccionadoE; canvas.drawRectB$G alto/&G anchoG altoG pRellenoE; //<arco del control

http://www.sgoliver.net/ log/!p"1313 #$gina 68 de 156

Desarrollo en Android
Kaint p;orde # new KaintBE; p;orde.setDtyleBDtyle.D5RAY8E; p;orde.set@olorB@olor.L,C58E; canvas.drawRectB$G $G ancho-*G alto/&G p;ordeE; canvas.drawRectB$G $G ancho-*G alto-*G p;ordeE;

"

En primer lu%ar obtenemos las dimensiones calculadas en la !ltima llamada a on<easureBE mediante los m/todos get<easured,eightBE y get<easuredLidthBE1 &osteriormente definimos un ob8eto Kaint 4ue usaremos para dibu8ar los rellenos de cada color seleccionable1 &ara indicar 4ue se trata del color de relleno a utilizar utilizaremos la llamada a setDtyleBDtyle.FC33E1 (ras esto- ya slo debemos dibu8ar cada uno de los cuadros en su posicin correspondiente con drawRectBE- estableciendo antes de cada uno de ellos el color deseado con set@olorBE1 &or !ltimo- dibu8amos el marco del control definiendo un nue.o ob8eto Kaint- esta .ez con estilo Dtyle.D5RAY8 dado 4ue se utilizar para dibu8ar slo l0neas- no rellenos1 Con esto- ya deber0amos tener un control con el aspecto e#acto 4ue definimos en un principio1 El si%uiente paso ser definir su funcionalidad implementando los e.entos a los 4ue 4ueramos 4ue responda nuestro control- tanto e.entos internos como e#ternos1 En nuestro caso slo .amos a tener un e.ento de cada tipo1 En primer lu%ar definiremos un e.ento interno (e.ento 4ue slo 4ueremos capturar de forma interna al control- sin e#ponerlo al usuario) para responder a las pulsaciones del usuario sobre los colores de la zona superior- y 4ue utilizaremos para actualizar el color de la zona inferior con el color seleccionado1 &ara ello implementaremos el e.ento on5ouchBE- lanzado cada .ez 4ue el usuario toca la pantalla sobre nuestro control1 La l%ica ser sencilla- simplemente consultaremos las coordenadas donde 'a pulsado el usuario (mediante los m/todos getRBE y get_BE)- y dependiendo del lu%ar pulsado determinaremos el color sobre el 4ue se 'a seleccionado y actualizaremos el .alor del atibuto colorDeleccionado1 Pinalmente- llamamos al m/todo invalidateBE para refrescar la interfaz del control- refle8ando as0 el cambio en el color seleccionado- si se 'a producido1
7Averride public boolean on5ouch8ventB<otion8vent eventE ! //Di se ha pulsado en la Nona superior i Bevent.get_BE 2 $ `` event.get_BE . Bget<easured,eightBE/&EE ! //Di se ha pulsado dentro de los lXmites del control i Bevent.getRBE 2 $ `` event.getRBE . get<easuredLidthBEE ! //Jeterminamos el color seleccionado seg[n el punto pulsado i Bevent.getRBE 2 Bget<easuredLidthBE/)E?'E colorDeleccionado # @olor._833AL; else i Bevent.getRBE 2 Bget<easuredLidthBE/)E?&E colorDeleccionado # @olor.;3-8; else i Bevent.getRBE 2 Bget<easuredLidthBE/)E?*E colorDeleccionado # @olor.HR88:; else

http://www.sgoliver.net/ log/!p"1313 #$gina 69 de 156

Desarrollo en Android
colorDeleccionado # @olor.R8J; //Re rescamos el control this.invalidateBE;

" " return super.on5ouch8ventBeventE; "

En se%undo lu%ar crearemos un e.ento e#terno personalizado- 4ue lanzaremos cuando el usuario pulse sobre la zona inferior del control- como una forma de aceptar definiti.amente el color seleccionado1 Llamaremos a este e.ento onDelected@olorBE1 &ara crearlo actuaremos de la misma forma 4ue ya .imos en el art0culo anterior1 &rimero definiremos una interfaz para el listener de nuestro e.ento:
package net.sgoliver.android; public inter ace An@olorDelected3istener ! void on@olorDelectedBint colorE; "

&osteriormente- definiremos un ob8eto de este tipo como atributo de nuestro control y escribiremos un nue.o m/todo 4ue permita a las aplicaciones suscribirse al e.ento:
public class Delector@olor extends 6iew ! private An@olorDelected3istener listener; //... public void setAn@olorDelected3istenerBAn@olorDelected3istener lE ! " " listener # l;

2 ya slo nos 4uedar0a lanzar el e.ento en el momento preciso1 Esto tambi/n lo 'aremos dentro del e.ento on5ouchBE- cuando detectemos 4ue el usuario 'a pulsado en la zona inferior de nuestro control:
7Averride public boolean on5ouch8ventB<otion8vent eventE ! //Di se ha pulsado en la Nona superior i Bevent.get_BE 2 $ `` event.get_BE . Bget<easured,eightBE/&EE ! //... "

http://www.sgoliver.net/ log/!p"1313 #$gina 70 de 156

Desarrollo en Android
//Di se ha pulsado en la Nona in erior else i Bevent.get_BE 2 Bget<easured,eightBE/&E `` event.get_BE . get<easured,eightBEE ! //3anNamos el evento externo de selecciTn de color listener.on@olorDelectedBcolorDeleccionadoE; " return super.on5ouch8ventBeventE; "

Con esto- nuestra aplicacin principal ya podr0a suscribirse a este nue.o e.ento para estar informada cada .ez 4ue se seleccione un color1 /irva la sig)iente plantilla a 'odo de
e0e'plo:
public class @ontrolKersonaliNado extends >ctivity ! private Delector@olor ctl@olor; 7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; ctl@olor # BDelector@olorE ind6iew;yCdBR.id.sc@olorE; ctl@olor.setAn@olorDelected3istenerBnew An@olorDelected3istenerBE ! 7Averride public void on@olorDelectedBint colorE ! //>+uX se tratarXa el color seleccionado BparSmetro ^color^ "E; " " " //...

Con esto- tendr0amos finalizado nuestro control completamente personalizado- 4ue 'emos construido sin utilizar como base nin%!n otro control predefinido- definiendo desde cero tanto su aspecto .isual como su funcionalidad interna o sus e.entos p!blicos1

http://www.sgoliver.net/ log/!p"1313 #$gina 71 de 156

Desarrollo en Android

Mens en Android <I=: Conceptos ;"sicos


En los dos si%uientes art0culos del Curso de &ro%ramacin Android nos .amos a centrar en la creacin de men!s de opciones en sus diferentes .ariantes1 En Android podemos encontrar 6 tipos diferentes de men!s:

Mens Principales1 Los ms 'abituales- aparecen en la zona inferior de la pantalla al pulsar el botn XmenuY del tel/fono1 'u;mens1 "on men!s secundarios 4ue se pueden mostrar al pulsar sobre una opcin de un men! principal1 Mens Conte6tuales1 Ztiles en muc'as ocasiones- aparecen al realizar una pulsacin lar%a sobre al%!n elemento de la pantalla1

En este primer art0culo sobre el tema .eremos cmo traba8ar con los dos primeros tipos de men!s1 En el si%uiente- comentaremos los men!s conte#tuales y al%unos caracter0sticas ms a.anzadas1 Como casi siempre- .amos a tener dos alternati.as a la 'ora de mostrar un men! en nuestra aplicacin Android1 La primera de ellas mediante la definicin del men! en un fic'ero ) L- y la se%unda creando el men! directamente mediante cdi%o1 En este art0culo .eremos ambas alternati.as1 Veamos en primer lu%ar cmo crear un men! a partir de su definicin en ) L1 Los fic'eros ) L de men! se deben colocar en la carpeta >res\menu? de nuestro proyecto y tendrn una estructura anlo%a a la del si%uiente e8emplo:
./xml version#0*.$0 encoding#0ut -10/2 .menu xmlns4android#0http4//schemas.android.com/apk/res/android0 2 .item android4id#079id/<nuApc*0 android4title#0Apcion*0 android4icon#07drawable/tag02./item2 .item android4id#079id/<nuApc&0 android4title#0Apcion&0 android4icon#07drawable/ ilter02./item2

http://www.sgoliver.net/ log/!p"1313 #$gina 72 de 156

Desarrollo en Android
.item android4id#079id/<nuApc'0 android4title#0Apcion'0 android4icon#07drawable/chart02./item2 ./menu2

Como .emos- la estructura bsica de estos fic'eros es muy sencilla1 (endremos un elemento principal .menu2 4ue contendr una serie de elementos .item2 4ue se correspondern con las distintas opciones a mostrar en el men!1 Estos elementos UitemV tendrn a su .ez .arias propiedades bsicas- como su ID (android4id)- su te#to (android4title) o su icono (android4icon)1 Los iconos utilizados debern estar por supuesto en las carpetas >res\drawable-M? de nuestro proyecto (al final del art0culo os paso unos enlaces donde pod/is conse%uir al%unos iconos de men! Android %ratuitos)1 <na .ez definido el men! en el fic'ero ) L- tendremos 4ue implementar el e.ento on@reateAptions<enuBE de la acti.idad 4ue 4ueremos 4ue lo muestre1 En este e.ento deberemos >inflar? el men! de forma parecida a cmo ya 'emos 'ec'o otras .eces con otro tipo de layouts1 &rimero obtendremos una referencia al inflater mediante el m/todo get<enuCn laterBE y posteriormente %eneraremos la estructura del men! llamando a su m/todo in ateBE pasndole como parmetro el ID del menu definido en ) L- 4ue en nuestro caso ser R.menu.menu(principal1 &or !ltimo de.ol.eremos el .alor true para confirmar 4ue debe mostrarse el men!1
7Averride public boolean on@reateAptions<enuB<enu menuE ! //>lternativa * <enuCn later in later # get<enuCn laterBE; in later.in lateBR.menu.menu(principalG menuE; return true; "

2 ya 'emos terminado- con estos sencillos pasos nuestra aplicacin ya deber0a mostrar sin problemas el men! 4ue 'emos constru0do- aun4ue toda.0a nos faltar0a implementar la funcionalidad de cada una de las opciones mostradas1

http://www.sgoliver.net/ log/!p"1313 #$gina 73 de 156

Desarrollo en Android

Como 'emos comentado antes- este mismo men! tambi/n lo podr0amos crear directamente mediante cdi%o- tambi/n desde el e.ento on@reateAptions<enuBE1 &ara ello- para aDadir cada opcin del men! podemos utilizar el m/todo addBE sobre el ob8eto de tipo <enu 4ue nos lle%a como parmetro del e.ento1 Este m/todo recibe [ parmetros: ID del %rupo asociado a la opcin (.eremos 4u/ es esto en el si%uiente art0culo- por a'ora utilizaremos <enu.:A:8)- un ID !nico para la opcin (4ue declararemos como constantes de la clase)- el orden de la opcin (4ue no nos interesa por a'ora- utilizaremos <enu.:A:8) y el te#to de la opcin1 &or otra aprte- el icono de cada opcin lo estableceremos mediante el m/todo setCconBE pasndole el ID del recurso1 Veamos cmo 4uedar0a el cdi%o utilizando esta alternati.a- 4ue %enerar0a un men! e#actamente i%ual al del e8emplo anterior:
private static inal int <:-(AK@* # *; private static inal int <:-(AK@& # &; private static inal int <:-(AK@' # '; //... 7Averride public boolean on@reateAptions<enuB<enu menuE ! //>lternativa & menu.addB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion*0E.setCconBR.drawable.tagE; menu.addB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion&0E.setCconBR.drawable. ilterE; menu.addB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion'0E.setCconBR.drawable.chartE; return true; "

Construido el men!- la implementacin de cada una de las opciones se incluir en el e.ento onAptionsCtemDelectedBE de la acti.idad 4ue mostrar el men!1 Este e.ento recibe
http://www.sgoliver.net/ log/!p"1313 #$gina 74 de 156

Desarrollo en Android

como parmetro el item de men! 4ue 'a sido pulsado por el usuario- cuyo ID podemos recuperar con el m/todo getCtemCdBE1 "e%!n este ID podremos saber 4u/ opcin 'a sido pulsada y e8ecutar unas acciones u otras1 En nuestro caso de e8emplo- lo !nico 4ue 'aremos ser modificar el te#to de una eti4ueta (lbl<ensaje) colocada en la pantalla principal de la aplicacin1
7Averride public boolean onAptionsCtemDelectedB<enuCtem itemE ! switch Bitem.getCtemCdBEE ! case R.id.<nuApc*4 lbl<ensaje.set5extB0Apcion * pulsadaP0E; return true; case R.id.<nuApc&4 lbl<ensaje.set5extB0Apcion & pulsadaP0E;; return true; case R.id.<nuApc'4 lbl<ensaje.set5extB0Apcion ' pulsadaP0E;; return true; de ault4 return super.onAptionsCtemDelectedBitemE; " "

Con esto- 'emos conse%uido ya un men! completamente funcional1 "i e8ecutamos el proyecto en el emulador comprobaremos cmo al pulsar el botn de Xmen$X del tel/fono aparece el men! 4ue 'emos definido y 4ue al pulsar cada opcin se muestra el mensa8e de e8emplo1 &asemos a'ora a comentar los s$!men3s1 <n submen! no es ms 4ue un men! secundario 4ue se muestra al pulsar una opcin determinada de un men! principal1 Los submen!s en Android se muestran en forma de lista emer%ente- cuyo t0tulo contiene el te#to de la opcin ele%ida en el men! principal1 Como e8emplo- .amos a aDadir un submen! a la *pcin 6 del e8emplo anterioral 4ue aDadiremos dos nue.as opciones secundarias1 &ara ello- bastar con insertar en el ) L de men! un nue.o elemento UmenuV dentro del item correspondiente a la opcin 61 De esta
&or'a1 el 234 +)edar5a ahora (o'o sig)e:
./xml version#0*.$0 encoding#0ut -10/2 .menu xmlns4android#0http4//schemas.android.com/apk/res/android0 2 .item android4id#079id/<nuApc*0 android4title#0Apcion*0 android4icon#07drawable/tag02./item2 .item android4id#079id/<nuApc&0 android4title#0Apcion&0 android4icon#07drawable/ ilter02./item2 .item android4id#079id/<nuApc'0 android4title#0Apcion'0 android4icon#07drawable/chart02 .menu2 .item android4id#079id/Dub<nuApc*0 android4title#0Apcion '.*0 /2 .item android4id#079id/Dub<nuApc&0 android4title#0Apcion '.&0 /2

http://www.sgoliver.net/ log/!p"1313 #$gina 75 de 156

Desarrollo en Android
./menu2 ./item2 ./menu2

"i .ol.emos a e8ecutar a'ora el proyecto y pulsamos la opcin 6 nos aparecer el correspondiente submen! con las dos nue.as opciones aDadidas1 Lo .emos en la si%uiente ima%en:

Comprobamos como efecti.amente aparecen las dos nue.as opciones en la lista emer%ente- y 4ue el t0tulo de la lista se corresponde con el te#to de la opcin ele%ida en el men! principal (>4pcion5>)1 &ara conse%uir esto mismo mediante cdi%o proceder0amos de forma similar a la anterior- con la !nica diferencia de 4ue la opcin de men! 6 la aDadiremos utilizando el m/todo add"ub enu() en .ez de add()- y %uardando una referencia al submenu1 "obre el submen! aDadido insertaremos las dos nue.as opciones utilizando una .ez ms el m/todo add()1 *e'os (.'o +)edar5a:
//>lternativa & menu.addB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion*0E.setCconBR.drawable.tagE; menu.addB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion&0E.setCconBR.drawable. ilterE; //menu.addB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion'0E.setCconBR.drawable.chartE; Dub<enu smnu # menu.addDub<enuB<enu.:A:8G <:-(AK@*G <enu.:A:8G 0Apcion'0E .setCconBR.drawable.chartE; smnu.addB<enu.:A:8G D<:-(AK@*G <enu.:A:8G 0Apcion '.*0E; smnu.addB<enu.:A:8G D<:-(AK@&G <enu.:A:8G 0Apcion '.&0E;

http://www.sgoliver.net/ log/!p"1313 #$gina 76 de 156

Desarrollo en Android

En cuanto a la implementacin de estas opciones de submen! no 'abr0a diferencia con todo lo comentado anteriormente ya 4ue tambi/n se tratan desde el e.ento onAptionsCtemDelectedBE- identificndolas por su ID1 &or tanto- con esto 'abr0amos terminado de comentar las opciones bsicas a la 'ora de crear men!s y submenus en nuestras aplicaciones Android1 En el si%uiente art0culo .eremos al%unas opciones al%o ms a.anzadas 4ue- aun4ue menos frecuentes- puede 4ue nos 'a%an falta para desarrollar determinadas aplicaciones1

Mens en Android <II=: Mens Conte6tuales


En el art0culo anterior del curso ya .imos cmo crear men!s y submen!s bsicos para nuestras aplicaciones Android1 "in embar%o- e#iste otro tipo de men!s 4ue nos pueden ser muy !tiles en determinados conte#tos: los men!s conte#tuales1 Este tipo de men! siempre .a asociado a un control concreto de la pantalla y se muestra al realizar una pulsacin lar%a sobre /ste1 "uele mostrar opciones espec0ficas disponibles !nicamente para el elemento pulsado1 &or e8emplo- en un control de tipo lista podr0amos tener un men! conte#tual 4ue apareciera al pulsar sobre un elemento concreto de la lista y 4ue permitiera editar su te#to o eliminarlo de la coleccin1 &ues bien- la creacin y utilizacin de este tipo de men!s es muy parecida a lo 4ue ya .imos para los men!s y submen!s bsicos- pero presentan al%unas particularidades 4ue 'acen interesante tratarlos al mar%en del resto en este nue.o art0culo1 Empecemos por un caso sencillo1 Vamos a partir del e8emplo del art0culo anterior- al 4ue .amos a aDadir en primer lu%ar un men! conte#tual 4ue aparezca al pulsar sobre la eti4ueta de te#to 4ue
http://www.sgoliver.net/ log/!p"1313 #$gina 77 de 156

Desarrollo en Android

mostrbamos en la .entana principal de la aplicacin1 &ara ello- lo primero 4ue .amos a 'acer es indicar en el m/todo onCreate() de nuestra acti.idad principal 4ue la eti4ueta tendr asociado un men! conte#tual1 Esto lo conse%uimos con una llamada a re%isterPorConte#t enu():
public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; //Abtenemos las re erencias a los controles lbl<ensaje # B5ext6iewE ind6iew;yCdBR.id.3bl<ensajeE; //>sociamos los men[s contextuales a los controles registerFor@ontext<enuBlbl<ensajeE; "

A continuacin- i%ual 4ue 'ac0amos con on@reateAptions<enuBE para los men!s bsicos.amos a sobreescribir en nuestra acti.idad el e.ento encar%ado de construir los men!s conte#tuales asociados a los diferentes controles de la aplicacin1 En este caso el e.ento se llama on@reate@ontext<enuBE- y a diferencia de on@reateAptions<enuBE /ste se llama cada .ez 4ue se necesita mostrar un men! conte#tual- y no una sola .ez al inicio de la aplicacin1 En este e.ento actuaremos i%ual 4ue para los m/nus bsicos- inflando el men! ) L 4ue 'ayamos creado con las distintas opciones- o creando a mano el men! mediante el m/todo addBE Hpara ms informacin leer el art0culo anteriorI1 En nuestro e8emplo 'emos definido un men! en ) L llamado >men$1ct,1eti.$eta+,ml>:

./xml version#0*.$0 encoding#0ut -10/2 .menu xmlns4android#0http4//schemas.android.com/apk/res/android0 2 .item android4id#079id/@tx3blApc*0 android4title#0Apc8ti+ueta*02./item2 .item android4id#079id/@tx3blApc&0 android4title#0Apc8ti+ueta&02./item2 ./menu2

&or su parte el e.ento onCreateConte#t enu() 4uedar0a de la si%uiente forma:


7Averride public void on@reate@ontext<enuB@ontext<enu menuG 6iew vG @ontext<enuCn o menuCn oE !

http://www.sgoliver.net/ log/!p"1313 #$gina 78 de 156

Desarrollo en Android
super.on@reate@ontext<enuBmenuG vG menuCn oE; <enuCn later in later # get<enuCn laterBE; in later.in lateBR.menu.menu(ctx(eti+uetaG menuE;

"

&or !ltimo- para implementar las acciones a realizar tras pulsar una opcin determinada del men! conte#tual .amos a implementar el e.ento on@ontextCtemDelectedBE de forma anlo%a a cmo 'ac0amos con onAptionsCtemDelectedBE para los men!s bsicos:
7Averride public boolean on@ontextCtemDelectedB<enuCtem itemE ! switch Bitem.getCtemCdBEE ! case R.id.@tx3blApc*4 lbl<ensaje.set5extB08ti+ueta4 Apcion * pulsadaP0E; return true; case R.id.@tx3blApc&4 lbl<ensaje.set5extB08ti+ueta4 Apcion & pulsadaP0E; return true; de ault4 return super.on@ontextCtemDelectedBitemE; " "

Con esto- ya tendr0amos listo nuestro men! conte#tual para la eti4ueta de te#to de la acti.idad principal- y como .eis todo es prcticamente anlo%o a cmo construimos los men!s y submen!s bsicos en el art0culo anterior1 En este punto ya podr0amos e8ecutar el proyecto en el emulador y comprobar su funcionamiento1 A'ora .amos con al%unas particularidades1 Los men!s conte#tuales se utilizan a menudo con controles de tipo lista- lo 4ue aDade al%unos detalles 4ue con.iene mencionar1 &ara ello .amos a aDadir a nuestro e8emplo una lista con .arios datos de muestra y .amos a asociarle un nue.o men! conte#tual1 odificaremos el layout ) L de la .entana principal para aDadir el control 3ist6iew y modificaremos el m/todo on@reateBE para obtener la referencia al controlinsertar .aios datos de e8emplo- y asociarle un men! conte#tual:
public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; //Abtenemos las re erencias a los controles lbl<ensaje # B5ext6iewE ind6iew;yCdBR.id.3bl<ensajeE; lst3ista # B3ist6iewE ind6iew;yCdBR.id.3st3istaE; //Rellenamos la lista con datos de ejemplo DtringUV datos # new DtringUV !08lem*0G08lem&0G08lem'0G08lem)0G08lemW0";

http://www.sgoliver.net/ log/!p"1313 #$gina 79 de 156

Desarrollo en Android

>rray>dapter.Dtring2 adaptador # new >rray>dapter.Dtring2BthisG android.R.layout.simple(list(item(*G datosE; lst3ista.set>dapterBadaptadorE; //>sociamos los men[s contextuales a los controles registerFor@ontext<enuBlbl<ensajeE; registerFor@ontext<enuBlst3istaE;

"

Como en el caso anterior- .amos a definir en ) L otro men! para asociarlo a los elementos de la lista- lo llamaremos >men$1ct,1lista>:
./xml version#0*.$0 encoding#0ut -10/2 .menu xmlns4android#0http4//schemas.android.com/apk/res/android0 2 .item android4id#079id/@tx3stApc*0 android4title#0Apc3ista*02./item2 .item android4id#079id/@tx3stApc&0 android4title#0Apc3ista&02./item2 ./menu2

Como si%uiente paso- y dado 4ue .amos a tener .arios men!s conte#tuales en la misma acti.idad- necesitaremos modificar el e.ento on@reate@ontext<enuBE para 4ue se construya un men! distinto dependiendo del control asociado1 Esto lo 'aremos obteniendo el ID del control al 4ue se .a a asociar el men! conte#tual- 4ue se recibe en forma de parmetro (6iew v) en el e.ento on@reate@ontext<enuBE1 <tilizaremos para ello una llamada al m/todo getCdBE de dic'o parmetro:

7Averride public void on@reate@ontext<enuB@ontext<enu menuG 6iew vG @ontext<enuCn o menuCn oE ! super.on@reate@ontext<enuBmenuG vG menuCn oE; <enuCn later in later # get<enuCn laterBE; i Bv.getCdBE ## R.id.3bl<ensajeE in later.in lateBR.menu.menu(ctx(eti+uetaG menuE; else i Bv.getCdBE ## R.id.3st3istaE ! >dapter6iew.>dapter@ontext<enuCn o in o # B>dapter6iew.>dapter@ontext<enuCn oEmenuCn o;

http://www.sgoliver.net/ log/!p"1313 #$gina 80 de 156

Desarrollo en Android

menu.set,eader5itleB lst3ista.get>dapterBE.getCtemBin o.positionE.toDtringBEE ; in later.in lateBR.menu.menu(ctx(listaG menuE; " "

Vemos cmo en el caso del men! para el control lista 'emos ido adems un poco ms all- y 'emos personalizado el t0tulo del men! conte#tual Hmediante set,eader5itleBEI para 4ue muestre el te#to del elemento seleccionado en la lista1 &ara 'acer esto nos 'ace falta saber la posicin en la lista del elemento seleccionado- al%o 4ue podemos conse%uir 'aciendo uso del !ltimo parmetro recibido en el e.ento on@reate@ontext<enuBE- llamado menuCn o1 Este parmetro contiene informacin adicional del control 4ue se 'a pulsado para mostrar el men! conte#tual- y en el caso particular del control 3ist6iew contiene la posicin del elemento concreto de la lista 4ue se 'a pulsado1 &ara obtenerlo- con.ertimos el parmetro menuCn o a un ob8eto de tipo >dapter@ontext<enuCn o y accedemos a su atributo position tal como .emos en el cdi%o anterior1 La respuesta a este nue.o men! se realizar desde el mismo e.ento 4ue el anterior- todo dentro de on@ontextCtemDelectedBE1 &or tanto- incluyendo las opciones del nue.o men! conte#tual para la lista el cdi%o nos 4uedar0a de la si%uiente forma:

7Averride public boolean on@ontextCtemDelectedB<enuCtem itemE ! >dapter@ontext<enuCn o in o # B>dapter@ontext<enuCn oE item.get<enuCn oBE; switch Bitem.getCtemCdBEE ! case R.id.@tx3blApc*4 lbl<ensaje.set5extB08ti+ueta4 Apcion * pulsadaP0E; return true; case R.id.@tx3blApc&4 lbl<ensaje.set5extB08ti+ueta4 Apcion & pulsadaP0E;

http://www.sgoliver.net/ log/!p"1313 #$gina 81 de 156

Desarrollo en Android
return true; case R.id.@tx3stApc*4 lbl<ensaje.set5extB03istaU0 9 in o.position 9 0V4 Apcion * pulsadaP0E; return true; case R.id.@tx3stApc&4 lbl<ensaje.set5extB03istaU0 9 in o.position 9 0V4 Apcion & pulsadaP0E; return true; de ault4 return super.on@ontextCtemDelectedBitemE; " "

Como .emos- a4u0 tambi/n utilizamos la informacin del ob8eto >dapter@ontext<enuCn o para saber 4u/ elemento de la lista se 'a pulsado- con la !nica diferencia de 4ue en esta ocasin lo obtenemos mediante una llamada al m/todo get<enuCn oBE de la opcin de men! (<enuCtem) recibida como parmetro1 "i .ol.emos a e8ecutar el proyecto en este punto podremos comprobar el aspecto de nuestro men! conte#tual al pulsar cual4uier elemento de la lista:

A modo de resumen- en este art0culo 'emos .isto cmo crear men!s conte#tuales asociados a determinados elementos y controles de nuestra interfaz de la aplicacin1 Femos .isto cmo crear men!s bsicos y al%unas particularidades 4ue e#isten a la 'ora de asociar men!s conte#tuales a elementos de un control de tipo lista1 &ara no alar%ar este art0culo dedicaremos un tercero a comentar al%unas opciones menos frecuentes- pero i%ualmente !tiles- de los men!s en Android1

http://www.sgoliver.net/ log/!p"1313 #$gina 82 de 156

Desarrollo en Android

Interfaz de usuario en Android: Widgets <I=


En los dos pr#imos art0culos del Curso de &ro%ramacin Android .amos a describir cmo crear un Eid%et de escritorio ()ome screen widget)1 En esta primera parte construiremos un Eid%et est6tico (no ser interacti.o- ni contendr datos actualizables- ni responder a e.entos) muy bsico para entender claramente la estructura interna de un componente de este tipo- y en el si%uiente art0culo completaremos el e8ercicio aDadiendo una .entana de confi%uracin inicial para el Eid%et- aDadiremos al%!n dato 4ue podamos actualizar periodicamente- y 'aremos 4ue responda a pulsaciones del usuario1
http://www.sgoliver.net/ log/!p"1313 #$gina 83 de 156

Desarrollo en Android

Como 'emos dic'o- en esta primera parte .amos a crear un Eid%et muy bsico- consistente en un simple marco rectan%ular ne%ro con un mensa8e de te#to predeterminado (>Mi "rimer Widget>)1 La sencillez del e8emplo nos permitir centrarnos en los pasos principales de la construccin de un Eid%et Android y ol.idarnos de otros detalles 4ue nada tienen 4ue .er con el tema 4ue nos ocupa (%rficos- datos- G)1 &ara 4ue os 'a%is una idea- /ste ser el aspecto final de nuestro Eid%et de e8emplo:

Los pasos principales para la creacin de un Eid%et Android son los si%uientes:
1. Definicin de su interfaz %rfica (la&o$t)1 2. Confi%uracin ) L del Eid%et (>ppLidgetKroviderCn o)1 3. Implementacin de la funcionalidad del Eid%et (>ppLidgetKrovider) -

especialmente su e.ento de actualizacin1 4. Declaracin del Eid%et en el Android Manifest de la aplicacin1 En el primer paso no nos .amos a detener muc'o ya 4ue es anlo%o a cual4uier definicin de layout de las 4ue 'emos .isto 'asta a'ora en el curso1 En esta ocasin- la interfaz del Eid%et estar compuesta !nicamente por un par de frames (Frame3ayout)- uno ne%ro e#terior y uno blanco interior al%o ms pe4ueDo para simular el marco- y una eti4ueta de te#to (5ext6iew) 4ue alber%ar el mensa8e a mostrar1 Veamos cmo 4ueda el layout #ml- 4ue para este e8emplo llamaremos >miwidget+,ml>:
.3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4padding#0Wdip02 .Frame3ayout

http://www.sgoliver.net/ log/!p"1313 #$gina 84 de 156

Desarrollo en Android
android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4background#0O$$$$$$0 android4padding#0*$dip0 2 .Frame3ayout android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4background#0OFFFFFF0 android4padding#0Wdip0 2 .5ext6iew android4id#079id/txt<ensaje0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4text@olor#0O$$$$$$0 android4text#0<i Krimer Lidget0 /2 ./Frame3ayout2 ./Frame3ayout2 ./3inear3ayout2

Cabe destacar a4u0 4ue- debido a 4ue el layout de los Eid%ets de Android est basado en un tipo especial de componentes llamados Remote6iews- no es posible utilizar en su interfaz todos los contenedores y controles 4ue 'emos .isto en art0culos anteriores sino unos pocos bsicos 4ue se indican a continuacin:

Contenedores: Frame3ayout- 3inear3ayout y Relative3ayout Controles: ;utton- Cmage;utton- Cmage6iew- 5ext6iew- Krogress;ar@hronometer y >nalog@lock1

Aun4ue la lista de controles soportados no de8a de ser curiosa (al menos en mi 'umilde opinin)deber0a ser suficiente para crear todo tipo de Eid%ets1

Como se%undo paso del proceso de construccin .amos a crear un nue.o fic'ero ) L donde definiremos un con8unto de propiedades del Eid%et- como por e8emplo su tamaDo en pantalla o su frecuencia de actualizacin1 Este ) L se deber crear en la carpeta \res\xml de nuestro proyecto1 En nuestro caso de e8emplo lo llamaremos >miwidget(wprovider.xml? y tendr la si%uiente estructura:
./xml version#0*.$0 encoding#0ut -10/2 .appwidget-provider xmlns4android#0http4//schemas.android.com/apk/res/android0 android4initial3ayout#07layout/miwidget0

http://www.sgoliver.net/ log/!p"1313 #$gina 85 de 156

Desarrollo en Android
android4minLidth#0*)adip0 android4min,eight#0%&dip0 android4label#0<i Krimer Lidget0 android4updateKeriod<illis#0'a$$$$$0 /2

&ara nuestro Eid%et estamos definiendo las si%uientes propiedades:


initial3ayout: referencia al layout ) L 4ue 'emos creado en el paso anterior1 minLidth: anc'o m0nimo del Eid%et en pantalla- en dp (densit&0independent pi,els)1 min,eight: alto m0nimo del Eid%et en pantalla- en dp (densit&0independent pi,els)1 label: nombre del Eid%et 4ue semostrar en el men! de seleccin de Android1 updateKeriod<illis: frecuencia de actualizacin del Eid%et- en milise%undos1

E#isten .arias propiedades ms 4ue se pueden definir1 En el si%uiente art0culo utilizaremos al%una de ellas- el resto se pueden consultar en la documentacin oficial de la clase App$id%et&ro.iderInfo1 Como sabemos- la pantalla inicial de Android se di.ide en [\[ celdas donde se pueden colocar aplicaciones- accesos directos y Eid%ets1 (eniendo en cuenta las diferentes dimensiones de estas celdas se%!n la orientacin de la pantalla- e#iste una frmula sencilla para a8ustar las dimensiones de nuestro Eid%et para 4ue ocupe un n!mero determinado de celdas sea cual sea la orientacin:

anc'oSm0nimo ] (numSceldas W ^[) _ B altoSm0nimo ] (numSceldas W ^[) _ B

Atendiendo a esta frmula- si 4ueremos 4ue nuestro Eid%et ocupe un tamaDo m0nimo de B celdas de anc'o por C celda de alto- deberemos indicar unas dimensiones de C[9dp # ^Bdp1 Vamos a'ora con el tercer paso1 Qste consiste en implementar la funcionalidad de nuestro Eid%et en su clase 8a.a asociada1 Esta clase deber 'eredar de >ppLidgetKrovider- 4ue a su .ez no es ms 4ue una clase au#iliar deri.ada de ;roadcastReceiver- ya 4ue los Eid%ets de Android no son ms 4ue un caso particular de este tipo de componentes1

En esta clase deberemos implementar los mensa8es a los 4ue .amos a responder desde nuestro Eid%et- entre los 4ue destacan:

on8nabledBE: lanzado cuando se aDade al escritorio la primera instancia de un Eid%et1 on-pdateBE: lanzado periodicamente cada .ez 4ue se debe actualizar un Eid%et1 onJeletedBE: lanzado cuando se elimina del escritorio una instancia de un Eid%et1 onJisabledBE: lanzado cuando se elimina del escritorio la !ltima instancia de un Eid%et1

http://www.sgoliver.net/ log/!p"1313 #$gina 86 de 156

Desarrollo en Android

En la mayor0a de los casos- tendremos 4ue implementar como m0nimo el e.ento on-pdateBE1 El resto de m/todos dependern de la funcionalidad de nuestro Eid%et1 En nuestro caso particular no nos 'ar falta nin%uno de ellos ya 4ue el Eid%et 4ue estamos creando no contiene nin%!n dato actualizable- por lo 4ue crearemos la clase- llamada <iLidget- pero de8aremos .ac0o por el momento el m/todo on-pdateBE1 En el si%uiente art0culo .eremos 4u/ cosas podemos 'acer dentro de estos m/todos1
package net.sgoliver.android; import android.appwidget.>ppLidget<anager; import android.appwidget.>ppLidgetKrovider; import android.content.@ontext; public class <iLidget extends >ppLidgetKrovider ! 7Averride public void on-pdateB@ontext contextG >ppLidget<anager appLidget<anagerG intUV appLidgetCdsE ! //>ctualiNar el widget //... " "

El !ltimo paso del proceso ser declarar el Eid%et dentro del manifest de nuestra aplicacin1 &ara ello- editaremos el fic'ero >ndroid<ani est.xml para incluir la si%uiente declaracin dentro del elemento .application2:
.application2 ... .receiver android4name#0.<iLidget0 android4label#0<i Krimer Lidget02 .intent- ilter2 .action android4name#0android.appwidget.action.>KKLCJH85(-KJ>580 /2 ./intent- ilter2 .meta-data android4name#0android.appwidget.provider0 android4resource#07xml/miwidget(wprovider0 /2 ./receiver2 ./application2

El Eid%et se declarar como un elemento .receiver2 y deberemos aportar la si%uiente informacin:


Atributo name: :eferencia a la clase 8a.a de nuestro Eid%et- creada en el paso anterior1 Elemento .intent- ilter2- donde indicaremos los >e.entos? a los 4ue responder nuestro Eid%et- normalmente aDadiremos el e.ento >KKLCJH85(-KJ>58- para detectar la accin de actualizacin1

http://www.sgoliver.net/ log/!p"1313 #$gina 87 de 156

Desarrollo en Android

Elemento .meta-data2- donde 'aremos referencia con su atributo resource al ) L de confi%uracin 4ue creamos en el se%undo paso del proceso1

Con esto 'abr0amos terminado de escribir los distintos elementos necesarios para 'acer funcionar nuestro Eid%et bsico de e8emplo1 &ara probarlo- podemos e8ecutar el proyecto de Eclipse en el emulador de Android- esperar a 4ue se e8ecute la aplicacin principal (4ue estar .ac0a- ya 4ue no 'emos incluido nin%una funcionalidad para ella)- ir a la pantalla principal del emulador y aDadir nuestro Eid%et al escritorio tal cmo lo 'ar0amos en nuestro tel/fono (pulsacin lar%a sobre el escritorio o tecla en!- seleccionar la opcin Widgets- y por !ltimo seleccionar nuestro $id%et)1 *s de8o una demostracin en .ideo1 Como pod/is .er en el .ideo- ya 'emos conse%uido la funcionalidad bsica de un Eid%et- es posible aDadir .arias instancias al escritorio- desplazarlos por la pantalla y eliminarlos en.indolos a la papelera1 En el pr#imo art0culo .eremos cmo podemos me8orar este Eid%et aDadiendo una pantalla de confi%uracin inicial- mostraremos al%!n dato 4ue se actualice peridicamente- y aDadiremos la posibilidad de capturar e.entos de pulsacin sobre el Eid%et1

Interfaz de usuario en Android: Widgets <II=


En un art0culo anterior del curso ya .imos cmo construir un Eid%et bsico para Android- y prometimos 4ue dedicar0amos un art0culo adicional a comentar al%unas caracter0sticas ms a.anzadas de este tipo de componentes1 &ues bien- en este se%undo art0culo sobre el tema .amos a .er cmo podemos aDadir los si%uientes elementos y funcionalidades al Eid%et bsico 4ue ya constru0mos:
http://www.sgoliver.net/ log/!p"1313 #$gina 88 de 156

Desarrollo en Android

&antalla de confi%uracin inicial1 Datos actualizables de forma periodica1 E.entos de usuario1

Como sab/is- intento simplificar al m#imo todos los e8emplos 4ue utilizo en este curso para 4ue podamos centrar nuestra atencin en los aspectos realmente importantes1 En esta ocasin utilizar/ el mismo criterio y las !nicas caracter0sticas (aun4ue suficientes para demostrar los tres conceptos anteriores) 4ue aDadiremos a nuestro Eid%et sern las si%uientes: C1 ADadiremos una pantalla de confi%uracin inicial del Eid%et- 4ue aparecer cada .ez 4ue se aDada una nue.a instancia del Eid%et a nuestro escritorio1 En esta pantalla podr confi%urarse !nicamente el mensa8e de te#to a mostrar en el Eid%et1 B1 ADadiremos un nue.o elemento de te#to al Eid%et 4ue muestre la 'ora actual1 Esto nos ser.ir para comprobar 4ue el Eid%et se actualiza periodicamente1 61 ADadiremos un botn al Eid%et- 4ue al ser pulsado forzar la actualizacin inmediata del mismo1 Empecemos por el primer punto- la pantalla de confi%uracin inicial del Eid%et1 2 procederemos i%ual 4ue para el diseDo de cual4uier otra acti.idad android- definiendo su layout #ml1 En nuestro caso ser muy sencilla- un cuadro de te#to para introducir el mensa8e a personalizar y dos botones- uno para aceptar la confi%uracin y otro para cancelar (en cuyo caso el Eid%et no se aDade al escritorio)1 En esta ocasin llamaremos a este layout >widget1config+,ml>1 *ea'os
(o'o +)eda:

./xml version#0*.$0 encoding#0ut -10/2 .3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4orientation#0vertical02 .5ext6iew android4id#079id/3bl<ensaje0 android4layout(width#0wrap(content0

http://www.sgoliver.net/ log/!p"1313 #$gina 89 de 156

Desarrollo en Android
android4layout(height#0wrap(content0 android4text#0<ensaje personaliNado40 /2 .8dit5ext android4id#079id/5xt<ensaje0 android4layout(height#0wrap(content0 android4layout(width#0 ill(parent0 /2 .3inear3ayout android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4orientation#0horiNontal0 2 .;utton android4id#079id/;tn>ceptar0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4text#0>ceptar0 /2 .;utton android4id#079id/;tn@ancelar0 android4layout(width#0wrap(content0 android4layout(height#0wrap(content0 android4text#0@ancelar0 /2 ./3inear3ayout2 ./3inear3ayout2

<na .ez diseDada la interfaz de nuestra acti.idad de confi%uracin tendremos 4ue implementar su funcionalidad en 8a.a1 Llamaremos a la clase $id%etConfi%- su estructura ser anlo%a a la de cual4uier acti.idad de Android- y las acciones a realizar sern las comentadas a continuacin1 En primer lu%ar nos 'ar falta el identificador de la instancia concreta del Eid%et 4ue se confi%urar con esta acti.idad1 Este ID nos lle%a como parmetro del intent 4ue 'a lanzado la acti.idad1 Como ya .imos en un art0culo anterior del curso- este intent se puede recuperar mediante el m/tdo %etIntent() y sus parmetros mediante el m/todo %etE#tras()1 Conse%uida la lista de parmetros del intent- obtendremos el .alor del ID del Eid%et accediendo a la cla.e App$id%et ana%er1E)(:ASA&&$ID=E(SID1 *ea'os el (.digo hasta este 'o'ento:

public class Lidget@on ig extends >ctivity ! private int widgetCd # $; 7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.widget(con igE; //Abtenemos el Cntent +ue ha lanNado esta ventana

http://www.sgoliver.net/ log/!p"1313 #$gina 90 de 156

Desarrollo en Android
//y recuperamos sus parSmetros Cntent intentArigen # getCntentBE; ;undle params # intentArigen.get8xtrasBE; //Abtenemos el CJ del widget +ue se estS con igurando widgetCd # params.getCntB >ppLidget<anager.8R5R>(>KKLCJH85(CJG >ppLidget<anager.C:6>3CJ(>KKLCJH85(CJE; //8stablecemos el resultado por de ecto Bsi se pulsa el botTn ^>trSs^ //del telZ ono serS Zste el resultado devueltoE. setResultBR8D-35(@>:@838JE; //... " "

En el cdi%o tambi/n podemos .er como apro.ec'amos este momento para establecer el resultado por defecto a de.ol.er por la acti.idad de confi%uracin mediante el m/todo setResultBE1 Esto es importante por4ue las acti.idades de confi%uracin de Eid%ets deben de.ol.er siempre un resultado (R8D-35(AY en caso de aceptarse la confi%uracin- o R8D-35(@>:@838J en caso de salir de la confi%uracin sin aceptar los cambios)1 Estableciendo a4u0 ya un resultado R8D-35(@>:@838J por defecto nos ase%uramos de 4ue si el usuario sale de la confi%uracin pulsando el botn Atr6s del tel/fono no aDadiremos el Eid%et al escritorio- mismo resultado 4ue si pulsramos el botn Cancelar de nuestra acti.idad1 Como si%uiente paso recuperamos las referencias a cada uno de los controles de la acti.idad de confi%uracin:
//Abtenemos la re erencia a los controles de la pantalla inal ;utton btn>ceptar # B;uttonE ind6iew;yCdBR.id.;tn>ceptarE; inal ;utton btn@ancelar # B;uttonE ind6iew;yCdBR.id.;tn@ancelarE; inal 8dit5ext txt<ensaje # B8dit5extE ind6iew;yCdBR.id.5xt<ensajeE;

&or !ltimo- implementaremos las acciones de los botones Aceptar y (ancelar1 En principio- el botn Cancelar no tendr0a por 4u/ 'acer nada- tan slo finalizar la acti.idad mediante una llamada al m/todo inishBE ya 4ue el resultado @>:@838J ya se 'a establecido por defecto anteriormente:
//CmplementaciTn del botTn 0@ancelar0 btn@ancelar.setAn@lick3istenerBnew An@lick3istenerBE ! 7Averride public void on@lickB6iew arg$E !

http://www.sgoliver.net/ log/!p"1313 #$gina 91 de 156

Desarrollo en Android
//Jevolvemos como resultado4 @>:@83>R BR8D-35(@>:@838JE inishBE; " "E;

En el caso del botn Aceptar tendremos 4ue 'acer ms cosas: C1 =uardar de al%una forma el mensa8e 4ue 'a introducido el usuario1 B1 Actualizar manualmente la interfaz del Eid%et se%!n la confi%uracin establecida1 61 De.ol.er el resultado :E"<L(S*; aportanto adems el ID del Eid%et1 &ara el primer punto nos ayudaremos de la A&I de &referencias 4ue describimos en el art0culo anterior1 En nuestro caso- %uardaremos una sla preferencia cuya cla.e se%uir el patrn >msg(CdLidget>- esto nos permitir distin%uir el mensa8e confi%urado para cada instancia del Eid%et 4ue aDadamos a nuestro escritorio de Android1 El se%undo paso indicado es necesario debido a 4ue si definimos una acti.idad de confi%uracin para un Eid%et- ser /sta la 4ue ten%a la responsabilidad de realizar la primera actualizacin del mismo en caso de ser necesario1 Es decir- tras salir de la acti.idad de confi%uracin no se lanzar automticamente el e.ento on-pdateBE del Eid%et (s0 se lanzar posteriormente y de forma peridica se%!n la confi%uracin del parmetro updateKeriod<illis del pro.ider 4ue .eremos ms adelante)- sino 4ue tendr 4ue ser la propia acti.idad 4uien fuerce la primera actualizacin1 &ara ello- simplemente obtendremos una referencia al widget manager de nuestro conte#to mediente el m/todo >ppLidget<anager.getCnstanceBE y con esta referencia llamaremos al m/todo esttico de actualizacin del Eid%et <iLidget.actualiNarLidgetBE- 4ue actualizar los datos de todos los controles del Eid%et (lo .eremos un poco ms adelante)1 &or !ltimo- al resultado a de.ol.er (R8D-35(AY) deberemos aDadir informacin sobre el ID de nuestro Eid%et1 Esto lo conse%uimos creando un nue.o Cntent 4ue conten%a como parmetro el ID del Eid%et 4ue recuperamos antes y estableci/ndolo como resultado de la acti.idad mediante el m/todo setResultBresultadoG intentE1 &or !ltimo llamaremos al m/todo inishBE para finalizar la acti.idad1

Con estas indicaciones- .eamos cmo 4uedar0a el cdi%o del botn Aceptar:
//CmplementaciTn del botTn 0>ceptar0 btn>ceptar.setAn@lick3istenerBnew An@lick3istenerBE ! 7Averride public void on@lickB6iew arg$E ! //Huardamos el mensaje personaliNado en las pre erencias DharedKre erences pre s # getDharedKre erencesB0LidgetKre s0G @ontext.<AJ8(KRC6>58E;

http://www.sgoliver.net/ log/!p"1313 #$gina 92 de 156

Desarrollo en Android
DharedKre erences.8ditor editor # pre s.editBE; editor.putDtringB0msg(0 9 widgetCdG txt<ensaje.get5extBE.toDtringBEE; editor.commitBE; //>ctualiNamos el widget tras la con iguraciTn >ppLidget<anager appLidget<anager # >ppLidget<anager.getCnstanceBLidget@on ig.thisE; <iLidget.actualiNarLidgetBLidget@on ig.thisG appLidget<anagerG widgetCdE; //Jevolvemos como resultado4 >@8K5>R BR8D-35(AYE Cntent resultado # new CntentBE; resultado.put8xtraB>ppLidget<anager.8R5R>(>KKLCJH85(CJG widgetCdE; " "E; setResultBR8D-35(AYG resultadoE; inishBE;

2a 'emos terminado de implementar nuestra acti.idad de confi%uracin1 &ero para su correcto funcionamiento a!n nos 4uedan dos detalles ms por modificar1 En primer lu%ar tendremos 4ue declarar esta acti.idad en nuestro fic'ero Android anifest1#ml- indicando 4ue debe responder a los mensa8es de tipo >KKLCJH85(@A:FCH-R8:
.activity android4name#0.Lidget@on ig02 .intent- ilter2 .action android4name#0android.apwidget.action.>KKLCJH85(@A:FCH-R80/2 ./intent- ilter2 ./activity2

&or !ltimo- debemos indicar en el ) L de confi%uracin de nuestro Eid%et (#ml`miEid%etSEpro.ider1#ml) 4ue al aDadir una instancia de este Eid%et debe mostrarse la acti.idad de confi%uracin 4ue 'emos creado1 Esto se consi%ue estableciendo el atributo android4con igure del provider1 Apro.ec'aremos adems este paso para establecer el tiempo de actualizacin automtica del Eid%et al m0nimo permitido por este parmetro (6R minutos) y el tamaDo del Eid%et a B\B celdas1 Veamos cmo 4uedar0a finalmente:

./xml version#0*.$0 encoding#0ut -10/2 .appwidget-provider xmlns4android#0http4//schemas.android.com/apk/res/android0 android4initial3ayout#07layout/miwidget0 android4minLidth#0*)adip0 android4min,eight#0*)adip0

http://www.sgoliver.net/ log/!p"1313 #$gina 93 de 156

Desarrollo en Android
android4label#0<i Krimer Lidget0 android4updateKeriod<illis#0*1$$$$$0 android4con igure#0net.sgoliver.android.Lidget@on ig0

/2

Con esto- ya tenemos todo listo para 4ue al aDadir nuestro Eid%et al escritorio se muestre automticamente la pantalla de confi%uracin 4ue 'emos construido1 &odemos e8ecutar el proyecto en este punto y comprobar 4ue todo funciona correctamente1 Como si%uiente paso .amos a modificar el layout del Eid%et 4ue ya construimos en el art0culo anterior para aDadir una nue.a eti4ueta de te#to donde mostraremos la 'ora actual- y un botn 4ue nos ser.ir para forzar la actualizacin de los datos del Eid%et:

./xml version#0*.$0 encoding#0ut -10/2 .3inear3ayout xmlns4android#0http4//schemas.android.com/apk/res/android 0 android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4padding#0Wdip02

http://www.sgoliver.net/ log/!p"1313 #$gina 94 de 156

Desarrollo en Android

.Frame3ayout android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4background#0O$$$$$$0 android4padding#0*$dip0 2 .3inear3ayout android4layout(width#0 ill(parent0 android4layout(height#0 ill(parent0 android4background#0OFFFFFF0 android4padding#0Wdip0 android4orientation#0vertical02 .5ext6iew android4id#079id/3bl<ensaje0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4text@olor#0O$$$$$$0 android4text#0mensaje0 /2 .5ext6iew android4id#079id/3bl,ora0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4text@olor#0O$$$$$$0 android4text#0hora(actual0 /2 .;utton android4id#079id/;tn>ctualiNar0 android4layout(width#0 ill(parent0 android4layout(height#0wrap(content0 android4text#0>ctualiNar0 /2 ./3inear3ayout2 ./Frame3ayout2 ./3inear3ayout2

Fec'o esto- tendremos 4ue modificar la implementacin de nuestro pro.ider (<iLidget.java) para 4ue en cada actualizacin del Eid%et se actualicen sus controles con los datos correctos (recordemos 4ue en el art0culo anterior de8amos este e.ento de actualizacin .ac0o ya 4ue no mostrbamos datos actualizables en el Eid%et)1 Esto lo 'aremos dentro del e.ento on-pdateBE de nuestro pro.ider1

Como ya di8imos- los componentes de un Eid%et se basan en un tipo especial de .istas 4ue llamamos 'emote iews1 &ues bien- para acceder a la lista de estos componentes 4ue constituyen la interfaz del Eid%et construiremos un nue.o ob8eto Remote6iews a partir del ID del layout de cada Eid%et1 *btenida la lista de componentes- tendremos disponibles una serie de m/todos set (uno para cada tipo de datos bsicos) para establecer las propiedades de cada control del Eid%et1 Estos m/todos reciben como parmetros el ID del control- el nombre del m/todo 4ue
http://www.sgoliver.net/ log/!p"1313 #$gina 95 de 156

Desarrollo en Android

4ueremos e8ecutar sobre el control- y el .alor a establecer1 Adems de estos m/todos- contamos adicionalmente con una serie de m/todos ms espec0ficos para establecer directamente el te#to y otras propiedades sencillas de los controles 5ext6iew- Cmage6iew- Krogress;ar y @hronometer- como por e8emplo set5ext6iew5extBid@ontrolG valorE para establecer el te#tode un control 5ext6iew1 &ueden consultarse todos los m/todos disponibles en la documentacin oficial de la clase Remote6iews1 De esta forma- si por e8emplo 4ueremos establecer el te#to del control cuyo id es 3bl<ensaje 'ar0amos lo si%uiente:
Remote6iews controles # new Remote6iewsBcontext.getKackage:ameBEG R.layout.miwidgetE; controles.set5ext6iew5extBR.id.3bl<ensajeG 0<ensaje de prueba0E;

El proceso de actualizacin 'abr 4ue realizarlo por supuesto para todas las instancias del Eid%et 4ue se 'ayan aDadido al escritorio1 :ecordemos a4u0 4ue el e.ento on-pdateBE recibe como parmetro la lista de Eid%ets 4ue 'ay 4ue actualizar1

Dic'o esto- creo 4ue ya podemos mostrar cmo 4uedar0a el cdi%o de actualizacin de nuestro Eid%et:
7Averride public void on-pdateB@ontext contextG >ppLidget<anager appLidget<anagerG intUV appLidgetCdsE !

http://www.sgoliver.net/ log/!p"1313 #$gina 96 de 156

Desarrollo en Android

//Cteramos la lista de widgets en ejecuciTn or Bint i # $; i . appLidgetCds.length; i99E ! //CJ del widget actual int widgetCd # appLidgetCdsUiV; //>ctualiNamos el widget actual actualiNarLidgetBcontextG appLidget<anagerG widgetCdE;

" "

public static void actualiNarLidgetB@ontext contextG >ppLidget<anager appLidget<anagerG int widgetCdE ! //Recuperamos el mensaje personaliNado para el widget actual DharedKre erences pre s # context.getDharedKre erencesB0LidgetKre s0G @ontext.<AJ8(KRC6>58E; Dtring mensaje # pre s.getDtringB0msg(0 9 widgetCdG 0,ora actual40E; //Abtenemos la lista de controles del widget actual Remote6iews controles # new Remote6iewsBcontext.getKackage:ameBEG R.layout.miwidgetE; //>ctualiNamos el mensaje en el control del widget controles.set5ext6iew5extBR.id.3bl<sgG mensajeE; //Abtenemos la hora actual @alendar calendario # new Hregorian@alendarBE; Dtring hora # calendario.get5imeBE.to3ocaleDtringBE; //>ctualiNamos la hora en el control del widget controles.set5ext6iew5extBR.id.3bl,oraG horaE; //:oti icamos al manager de la actualiNaciTn del widget actual appLidget<anager.update>ppLidgetBwidgetCdG controlesE;

"

Como .emos- todo el traba8o de actualzacin para un Eid%et lo 'emos e#traido a un m/todo esttico independiente- de forma 4ue tambi/n podamos llamarlo desde otras partes de la aplicacin (como 'acemos por e8emplo desde la acti.idad de confi%uracin para forzar la primera actualizacin del Eid%et)1 Adems 4uiero destacar la !ltima linea del cdi%o- donde llamamos al m/todo update>ppLidgetBE del widget manager1 Esto es importante y necesario- ya 4ue de no 'acerlo la actualizacin de los controles no se refle8ar correctamente en la interfaz del Eid%et1 (ras esto- ya slo nos 4ueda implementar la funcionalidad del nue.o botn 4ue 'emos incluido en el Eid%et para poder forzar la actualizacin del mismo1 A los controles utilizados en los Eid%ets de Android- 4ue ya sabemos 4ue son del tipo Remote6iew- no podemos asociar
http://www.sgoliver.net/ log/!p"1313 #$gina 97 de 156

Desarrollo en Android

e.entos de la forma tradicional 4ue 'emos .isto en m!ltiples ocasiones durante el curso1 "in embar%o- en su lu%ar- tenemos la posibilidad de asociar a un e.ento (por e8emplo- el clicO sobre un botn) un determinado mensa8e ("ending Intent) de tipo !roadcast 4ue ser lanzado cada .ez 4ue se produzca dic'o e.ento1 Adems- podremos confi%urar el Eid%et (4ue como ya indicamos no es ms 4ue un componente de tipo !roadcast receiver) para 4ue capture esos mensa8es- e implementar en el e.ento onReceiveBE del Eid%et las acciones necesarias a e8ecutar tras capturar el mensa8e1 Con estas tres acciones simularemos la captura de e.entos sobre controles de un Eid%et1 Vamos por partes1 En primer lu%ar 'a%amos 4ue se lance un intent broadcast cada .ez 4ue se pulse el botn del Eid%et1 &ara ello- en el m/todo actualizar$id%et() construiremos un nue.o Intent asocindole una accin personalizada- 4ue en nuestro caso llamaremos por e8emplo >net1s%oli.er1AC(<ALIaA:S$ID=E(>1 Como parmetro del nue.o Intent insertaremos mediante putE#tra() el ID del Eid%et actual de forma 4ue ms tarde podamos saber el Eid%et concreto 4ue 'a lanzado el mensa8e1 &or !ltimo crearemos el &endin%Intent mediante el m/todo %et+roadcast() y lo asociaremos al e.ento onClicO del control llamando a set*nClicO&endin%Intent() pasndole el ID del control- en nuestro caso el botn de Actualizar1
*ea'os (.'o +)eda todo esto:
//>sociamos los ^eventos^ al widget Cntent intent # new CntentB0net.sgoliver.>@5->3Cb>R(LCJH850E; intent.put8xtraB >ppLidget<anager.8R5R>(>KKLCJH85(CJG widgetCdE; KendingCntent pendingCntent # KendingCntent.get;roadcastBcontextG widgetCdG intentG KendingCntent.F3>H(-KJ>58(@-RR8:5E; controles.setAn@lickKendingCntentBR.id.;tn>ctualiNarG pendingCntentE;

A'ora .amos a declarar en el Android anifest este mensa8e personalizado- de forma 4ue el Eid%et sea capaz de capturarlo1 &ara ello- aDadiremos simplemente un nue.o elemento UintentA filterV con nuestro nombre de accin personalizado:
.intent- ilter2 .action android4name#0net.sgoliver.>@5->3Cb>R(LCJH850/2 ./intent- ilter2

&or !ltimo- .amos a implementar el e.ento onReceiveBE del Eid%et para actuar en caso de recibir nuestro mensa8e de actualizacin personalizado1 Dentro de este e.ento comprobaremos si la accin del menas8e recibido es la nuestra- y en ese caso recuperaremos el ID del Eid%et 4ue lo
http://www.sgoliver.net/ log/!p"1313 #$gina 98 de 156

Desarrollo en Android

'a lanzado- obtendremos una referencia al widget manager- y por !ltimo llamaremos nuestro m/todo esttico de actualizacin pasndole estos datos1
7Averride public void onReceiveB@ontext contextG Cntent intentE ! i Bintent.get>ctionBE.e+ualsB0net.sgoliver.>@5->3Cb>R(LCJH850EE ! //Abtenemos el CJ del widget a actualiNar int widgetCd # intent.getCnt8xtraB >ppLidget<anager.8R5R>(>KKLCJH85(CJG >ppLidget<anager.C:6>3CJ(>KKLCJH85(CJE; //Abtenemos el widget manager de nuestro contexto >ppLidget<anager widget<anager # >ppLidget<anager.getCnstanceBcontextE; //>ctualiNamos el widget i BwidgetCd P# >ppLidget<anager.C:6>3CJ(>KKLCJH85(CJE ! actualiNarLidgetBcontextG widget<anagerG widgetCdE; "

"

Con esto- por fin- 'emos ya finalizado la construccin de nuestro Eid%et android y podemos e8ecutar el proyecto de Eclipse para comprobar 4ue todo funciona correctamente- tanto para una sola instancia como para .arias instancias simultaneas1 <n comentario final- la actualizacin automtica del Eid%et se 'a establecido a la frecuencia m0nima 4ue permite el atributo updateKeriod<illis del widget provider- 4ue son 6R minutos1 &or tanto es dificil y aburrido esperar para .erla en funcionamiento mientras probamos el Eid%et en el emulador1 &ero funciona- os lo ase%uro1 De cual4uier forma- esos 6R minutos pueden ser un periodo demasiado lar%o de tiempo se%!n la funcionalidad 4ue 4ueramos dar a nuestro Eid%et- 4ue puede re4uerir tiempos de actualizacin muc'o ms cortos (o8o con el rendimiento y el %asto de bater0a)1 s adelante- cuando 'ablemos de Alarmas- .eremos una t/cnica 4ue nos permitir actualizar los Eid%ets sin esa limitacin de 6R minutos1 Fasta entoncesespero 4ue el tema os sea de utilidad y 4ue os 'aya parecido interesante1

Preferencias en Android I: '5ared Preferences


http://www.sgoliver.net/ log/!p"1313 #$gina 99 de 156

Desarrollo en Android

En el art0culo anterior del Curso de &ro%ramacin en Android .imos como construir un Eid%et bsico y prometimos dedicar un se%undo art0culo a comentar otras funcionalidades ms a.anzadas de este tipo de componentes1 "in embar%o- antes de esto 'e decidido 'acer un pe4ueDo alto en el camino para 'ablar de un tema 4ue nos ser de ayuda ms adelante- y no slo para la construccin de Eid%ets- sino para cual4uier tipo de aplicacin Android1 Este tema es la administracin de preferencias1 Las preferencias no son ms 4ue datos 4ue una aplicacin debe %uardar para personalizar la e#periencia del usuario- por e8emplo informacin personal- opciones de presentacin- etc1 En art0culos anteriores .imos ya uno de los m/todos disponibles en la plataforma Android para almacenar datos- como son las bases de datos ",Lite1 Las preferencias de una aplicacin se podr0an almacenar por su puesto utilizando este m/todo- y no tendr0a nada de malo- pero Android proporciona otro m/todo alternati.o diseDado espec0ficamente para administrar este tipo de datos: las preferencias compartidas o s)ared preferences1 Cada preferencia se almacenar en forma de cla.eA.alor- es decir- cada una de ellas estar compuesta por un identificador !nico (p1e1 >email?) y un .alor asociado a dic'o identificador (p1e1 >pruebaMemail1com?)1 Adems- y a diferencia de ",Lite- los datos no se %uardan en un fic'ero de binario de base de datos- sino en fic'eros ) L como .eremos al final de este art0culo1 La A&I para el mane8o de estas preferencias es muy sencilla1 (oda la %estin se centraliza en la clase DharedKre ences- 4ue representar a una coleccin de preferencias1 <na aplicacin Android puede %estionar .arias colecciones de preferencias- 4ue se diferenciarn mediante un identificador !nico1 &ara obtener una referencia a una coleccin determinada utilizaremos el m/todo getDharedKre encesBE al 4ue pasaremos el identificador de la coleccin y un modo de acceso1 El modo de acceso indicar 4u/ aplicaciones tendrn acceso a la coleccin de preferencias y 4u/ operaciones tendrn permitido realizar sobre ellas1 As0- tendremos tres posibilidades principales:

<AJ8(KRC6>581 "lo nuestra aplicacin tiene acceso a estas preferencias1 <AJ8(LAR3J(R8>J>;381 (odas las aplicaciones pueden leer estas preferencias- pero slo la nuestra modificarlas1 <AJ8(LAR3J(LRC5>;381 (odas las aplicaciones pueden leer y modificar estas preferencias1

(eniedo todo esto en cuenta- para obtener una referencia a una coleccin de preferencias llamada por e8emplo > is&referencias? y como modo de acceso e#clusi.o para nuestra aplicacin 'ar0amos lo si%uiente:

DharedKre erences pre s # getDharedKre erencesB0<isKre erencias0G@ontext.<AJ8(KRC6>58E ;

http://www.sgoliver.net/ log/!p"1313 #$gina 100 de 156

Desarrollo en Android

<na .ez 'emos obtenido una referencia a nuestra coleccin de preferencias- ya podemos obtenerinsertar o modificar preferencias utilizando los m/todos get o p$t correspondientes al tipo de dato de cada preferencia1 As0- por e8emplo- para obtener el .alor de una preferencia llamada >email? de tipo Dtring escribir0amos lo si%uiente:
DharedKre erences pre s # getDharedKre erencesB0<isKre erencias0G@ontext.<AJ8(KRC6>58E ; Dtring correo # pre s.getDtringB0email0G 0por(de ecto7email.com0E;

Como .emos- al m/todo getDtringBE le pasamos el nombre de la preferencia 4ue 4ueremos recuperar y un se%undo parmetro con un .alor por defecto1 Este .alor por defecto ser el de.uelto por el m/todo getDtringBE si la preferencia solicitada no e#iste en la coleccin1 Adems del m/todo getDtringBE- e#isten por supuesto m/todos anlo%os para el resto de tipos de datos bsicos- por e8emplo getCntBE- get3ongBE- getFloatBEget;ooleanBE- G &ara actualizar o insertar nue.as preferencias el proceso ser i%ual de sencillo- con la !nica diferencia de 4ue la actualizacin o insercin no la 'aremos directamente sobre el ob8eto "'ared&references- sino sobre su ob8eto de edicin "'ared&references1Editor1 A este !ltimo ob8eto accedemos mediante el m/todo edit() de la clase "'ared&references1 <na .ez obtenida la referencia al editor- utilizaremos los m/todos p$t correspondientes al tipo de datos de cada preferencia para actualizar@insertar su .alor- por e8emplo put"trin%(cla.e- .alor)- para actualizar una preferencia de tipo "trin%1 De forma anlo%a a los m/todos %et 4ue ya 'emos .istotendremos disponibles m/todos put para todos los tipos de datos bsicos: putInt()- putPloat()put+oolean()- etc1 Pinalmente- una .ez actualizados@insertados todos los datos necesarios llamaremos al m/todo commit() para confirmar los cambios1 *ea'os )n e0e'plo sen(illo:
DharedKre erences pre s # getDharedKre erencesB0<isKre erencias0G@ontext.<AJ8(KRC6>58E ; DharedKre erences.8ditor editor # pre s.editBE; editor.putDtringB0email0G 0modi icado7email.com0E; editor.putDtringB0nombre0G 0Krueba0E; editor.commitBE;

KDonde se almacenan estas preferencias compartidasL Como di8imos al comienzo del art0culolas preferencias no se almacenan en fic'eros binarios como las bases de datos ",Lite- sino en fic'eros ) L1 Estos fic'eros ) L se almacenan en una ruta con el si%uiente patrn: /data/data/pa+uetejava/shared(pre s/nombre(coleccion.xml

As0- por e8emplo- en nuestro caso encontrar0amos nuestro fic'ero de preferencias en la ruta:
http://www.sgoliver.net/ log/!p"1313 #$gina 101 de 156

Desarrollo en Android

/data/data/net.sgoliver.android/shared(pre s/MisPreferencias.xml "i descar%amos este fic'ero desde el DD " y lo abrimos con cual4uier editor de te#to .eremos un contenido como el si%uiente:
./xml version#^*.$^ encoding#^ut -1^ standalone#^yes^ / 2 .map2 .string name#0nombre02prueba./string2 .string name#0email02modi icado7email.com./string2 ./map2

En este ) L podemos obser.ar cmo se 'an almacenado las dos preferencias de e8emplo 4ue insertamos anteriormente- con sus cla.es y .alores correspondientes1 2 nada ms- as0 de fcil y prctico1 Con esto 'emos aprendido una forma sencilla de almacenar determinadas opciones de nuestra aplicacin sin tener 4ue recurrir para ello a definir bases de datos ",Lite- 4ue aun4ue tampoco aDaden muc'a dificultad s0 4ue re4uieren al%o ms de traba8o por nuestra parte1 En una se%unda parte de este tema dedicado a las preferencias .eremos cmo Android nos ofrece otra forma de %estionar estos datos- 4ue se inte%ra adems fcilmente con la interfaz %rfica necesaria para solicitar los datos al usuario1

Tratamiento de XML en Android <I=: 'AX


http://www.sgoliver.net/ log/!p"1313 #$gina 102 de 156

Desarrollo en Android

En los si%uientes art0culos de este (utorial de Desarrollo para Android .amos a comentar las distintas posibilidades 4ue tenemos a la 'ora de traba8ar con datos en formato ) L desde la plataforma Android1 A d0a de 'oy- en casi todas las %randes plataformas de desarrollo e#isten .arias formas de leer y escribir datos en formato ) L1 Los dos modelos ms e#tendidos son "A) (Simple A"I for 7M/) y D* (Doc$ment 4!%ect Model)1 &osteriormente- 'an ido apareciendo otros tantos- con ms o menos /#ito- entre los 4ue destaca "tA) (Streaming A"I for 7M/)1 &ues bien- Android no se 4ueda atrs en este sentido e incluye estos tres modelos principales para el tratamiento de ) L- o para ser ms e#actos- los dos primeros como tal y una .ersin anlo%a del tercero (7ml"$ll)1 &or supuesto con cual4uiera de los tres modelos podemos 'acer las mismas tareaspero ya .eremos cmo dependiendo de la naturaleza de la tarea 4ue 4ueramos realizar .a a resultar ms eficiente utilizar un modelo u otro1 Antes de empezar- unas anotaciones respecto a los e8emplos 4ue .oy a utilizar1 Estas t/cnicas se pueden utilizar para tratar cual4uier documento ) L- tanto online como local- pero por utilizar al%o conocido por la mayor0a de .osotros todos los e8emplos .an a traba8ar sobre los datos ) L de un documento :"" online- concretamente sobre el canal :"" de portada de europapress1com1

<n documento :"" de este feed tiene la estructura si%uiente:


http://www.sgoliver.net/ log/!p"1313 #$gina 103 de 156

Desarrollo en Android
.rss version#0&.$02 .channel2 .title28uropa Kress./title2 .link2http4//www.europapress.es/./link2 .description2:oticias de Kortada../description2 .image2 .url2http4//s$*.europapress.net/eplogo.gi ./url2 .title28uropa Kress./title2 .link2http4//www.europapress.es./link2 ./image2 .language2es-8D./language2 .copyright2@opyright./copyright2 .pubJate2DatG &W Jec &$*$ &'4&%4&a H<5./pubJate2 .last;uildJate2DatG &W Jec &$*$ &&4)%4*) H<5./last;uildJate2 .item2 .title25Xtulo de la noticia *./title2 .link2http4//link(de(la(noticia(&.es./link2 .description2JescripciTn de la noticia &./description2 .guid2http4//identi icador(de(la(noticia(&.es./guid2 .pubJate2Fecha de publicaciTn &./pubJate2 ./item2 .item2 .title25Xtulo de la noticia &./title2 .link2http4//link(de(la(noticia(&.es./link2 .description2JescripciTn de la noticia &./description2 .guid2http4//identi icador(de(la(noticia(&.es./guid2 .pubJate2Fecha de publicaciTn &./pubJate2 ./item2 ... ./channel2 ./rss2

Como puede obser.arse- se compone de un elemento principal .channel2 se%uido de .arios datos relati.os al canal y posteriormente una lista de elementos .item2 para cada noticia con sus datos asociados1 En estos art0culos .amos a describir cmo leer este ) L mediante cada una de las tres alternati.as citadas- y para ello lo primero 4ue .amos a 'acer es definir una clase 8a.a para almacenar los datos de una noticia1 3uestro ob8eti.o final ser de.ol.er una lista de ob8etos de este tipo- con la informacin de todas las noticias1 &or comodidad- .amos a almacenar todos los datos como cadenas de te#to:

public class :oticia !

http://www.sgoliver.net/ log/!p"1313 #$gina 104 de 156

Desarrollo en Android
private private private private private Dtring Dtring Dtring Dtring Dtring titulo; link; descripcion; guid; echa;

public Dtring get5ituloBE ! return titulo; " public Dtring get3inkBE ! return link; " public Dtring getJescripcionBE ! return descripcion; " public Dtring getHuidBE ! return guid; " public Dtring getFechaBE ! return echa; " public void set5ituloBDtring tE ! titulo # t; " public void set3inkBDtring lE ! link # l; " public void setJescripcionBDtring dE " descripcion # d;

public void setHuidBDtring gE ! guid # g; " public void setFechaBDtring echa # ; " " E !

<na .ez conocemos la estructura del ) L a leer y 'emos definido las clases au#iliares 4ue nos 'acen falta para almacenar los datos- pasamos ya a comentar el primero de los modelos de tratamiento de ) L1
http://www.sgoliver.net/ log/!p"1313 #$gina 105 de 156

Desarrollo en Android

'AX en Android En el modelo "A)- el tratamiento de un ) L se basa en un analizador (parser) 4ue a medida 4ue lee secuencialmente el documento ) L .a %enerando diferentes e.entos con la informacin de cada elemento leido1 Asi- por e8emplo- a medida 4ue lee el ) L- si encuentra el comienzo de una eti4ueta .title2 %enerar un e.ento de comienzo de eti4ueta- start8lementBE- con su informacin asociada- si despu/s de esa eti4ueta encuentra un fra%mento de te#to %enerar un e.ento charactersBE con toda la informacin necesaria- y as0 sucesi.amente 'asta el final del documento1 3uestro traba8o consistir por tanto en implementar las acciones necesarias a e8ecutar para cada uno de los e.entos posibles 4ue se pueden %enerar durante la lectura del documento ) L1 Los principales e.entos 4ue se pueden producir son los si%uientes (consultar a4u0 la lista completa):

startJocumentBE: comienza el documento ) L1 endJocumentBE: termina el documento ) L1 start8lementBE: comienza una eti4ueta ) L1 end8lementBE: termina una eti4ueta ) L1 charactersBE: fra%mento de te#to1

(odos estos m/todos estn definidos en la clase or%1#ml1sa#1'elpers1DefaultFandler- de la cual deberemos deri.ar una clase propia donde se sobrescriban los e.entos necesarios1 En nuestro caso .amos a llamarla :ssFandler.

http://www.sgoliver.net/ log/!p"1313 #$gina 106 de 156

Desarrollo en Android

public class Rss,andler extends Je ault,andler ! private 3ist.:oticia2 noticias; private :oticia noticia>ctual; private Dtring;uilder sb5exto; public 3ist.:oticia2 get:oticiasBE! return noticias; " 7Averride public void charactersBcharUV chG int startG int lengthE throws D>R8xception ! super.charactersBchG startG lengthE; i Bthis.notcia>ctual P# nullE builder.appendBchG startG lengthE; " 7Averride public void end8lementBDtring uriG Dtring local:ameG Dtring nameE throws D>R8xception ! super.end8lementBuriG local:ameG nameE; i Bthis.notcia>ctual P# nullE ! i Blocal:ame.e+ualsB0title0EE ! noticia>ctual.set5ituloBsb5exto.toDtringBEE; " else i Blocal:ame.e+ualsB0link0EE ! noticia>ctual.set3inkBsb5exto.toDtringBEE; " else i Blocal:ame.e+ualsB0description0EE ! noticia>ctual.setJescripcionBsb5exto.toDtringBEE; " else i Blocal:ame.e+ualsB0guid0EE ! noticia>ctual.setHuidBsb5exto.toDtringBEE; " else i Blocal:ame.e+ualsB0pubJate0EE ! noticia>ctual.setFechaBsb5exto.toDtringBEE; " else i Blocal:ame.e+ualsB0item0EE ! noticias.addBnoticia>ctualE; " sb5exto.set3engthB$E; " "

7Averride public void startJocumentBE throws D>R8xception ! super.startJocumentBE; noticias # new >rray3ist.:oticia2BE; sb5exto # new Dtring;uilderBE;

http://www.sgoliver.net/ log/!p"1313 #$gina 107 de 156

Desarrollo en Android
" 7Averride public void start8lementBDtring uriG Dtring local:ameG Dtring nameG >ttributes attributesE throws D>R8xception ! super.start8lementBuriG local:ameG nameG attributesE; i Blocal:ame.e+ualsB0item0EE ! noticia>ctual # new :oticiaBE; "

" "

Como se puede obser.ar en el cdi%o de anterior- lo primero 4ue 'aremos ser incluir como miembro de la clase la lista de noticias 4ue pretendemos construir- 3ist.:oticia2 noticias- y un m/todo get:oticiasBE 4ue permita obtenerla tras la lectura completa del documento1 (ras esto- implementamos directamente los e.entos "A) necesarios1 Comencemos por startJocumentBE- este e.ento indica 4ue se 'a comenzado a leer el documento ) L- por lo 4ue lo apro.ec'aremos para inicializar la lista de noticias y las .ariables au#iliares1 (ras /ste- el e.ento start8lementBE se lanza cada .ez 4ue se encuentra una nue.a eti4ueta de apertura1 En nuestro caso- la !nica eti4ueta 4ue nos interesar ser .item2- momento en el 4ue inicializaremos un nue.o ob8eto au#iliar de tipo :oticia donde almacenaremos posteriormente los datos de la noticia actual1 El si%uiente e.ento rele.ante es charactersBE- 4ue se lanza cada .ez 4ue se encuentra un fra%mento de te#to en el interior de una eti4ueta1 La t/cnica a4u0 ser ir acumulando en una .ariable au#iliar- sb5exto- todos los fra%mentos de te#to 4ue encontremos 'asta detectarse una eti4ueta de cierre1 &or !ltimo- en el e.ento de cierre de eti4ueta- end8lementBE- lo 4ue 'aremos ser almacenar en el atributo apropiado del ob8eto noticia>ctual (4ue conoceremos por el parmetro local:ame de.uelto por el e.ento) el te#to 4ue 'emos ido acumulando en la .ariable sb5exto y limpiaremos el contenido de dic'a .ariable para comenzar a acumular el si%uiente dato1 El !nico caso especial ser cuando detectemos el cierre de la eti4ueta .item2- 4ue si%nificar 4ue 'emos terminado de leer todos los datos de la noticia y por tanto apro.ec'aremos para aDadir la noticia actual a la lista de noticias 4ue estamos construyendo1 <na .ez implementado nuestro )andler- .amos a crear una nue.a clase 4ue 'a%a uso de /l para parsear mediante "A) un documento ) L concreto1 A esta clase la llamaremos :ss&arser"a#1 s adelante crearemos otras clases anlo%as a /sta 4ue 'a%an lo mismo pero utilizando los otros dos m/todos de tratamiento de ) L ya mencionados1 Esta clase tendr !nicamente un constructor 4ue reciba como parmetro la <:L del documento a parsear- y un m/todo p!blico
http://www.sgoliver.net/ log/!p"1313 #$gina 108 de 156

Desarrollo en Android

llamado parse() para e8ecutar la lectura del documento- y 4ue de.ol.er como resultado una lista de noticias1 *ea'os (.'o +)eda esta (lase:
import java.io.CA8xception; import java.io.CnputDtream; import java.util.3ist; import import import import java.net.-R3; javax.xml.parsers.D>RKarser; java.net.<al ormed-R38xception; javax.xml.parsers.D>RKarserFactory;

public class RssKarserDax ! private -R3 rss-rl; public RssKarserDaxBDtring urlE ! try ! this.rss-rl # new -R3BurlE; " catch B<al ormed-R38xception eE ! throw new Runtime8xceptionBeE; " " public 3ist.:oticia2 parseBE ! D>RKarserFactory actory # D>RKarserFactory.newCnstanceBE; try !

" catch B8xception eE ! throw new Runtime8xceptionBeE; " "

D>RKarser parser # actory.newD>RKarserBE; Rss,andler handler # new Rss,andlerBE; parser.parseBthis.getCnputDtreamBEG handlerE; return handler.get:oticiasBE;

private CnputDtream getCnputDtreamBE ! try ! return rss-rl.open@onnectionBE.getCnputDtreamBE; " catch BCA8xception eE !

http://www.sgoliver.net/ log/!p"1313 #$gina 109 de 156

Desarrollo en Android
throw new Runtime8xceptionBeE;

" " "

Como se puede obser.ar en el cdi%o anterior- el constructor de la clase se limitar a aceptar como parmetro la <:L del documento ) L a parsear a controlar la .alidez de dic'a <:L%enerando una e#cepcin en caso contrario1 &or su parte- el m/todo parseBE ser el encar%ado de crear un nue.o parser "A) mediante s! f6!rica correspondiente Hlo 4ue se consi%ue obteniendo una instancia de la fbrica con D>RKarserFactory.newCnstanceBE y creando un nue.o parser con actory.newDaxKarserBEI y de iniciar el proceso pasando al parser una instancia del )andler 4ue 'emos creado anteriormente y una referencia al documento a parsear en forma de stream1 &ara esto !ltimo- nos apoyamos en un m/todo pri.ado au#iliar getCnputDtreamBE- 4ue se encar%a de abrir la cone#in con la <:L especificada Hmediante open@onnectionBEI y obtener el stream de entrada Hmediante getCnputDtreamBEI1 Con esto ya tenemos nuestra aplicacin Android preparada para parsear un documento ) L online utilizando el modelo "A)1 Veamos lo simple 4ue ser0a a'ora llamar a este parser por e8emplo desde nuestra acti.idad principal:
public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; RssKarserDax saxparser # new RssKarserDaxB0http4//www.europapress.es/rss/rss.aspx0E; 3ist.:oticia2 noticias # saxparser.parseBE; //<anipulaciTn del array de noticias //... "

Las lineas 9 y b del cdi%o anterior son las 4ue 'acen toda la ma%ia1 &rimero creamos el parser "A) pasndole la <:L del documento ) L y posteriormente llamamos al m/todo parseBE para obtener una lista de ob8etos de tipo :oticia 4ue posteriormente podremos manipular de la forma 4ue 4ueramos1 As0 de sencillo1

http://www.sgoliver.net/ log/!p"1313 #$gina 110 de 156

Desarrollo en Android

(an slo una anotacin final1 &ara 4ue este e8emplo funcione debemos aDadir pre.iamente permisos de acceso a internet para la aplicacin1 Esto se 'ace en el fic'ero Android anifest1#ml4ue 4uedar0a de la si%uiente forma:
.mani est xmlns4android#0http4//schemas.android.com/apk/res/android0 package#0net.sgoliver0 android4version@ode#0*0 android4version:ame#0*.$02 .uses-permission android4name#0android.permission.C:58R:850 /2 .application android4icon#07drawable/icon0 android4label#07string/app(name02 .activity android4name#0.>ndroidRml0 android4label#07string/app(name02 .intent- ilter2 .action android4name#0android.intent.action.<>C:0 /2 .category android4name#0android.intent.category.3>-:@,8R0 ./intent- ilter2 ./activity2 ./application2 .uses-sdk android4minDdk6ersion#0%0 /2 ./mani est2

/2

En la linea 9 del cdi%o pod/is .er cmo aDadimos el permiso de acceso a la red mediante el elemento .uses-permission2 con el parmetro android.permission.C:58R:85 &od/is descar%ar el cdi%o fuente de este art0culo pulsando a4u01 En los si%uientes art0culos .eremos los otros dos m/todos de tratamiento ) L en Android 4ue 'emos comentado (D* y "tA)) y por !ltimo intentaremos comentar las diferencias entre ellos dependiendo del conte#to de la aplicacin1 ACTUALIAACIBC: Android propone un modelo "A) alternati.o 4ue puede ayudar a simplicar al%unas acciones y disminuir la comple8idad del 'andler necesario1 En este art0culo puedes aprender a utilizar esta nue.a .ariante de "A) para Android1

http://www.sgoliver.net/ log/!p"1313 #$gina 111 de 156

Desarrollo en Android

Tratamiento de XML en Android <II=: 'AX 'implificado


En el art0culo anterior del tutorial .imos cmo realizar la lectura y tratamiento de un documento ) L utilizando el modelo "A) clsico1 Vimos cmo implementar un )andler "A)- donde se defin0an las acciones a realizar tras recibirse cada uno de los posibles e.entos %enerados por el parser ) L1 Este modelo- a pesar de funcionar perfectamente y de forma bastante eficiente- tiene claras des.enta8as1 &or un lado se 'ace necesario definir una clase independiente para el )andler1 Adicionalmente- la naturaleza del modelo "A) implica la necesidad de poner bastante atencin a la 'ora de definir dic'o )andler- ya 4ue los e.entos "A) definidos no estan li%ados de nin%una forma a eti4uetas concretas del documento ) L sino 4ue se lanzarn para todas ellas- al%o 4ue obli%a entre otras cosas a realizar la distincin entre eti4uetas dentro de cada e.ento y a realizar otros c'e4ueos adicionales1 Estos problemas se pueden obser.ar perfectamente en el e.ento end8lementBE 4ue definimos en el e8emplo del art0culo anterior1 En primer lu%ar ten0amos 4ue comprobar la condicin de 4ue el atributo noticia>ctual no fuera null- para e.itar confundir el elemento .title2 descendiente de .channel2 con el del mismo nombre pero descendiente de .item21 &osteriormente- ten0amos 4ue distin%uir con un IP %i%antesco entre todas las eti4uetas posibles para realizar una accin u otra1 2 todo esto para un documento ) L bastante sencillo1 3o es dificil darse cuenta de 4ue para un documento ) L al%o ms elaborado la comple8idad del 'andler podr0a dispararse rpidamente- dando lu%ar a posibles errores1 &ara e.itar estos problemas- Android propone una .ariante del modelo "A) 4ue e.ita definir una clase separada para el 'andler y 4ue permite asociar directamente las acciones a eti4uetas concretas dentro de la estructura del documento ) L- lo 4ue ali.ia en %ran medida los incon.enientes mencionados1 Veamos cmo 4ueda nuestro parser ) L utilizando esta .ariante simplificada de "A) para Android y despu/s comentaremos los aspectos ms importantes del mismo1

http://www.sgoliver.net/ log/!p"1313 #$gina 112 de 156

Desarrollo en Android

import import import import import import

java.io.CA8xception; java.io.CnputDtream; java.net.<al ormed-R38xception; java.net.-R3; java.util.>rray3ist; java.util.3ist;

import org.xml.sax.>ttributes; import import import import import import android.sax.8lement; android.sax.8nd8lement3istener; android.sax.8nd5ext8lement3istener; android.sax.Root8lement; android.sax.Dtart8lement3istener; android.util.Rml;

public class RssKarserDax& ! private -R3 rss-rl; private :oticia noticia>ctual; public RssKarserDax&BDtring urlE ! try ! this.rss-rl # new -R3BurlE; " catch B<al ormed-R38xception eE ! throw new Runtime8xceptionBeE; " " public 3ist.:oticia2 parseBE ! inal 3ist.:oticia2 noticias # new >rray3ist.:oticia2BE; Root8lement root # new Root8lementB0rss0E; 8lement channel # root.get@hildB0channel0E; 8lement item # channel.get@hildB0item0E; item.setDtart8lement3istenerBnew Dtart8lement3istenerBE ! public void startB>ttributes attrsE ! noticia>ctual # new :oticiaBE; " "E;

http://www.sgoliver.net/ log/!p"1313 #$gina 113 de 156

Desarrollo en Android

item.set8nd8lement3istenerBnew 8nd8lement3istenerBE! public void endBE ! noticias.addBnoticia>ctualE; " "E;

item.get@hildB0title0E.set8nd5ext8lement3istenerB new 8nd5ext8lement3istenerBE! public void endBDtring bodyE ! noticia>ctual.set5ituloBbodyE; " "E; item.get@hildB0link0E.set8nd5ext8lement3istenerB new 8nd5ext8lement3istenerBE! public void endBDtring bodyE ! noticia>ctual.set3inkBbodyE; " "E; item.get@hildB0description0E.set8nd5ext8lement3istenerB new 8nd5ext8lement3istenerBE! public void endBDtring bodyE ! noticia>ctual.setJescripcionBbodyE; " "E; item.get@hildB0guid0E.set8nd5ext8lement3istenerB new 8nd5ext8lement3istenerBE! public void endBDtring bodyE ! noticia>ctual.setHuidBbodyE; " "E; item.get@hildB0pubJate0E.set8nd5ext8lement3istenerB new 8nd5ext8lement3istenerBE! public void endBDtring bodyE ! noticia>ctual.setFechaBbodyE; " "E; try ! Rml.parseBthis.getCnputDtreamBEG Rml.8ncoding.-5F(1G root.get@ontent,andlerBEE;

" catch B8xception exE ! throw new Runtime8xceptionBexE; "

http://www.sgoliver.net/ log/!p"1313 #$gina 114 de 156

Desarrollo en Android
return noticias;

"

"

private CnputDtream getCnputDtreamBE ! try ! return rss-rl.open@onnectionBE.getCnputDtreamBE; " catch BCA8xception eE ! throw new Runtime8xceptionBeE; " "

Debemos atender principalmente al m/todo parseBE1 En el modelo "A) clsico nos limitamos a instanciar al )andler definido en una clase independiente y llamar al correspondiente m/todo parseBE de "A)1 &or el contrario- en este nue.o modelo "A) simplificado de Android- las acciones a realizar para cada e.ento las .amos a definir en esta misma clase y adems asociadas a eti4uetas concretas del ) L1 2 para ello lo primero 4ue 'aremos ser navegar por la estructura del ) L 'asta lle%ar a las eti4uetas 4ue nos interesa tratar y una .ez all0- asi%narle al%unos de los listeners disponibles Hde apertura (Dtart8lement3istener) o cierre (8nd8lement3istener) de eti4uetaI incluyendo las acciones oportunas1 De esta forma- para el elemento .item2 na.e%aremos 'asta /l obteniendo en primer lu%ar el elemento ra0z del ) L (.rss2) declarando un nue.o ob8eto Root8lement y despu/s accederemos a su elemento 'i8o .channel2 y a su .ez a su elemento 'i8o .item2- utilizando en cada paso el m/todo get@hildBE1 <na .ez 'eos lle%ado a la eti4ueta deseada- asi%naremos los listeners necesariosen nuestro caso uno de apertura de eti4ueta y otro de cierre- donde inicializaremos la noticia actual y la aDadiremos a la lista final respecti.amente- de forma anlo%a a lo 4ue 'ac0amos para el modelo "A) clsico1 &ara el resto de eti4uetas actuaremos de la misma forma- accediendo a ellas con get@hildBE y asi%nado los listeners necesarios1 Pinalmente- iniciaremos el proceso de parsin% simplemente llamando al m/todo parseBE definido en la clase android.-til.Rml- al 4ue pasaremos como parmetros el stream de entrada- la codificacin del documento ) L y un 'andler "A) obtenido directamente del ob8eto Root8lement definido anteriormente1 Como .emos- este modelo "A) alternati.o simplifica la elaboracin del 'andler necesario y puede ayudar a e.itar posibles errores en el 'andler y disminuir la comple8idad del mismo para casos en los 4ue el documento ) L no sea tan sencillo como el utilizado para estos e8emplos1 &or supuesto- el modelo clsico es tan .lido y eficiente como /ste- por lo 4ue la eleccin entre ambos es cuestin de %ustos1
http://www.sgoliver.net/ log/!p"1313 #$gina 115 de 156

Desarrollo en Android

El cdi%o fuente de este art0culo puede descar%arse desde este enlace1 En el si%uiente art0culo pasaremos ya a describir el si%uiente de los m/todos de lectura de ) L en Android- llamado Doc$ment 4!%ect Model (D* )1

Tratamiento de XML en Android <III=: !DM


En el art0culo anterior del curso de pro%ramacin para Android 'ablamos sobre "A)- el primero de los m/todos disponibles en Android para leer fic'eros ) L desde nuestras aplicaciones1 En este se%undo art0culo .amos a centrarnos en D* - otro de los m/todos clsicos para la lectura y tratamiento de ) L1 Cuando comentbamos la filosof0a de "A) ya .imos cmo con dic'o modelo el tratamiento del fic'ero ) L se realizaba de forma secuencial- es decir- se iban realizando las acciones necesarias durante la propia lectura del documento1 "in embar%o- con D* la estrate%ia cambia radicalmente1 Con D* - el documento ) L se lee completamente antes de poder realizar nin%una accin en funcin de su contenido1 Esto es posible %racias a 4ue- como resultado de la lectura del documento- el parser D* de.uel.e todo su contenido en forma de una estructura de tipo rbol- donde los distintos elementos del ) L se representa en forma de nodos y su 8erar4u0a padreA'i8o se establece mediante relaciones entre dic'os nodos1 Como e8emplo- .emos un e8emplo de ) L sencillo y cmo 4uedar0a su representacin en forma de rbol:
.noticias2 .noticia2 .titulo25*./titulo 2 .link23*./link2 ./noticia2 .noticia2 .titulo25&./titulo 2 .link23&./link2 ./noticia2 .noticias2

Este ) L se traducir0a en un rbol parecido al si%uiente:

http://www.sgoliver.net/ log/!p"1313 #$gina 116 de 156

Desarrollo en Android

Como .emos- este rbol conser.a la misma informacin contenida en el fic'ero ) L pero en forma de nodos y transiciones entre nodos- de forma 4ue se puede na.e%ar fcilmente por la estructura1 Adems- este rbol se conser.a persistente en memoria una .ez leido el documento completo- lo 4ue permite procesarlo en cual4uier orden y tantas .eces como sea necesario (a diferencia de "A)- donde el tratamiento era secuencial y siempre de principio a fin del documento- no pudiendo .ol.er atrs una .ez finalizada la lectura del ) L)1 &ara todo esto- el modelo D* ofrece una serie de clases y m/todos 4ue permiten almacenar la informacin de la forma descrita y facilitan la na.e%acin y el tratamiento de la estructura creada1 Veamos cmo 4uedar0a nuestro parser utilizando el modelo D* los detalles ms importantes1
public class RssKarserJom ! private -R3 rss-rl; public RssKarserJomBDtring urlE ! try ! this.rss-rl # new -R3BurlE; " catch B<al ormed-R38xception eE ! throw new Runtime8xceptionBeE; " " public 3ist.:oticia2 parseBE ! //Cnstanciamos la Sbrica para JA< Jocument;uilderFactory actory # Jocument;uilderFactory.newCnstanceBE;

y 8usto despu/s comentaremos

http://www.sgoliver.net/ log/!p"1313 #$gina 117 de 156

Desarrollo en Android
3ist.:oticia2 noticias # new >rray3ist.:oticia2BE; try !

//@reamos un nuevo parser JA< Jocument;uilder builder # actory.newJocument;uilderBE; //RealiNamos lalectura completa del R<3 Jocument dom # builder.parseBthis.getCnputDtreamBEE; //:os posicionamos en el nodo principal del Srbol B.rss2E 8lement root # dom.getJocument8lementBE; //3ocaliNamos todos los elementos .item2 :ode3ist items # root.get8lements;y5ag:ameB0item0E; //Recorremos la lista de noticias or Bint i#$; i.items.get3engthBE; i99E ! :oticia noticia # new :oticiaBE; //Abtenemos la noticia actual :ode item # items.itemBiE; //Abtenemos la lista de datos de la noticia actual :ode3ist datos:oticia # item.get@hild:odesBE; //Krocesamos cada dato de la noticia or Bint j#$; j.datos:oticia.get3engthBE; j99E ! :ode dato # datos:oticia.itemBjE; Dtring eti+ueta # dato.get:ode:ameBE; i Beti+ueta.e+ualsB0title0EE ! Dtring texto # obtener5extoBdatoE; noticia.set5ituloBtextoE; " else i Beti+ueta.e+ualsB0link0EE ! noticia.set3inkBdato.getFirst@hildBE.get:ode6alueBEE; " else i Beti+ueta.e+ualsB0description0EE ! Dtring texto # obtener5extoBdatoE; noticia.setJescripcionBtextoE; " else i Beti+ueta.e+ualsB0guid0EE ! noticia.setHuidBdato.getFirst@hildBE.get:ode6alueBEE; " else i Beti+ueta.e+ualsB0pubJate0EE ! noticia.setFechaBdato.getFirst@hildBE.get:ode6alueBEE

http://www.sgoliver.net/ log/!p"1313 #$gina 118 de 156

Desarrollo en Android
; " noticias.addBnoticiaE; " catch B8xception exE ! throw new Runtime8xceptionBexE; " return noticias; "

"

"

private Dtring obtener5extoB:ode datoE ! Dtring;uilder texto # new Dtring;uilderBE; :ode3ist ragmentos # dato.get@hild:odesBE; or Bint k#$;k. ragmentos.get3engthBE;k99E ! " return texto.toDtringBE; " private CnputDtream getCnputDtreamBE ! try ! return rss-rl.open@onnectionBE.getCnputDtreamBE; " catch BCA8xception eE ! throw new Runtime8xceptionBeE; " " " texto.appendB ragmentos.itemBkE.get:ode6alueBEE;

3os centramos una .ez ms en el m/todo parseBE1 Al i%ual 4ue 'ac0amos para "A)- el primer paso ser instanciar una nue.a fbrica- esta .ez de tipo Jocument;uilderFactory- y posteriormente crear un nue.o parser a partir de ella mediante el m/todo newJocument;uilderBE1 (ras esto- ya podemos realizar la lectura del documento ) L llamando al m/tod parseBE de nuestro parser D* - pasndole como parmetro el stream de entrada del fic'ero1 Al 'acer estoel documento ) L se leer completo y se %enerar la estructura de rbol e4ui.alente- 4ue se
http://www.sgoliver.net/ log/!p"1313 #$gina 119 de 156

Desarrollo en Android

de.ol.er como un ob8eto de tipo Jocument1 Qste ser el ob8eto 4ue podremos na.e%ar para realizar eltratamiento necesario del ) L1 &ara ello- lo primero 4ue 'aremos ser acceder al nodo principal del rbol (en nuestro caso- la eti4ueta .rss2) utilizando el m/todo getJocument8lementBE1 <na .ez posicionados en dic'o nodo- .amos a buscar todos los nodos cuya eti4ueta sea .item21 Esto lo conse%uimos utilizando el m/todo de b!s4ueda por nombre de eti4uetaget8lements;y5ag:ameBnombre_de_etiquetaE- 4ue de.ol.er una lista (de tipo :ode3ist) con todos los nodos 'i8os del nodo actual cuya eti4ueta coincida con la pasada como parmetro1 <na .ez tenemos localizados todos los elementos .item2- 4ue representan a cada noticia- los .amos a recorrer uno a uno para ir %enerando todos los ob8etos :oticia necesarios1 &ara cada uno de ellos- se obtendrn los nodos 'i8os del elemento mediante get@hild:odesBE y se recorrern /stos obteniendo su te#to y almacenndolo en el atributo correspondiente del ob8eto :oticia1 &ara saber a 4u/ eti4ueta corresponde cada nodo 'i8o utilizamos el m/todo get:ode:ameBE1 erece la pena pararnos un poco en comentar la forma de obtener el te#to contenido en un nodo1 Como .imos al principio del art0culo en el e8emplo %rfico de rbol D* - el te#to de un nodo determinado se almacena a su .ez como nodo 'i8o de dic'o nodo1 Este nodo de te#to suele ser !nico- por lo 4ue la forma 'abitual de obtener el te#to de un nodo es obtener su primer nodo 'i8o y de /ste !ltimo obtener su .alor: CDtring texto # nodo.getFirst@hildBE.get:ode6alueBE; "in embar%o- en ocasiones- el te#to contenido en el nodo .iene fra%mentado en .arios nodos 'i8os- en .ez de slo uno1 Esto ocurre por e8emplo cuando se utilizan en el te#to entidades F( L- como por e8emplo c4uotd 1 En estas ocasiones- para obtener el te#to completo 'ay 4ue recorrer todos los nodos 'i8os e ir concatenando el te#to de cada uno para formar el te#to completo1 Esto es lo 4ue 'ace nuestra funcin au#iliar obtener(e#to():
private Dtring obtener5extoB:ode datoE ! Dtring;uilder texto # new Dtring;uilderBE; :ode3ist ragmentos # dato.get@hild:odesBE; or Bint k#$;k. ragmentos.get3engthBE;k99E texto.appendB ragmentos.itemBkE.get:ode6alueBEE " return texto.toDtringBE; "

! ;

http://www.sgoliver.net/ log/!p"1313 #$gina 120 de 156

Desarrollo en Android

Como .emos- el modelo D* nos permite localizar y tratar determinados elementos concretos del documento ) L- sin la necesidad de recorrer todo su contenido de principio a fin1 Ademsa diferencia de "A)- como tenemos car%ado en memoria el documento completo de forma persistente (en forma de ob8eto Jocument)- podremos consultar- recorrer y tratar el documento tantas .eces como sea necesario sin necesidad de .ol.erlo a parsear1 En un art0culo posterior .eremos como todas estas caracter0sticas pueden ser .enta8as o incon.enientes se%!n el conte#to de la aplicacin y el tipo de ) L tratado1

Tratamiento de XML en Android <I-=: XmlPull


En los art0culos anteriores dedicados al tratamiento de ) L en aplicaciones Android (parte Cparte B- parte 6) dentro de nuestro tutorial de pro%ramacin Android 'emos comentado ya los modelos "A) y D* - los dos m/todos ms comunes de lectura de ) L soportados en la plataforma1 En este cuarto art0culo nos .amos a centrar en el !ltimo m/todo menos conocido- aun4ue i%ual de .lido se%!n el conte#to de la aplicacin- llamado )ml&ull1 Este m/todo es una .ersin similar al modelo "tA) ("treamin% A&I for ) L)- 4ue en esencia es muy parecido al modelo "A) ya comentado1 2 di%o muy parecido por4ue tambi/n se basa en definir las acciones a realizar para cada uno de los e.entos %enerados durante la lectura secuencial del documento ) L1 KCul es la diferencia entoncesL La diferencia radica principalmente en 4ue- mientras 4ue en "A) no ten0amos control sobre la lectura del ) L una .ez iniciada (el parser lee automticamente el ) L de principio a fin %enerando todos los e.entos necesarios)- en el modelo )ml&ull .amos a poder %uiar o inter.enir en la lectura del documento- siendo nosotros los 4ue .ayamos pidiendo de forma e#pl0cita la lectura del si%uiente elemento del ) L y respondiendo al resultado e8ecutando las acciones oportunas1

http://www.sgoliver.net/ log/!p"1313 #$gina 121 de 156

Desarrollo en Android

Veamos cmo podemos 'acer esto:


public class RssKarserKull ! private -R3 rss-rl; public RssKarserKullBDtring urlE ! try ! this.rss-rl # new -R3BurlE; " catch B<al ormed-R38xception eE ! throw new Runtime8xceptionBeE; " " public 3ist.:oticia2 parseBE ! 3ist.:oticia2 noticias # null; RmlKullKarser parser # Rml.newKullKarserBE; try ! parser.setCnputBthis.getCnputDtreamBEG nullE; int evento # parser.get8vent5ypeBE; :oticia noticia>ctual # null; while Bevento P# RmlKullKarser.8:J(JA@-<8:5E ! Dtring eti+ueta # null; switch BeventoE ! case RmlKullKarser.D5>R5(JA@-<8:54

http://www.sgoliver.net/ log/!p"1313 #$gina 122 de 156

Desarrollo en Android
noticias # new >rray3ist.:oticia2BE; break; case RmlKullKarser.D5>R5(5>H4 eti+ueta # parser.get:ameBE; i Beti+ueta.e+ualsB0item0EE ! noticia>ctual # new :oticiaBE; " else i Bnoticia>ctual P# nullE ! i Beti+ueta.e+ualsB0link0EE ! noticia>ctual.set3inkBparser.next5extBEE; " else i Beti+ueta.e+ualsB0description0EE ! noticia>ctual.setJescripcionBparser.next5extBEE; " else i Beti+ueta.e+ualsB0pubJate0EE ! noticia>ctual.setFechaBparser.next5extBEE; " else i Beti+ueta.e+ualsB0title0EE ! noticia>ctual.set5ituloBparser.next5extBEE; " else i Beti+ueta.e+ualsB0guid0EE ! noticia>ctual.setHuidBparser.next5extBEE; " " break; case RmlKullKarser.8:J(5>H4 eti+ueta # parser.get:ameBE; i Beti+ueta.e+ualsB0item0E `` noticia>ctual P# nullE ! noticias.addBnoticia>ctualE; " break;

" " catch B8xception exE ! throw new Runtime8xceptionBexE; " return noticias; " private CnputDtream getCnputDtreamBE

" evento # parser.nextBE;

http://www.sgoliver.net/ log/!p"1313 #$gina 123 de 156

Desarrollo en Android
!

try !

" "

return rss-rl.open@onnectionBE.getCnputDtreamBE; " catch BCA8xception eE ! throw new Runtime8xceptionBeE; "

Centrndonos una .ez ms en el m/todo parseBE- .emos 4ue tras crear el nue.o parser )ml&ull y establecer el fic'ero de entrada en forma de stream Hmediante RmlKull.newKullKarserBE y parser.setCnputB...EI nos metemos en un buble en el 4ue iremos solicitando al parser en cada paso el si%uiente e.ento encontrado en la lectura del ) L- utilizando para ello el m/todo parser.nextBE1 &ara cada e.ento de.uelto como resultado consultaremos su tipo mediante el m/todo parser.get8vent5ypeBE y responderemos con las acciones oportunas se%!n dic'o tipo (D5>R5(JA@-<8:58:J(JA@-<8:5- D5>R5(5>H- 8:J(5>H)1 <na .ez identificado el tipo concreto de e.entopodremos consultar el nombre de la eti4ueta del elemento ) L mediante parser.get:ameBE y su te#to correspondiente mediante parser.next5extBE1 En cuanto a la obtencin del te#to- con este modelo tenemos la .enta8a de no tener 4ue preocuparnos por >recolectar? todos los fra%mentos de te#to contenidos en el elemento ) L- ya 4ue next5extBE de.ol.er todo el te#to 4ue encuentre 'asta el pr#imo e.ento de fin de eti4ueta (8:5(5>H)1 2 sobre este modelo de tratamiento no 4ueda muc'o ms 4ue decir- ya 4ue las acciones e8ecutadas en cada caso son anlo%as a las 4ue ya .imos en los art0culos anteriores1 El cdi%o fuente completo de este art0culo pod/is descar%arlo pulsando a4u01 Espero 'aber sido capaz de mostrar con claridad en estos cuatro art0culos todas las posibilidades e#istentes a la 'ora de leer y procesar documentos ) L en aplicaciones Android1

http://www.sgoliver.net/ log/!p"1313 #$gina 124 de 156

Desarrollo en Android

ases de !atos en Android <I=: Primeros pasos


En los si%uientes art0culos de este tutorial de pro%ramacin Android- nos .amos a detener en describir las distintas opciones de acceso a datos 4ue proporciona la plataforma y en cmo podemos realizar las tareas ms 'abituales dentro de este apartado1 La plataforma Android proporciona dos 'erramientas pricipales para el almacenamiento y consulta de datos estructurados:

+ases de Datos ",Lite Content &ro.iders

En estos pr#imos art0culos nos centraremos en la primera opcin- S8/ite- 4ue abarcar todas las tareas relacionadas con el almacenamiento de los datos propios de nuestra aplicacin1 El se%undo de los mecanismos- los (ontent "roviders- 4ue trataremos ms adelante- nos facilitarn la tarea de 'acer .isibles esos datos a otras aplicaciones y- de forma rec0proca- de permitir la consulta de datos publicados por terceros desde nuestra aplicacin1 ",Lite es un motor de bases de datos muy popular en la actualidad por ofrecer caracter0sticas tan interesantes como su pe4ueDo tamaDo- no necesitar ser.idor- precisar poca confi%uracin- ser transaccional y por supuesto ser de cdi%o libre1 Android incorpora de serie todas las 'erramientas necesarias para la creacin y %estin de bases de datos ",Lite- y entre ellas una completa A&I para lle.ar a cabo de manera sencilla todas las tareas necesarias1 "in embar%o- en este primer art0culo sobre bases de datos en Android no .amos a entrar en muc'o detalle con esta A&I1 &or el momento nos limitaremos a .er el cdi%o
http://www.sgoliver.net/ log/!p"1313 #$gina 125 de 156

Desarrollo en Android

necesario para crear una base de datos- insertaremos al%!n dato de prueba- y .eremos cmo podemos comprobar 4ue todo funciona correctamente1 En Android- la forma t0pica para crear- actualizar- y conectar con una base de datos ",Lite ser a tra./s de una clase au#iliar llamada Dc3iteApen,elper- o para ser ms e#actos- de una clase propia 4ue deri.e de ella y 4ue debemos personalizar para adaptarnos a las necesidades concretas de nuestra aplicacin1 La clase Dc3iteApen,elper tiene tan slo un constructor- 4ue normalmente no necesitaremos sobrescribir- y dos m/todos abstractos- on@reateBE y on-pgradeBE- 4ue deberemos personalizar con el cdi%o necesario para crear nuestra base de datos y para actualizar su estructura respecti.amente1 Como e8emplo- nosotros .amos a crear una base de datos muy sencilla llamada ;J-suarioscon una sla tabla llamada -suarios 4ue contendr slo dos campos: nombre e email1 &ara ellos- .amos a crear una clase deri.ada de Dc3iteApen,elper 4ue llamaremos -suariosDc3ite,elper- donde sobrescribiremos los m/todos on@reateBE y on-pgradeBE para adaptarlos a la estructura de datos indicada:
package net.sgoliver.android; import import import import android.content.@ontext; android.database.s+lite.Dc3iteJatabase; android.database.s+lite.Dc3iteJatabase.@ursorFactory; android.database.s+lite.Dc3iteApen,elper;

public class -suariosDc3ite,elper extends Dc3iteApen,elper ! //Dentencia Dc3 para crear la tabla de -suarios Dtring s+l@reate # 0@R8>58 5>;38 -suarios Bcodigo C:58H8RG nombre 58R5E0; public -suariosDc3ite,elperB@ontext contextoG Dtring nombreG @ursorFactory actoryG int versionE ! superBcontextoG nombreG actoryG versionE; " 7Averride public void on@reateBDc3iteJatabase dbE ! //De ejecuta la sentencia Dc3 de creaciTn de la tabla db.execDc3Bs+l@reateE; " 7Averride public void on-pgradeBDc3iteJatabase dbG int version>nteriorG int version:uevaE ! //:A5>4 Kor simplicidad del ejemplo a+uX utiliNamos directamente la opciTn de // eliminar la tabla anterior y crearla de nuevo vacXa con el nuevo ormato. // Din embargo lo normal serS +ue haya +ue migrar datos de la

http://www.sgoliver.net/ log/!p"1313 #$gina 126 de 156

Desarrollo en Android
tabla antigua //

a la nuevaG por lo +ue este mZtodo deberXa ser mSs elaborado.

//De elimina la versiTn anterior de la tabla db.execDc3B0JRAK 5>;38 CF 8RCD5D -suarios0E; //De crea la nueva versiTn de la tabla db.execDc3Bs+l@reateE; " "

Lo primero 4ue 'acemos es definir una .ariable llamado s+l@reate donde almacenamos la sentencia ",L para crear una tabla llamada -suarios con los campos alfanum/ricos nombre e email1 CDTA: 3o es ob8eti.o de este tutorial describir la sinta#is del len%ua8e ",L ni las particularidades del motor de base de datos ",Lite- por lo 4ue no entrar/ a describir las sentencias ",L utilizadas1 &ara ms informacin sobre ",Lite puedes consultar la documentacin oficial o empezar por leer una pe4ueDa introduccin 4ue 'ice en este mismo blo% cuando trat/ el tema de utilizar ",Lite desde aplicaciones 13E(

El m/todo on@reateBE ser e8ecutado automticamente por nuestra clase -suariosJ;,elper cuando sea necesaria la creacin de la base de datos- es decir- cuando a!n no e#ista1 Las tareas t0picas 4ue deben 'acerse en este m/todo sern la creacin de todas las tablas necesarias y la insercin de los datos iniciales si son necesarios1 En nuestro caso- slo .amos a crear la tabla -suarios descrita anteriomente1 &ara la creacin de la tabla utilizaremos la sentencia ",L ya definida y la e8ecutaremos contra la base de datos utilizando el m/todo ms sencillo de los disponibles en la A&I de ",Lite proporcionada por Android- llamado execDc3BE1 Este m/todo se limita a e8ecutar directamente el cdi%o ",L 4ue le pasemos como parmetro1 &or su parte- el m/todo on-pgradeBE se lanzar automticamente cuando sea necesaria una actualizacin de la estructura de la base de datos o una con.ersin de los datos1 <n e8emplo prctico: ima%inemos 4ue publicamos una aplicacin 4ue utiliza una tabla con los campos usuario e email (llam/moslo .ersin C de la base de datos)1 s adelante- ampliamos la funcionalidad de nuestra aplicacin y necesitamos 4ue la tabla tambi/n incluya un campo adicional por e8emplo con la edad del usuario (.ersin B de nuestra base de datos)1 &ues bienpara 4ue todo funcione correctamente- la primera .ez 4ue e8ecutemos la .ersin ampliada de la aplicacin necesitaremos modificar la estructura de la tabla -suarios para aDadir el nue.o campo edad1 &ues este tipo de cosas son las 4ue se encar%ar de 'acer automticamente el m/todo on-pgradeBE cuando intentemos abrir una .ersin concreta de la base de datos 4ue a!n no e#ista1 &ara ello- como parmetros recibe la .ersin actual de la base de datos en el sistema- y la nue.a .ersin a la 4ue se 4uiere con.ertir1 En funcin de esta pare8a de datos necesitaremos realizar unas acciones u otras1 En nuestro caso de e8emplo optamos por la opcin ms sencilla: borrar la tabla actual y .ol.er a crearla con la nue.a estructura- pero como se indica en los comentarios del cdi%o- lo 'abitual ser 4ue necesitemos al%o ms de l%ica para con.ertir
http://www.sgoliver.net/ log/!p"1313 #$gina 127 de 156

Desarrollo en Android

la base de datos de una .ersin a otra y por supuesto para conser.ar los datos re%istrados 'asta el momento1 <na .ez definida nuestra clase )elper- la apertura de la base de datos desde nuestra aplicacin resulta ser al%o de lo ms sencillo1 Lo primero ser crear un ob8eto de la clase -suariosDc3ite,elper al 4ue pasaremos el conte#to de la aplicacin (en el e8emplo una referencia a la acti.idad principal)- el nombre de la base de datos- un ob8eto @ursorFactory 4ue t0picamente no ser necesario (en ese caso pasaremos el .alor null)- y por !ltimo la .ersin de la base de datos 4ue necesitamos1 La simple creacin de este ob8eto puede tener .arios efectos:

"i la base de datos ya e#iste y su .ersin actual coincide con la solicitada simplemente se realizar la cone#in con ella1 "i la base de datos e#iste pero su .ersin actual es anterior a la solicitada- se llamar automticamente al m/todo on-pgradeBE para con.ertir la base de datos a la nue.a .ersin y se conectar con la base de datos con.ertida1 "i la base de datos no e#iste- se llamar automticamente al m/todo on@reateBE para crearla y se conectar con la base de datos creada1

<na .ez tenemos una referencia al ob8eto -suariosDc3ite,elper- llamaremos a su m/todo getReadableJatabaseBE o getLritableJatabaseBE para obtener una referencia a la base de datos- dependiendo si slo necesitamos consultar los datos o tambi/n necesitamos realizar modificaciones- respecti.amente1 A'ora 4ue ya 'emos conse%uido una referencia a la base de datos (ob8eto de tipo Dc3iteJatabase) ya podemos realizar todas las acciones 4ue 4ueramos sobre ella1 &ara nuestro e8emplo nos limitaremos a insertar 7 re%istros de prueba- utilizando para ello el m/todo ya comentado execDc3BE con las sentencias C:D8R5 correspondientes1 &or !ltimo cerramos la cone#in con la base de datos llamando al m/todo closeBE1
package net.sgoliver.android; import android.app.>ctivity; import android.database.s+lite.Dc3iteJatabase; import android.os.;undle; public class >ndroid;aseJatos extends >ctivity ! 7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; //>brimos la base de datos ^J;-suarios^ en modo escritura -suariosDc3ite,elper usdbh # new -suariosDc3ite,elperBthisG 0J;-suarios0G nullG *E;

http://www.sgoliver.net/ log/!p"1313 #$gina 128 de 156

Desarrollo en Android
Dc3iteJatabase db # usdbh.getLritableJatabaseBE; //Di hemos abierto correctamente la base de datos i Bdb P# nullE ! //Cnsertamos W usuarios de ejemplo orBint i#*; i.#W; i99E ! //Heneramos los datos int codigo # i; Dtring nombre # 0-suario0 9 i; //Cnsertamos los datos en la tabla -suarios db.execDc3B0C:D8R5 C:5A -suarios BcodigoG nombreE 0 9 06>3-8D B0 9 codigo 9 0G ^0 9 nombre " //@erramos la base de datos db.closeBE;

90^E0E;

" " "

Vale- Ky a'ora 4u/L Kdnde est la base de datos 4ue acabamos de crearL Kcmo podemos comprobar 4ue todo 'a ido bien y 4ue los re%istros se 'an insertado correctamenteL Vayamos por partes1 En primer lu%ar .eamos dnde se 'a creado nuestra base de datos1 (odas las bases de datos ",Lite creadas por aplicaciones Android se almacenan en la memoria del tel/fono en un fic'ero con el mismo nombre de la base de datos situado en una ruta 4ue si%ue el si%uiente patrn: / data/data/pa+uete.java.de.la.aplicacion/databases/nombre(base(da tos En el caso de nuestro e8emplo- la base de datos se almacenar0a por tanto en la ruta si%uiente: /data/data/net.sgoliver.android/databases/J;-suarios &ara comprobar esto podemos 'acer lo si%uiente1 <na .ez e8ecutada por primera .ez desde Eclipse la aplicacin de e8emplo sobre el emulador de Android (y por supuesto antes de cerrarlo) podemos ir a la perspecti.a >DD "? (Dalvi# De!$g Monitor Server) de Eclipse y en la solapa >9ile E,plorer? podremos acceder al sistema de arc'i.os del emulador- donde podremos buscar la ruta indicada de la base de datos1 &odemos .er esto en la si%uiente ima%en (clicO para ampliar):

http://www.sgoliver.net/ log/!p"1313 #$gina 129 de 156

Desarrollo en Android

Con esto ya comprobamos al menos 4ue el fic'ero de nuestra base de datos se 'a creado en la ruta correcta1 2a slo nos 4ueda comprobar 4ue tanto las tablas creadas como los datos insertados tambi/n se 'an incluido correctamente en la base de datos1 &ara ello podemos recurrir a dos posibles m/todos: C1 (rasnferir la base de datos a nuestro &C y consultarla con cual4uier administrador de bases de datos ",Lite1 B1 Acceder directamente a la consola de comandos del emulador de Android y utilizar los comandos e#istentes para acceder y consultar la base de datos ",Lite1 El primero de los m/todos es sencillo1 El fic'ero de la base de datos podemos transferirlo a nuestro &C utilizando el botn de descar%a situado en la es4uina superior derec'a del e#plorador de arc'i.os (remarcado en ro8o en la ima%en anterior)1 5unto a este botn aparecen otros dos para 'acer la operacin contraria (copiar un fic'ero local al sistema de arc'i.os del emulador) y para eliminar fic'eros del emulador1 <na .ez descar%ado el fic'ero a nuestro sistema local- podemos utilizar cual4uier administrador de ",Lite para abrir y consultar la base de datos- por e8emplo ",Lite Administrator (freeEare)1 El se%undo m/todo utiliza una estrate%ia diferente1 En .ez de descar%ar la base de datos a nuestro sistema local- somos nosotros los 4ue accedemos de forma remota al emulador a tra./s de su consola de comandos (s)ell)1 &ara ello- con el emulador de Android a!n abierto- debemos abrir una consola de "AD*" y utilizar la utilidad adb.exe (Android De!$g :ridge) situada en la carpeta plat orm-tools del "D; de Android (en mi caso: c4\android-sdkwindows\plat orm-tools\)1 En primer lu%ar consultaremos los identificadores de todos los emuladores en e8ecucin mediante el comando >adb devices>1 Esto nos debe de.ol.er una !nica instancia si slo tenemos un emulador abierto- 4ue en mi caso particular se llama >emulator-WWW)>1 (ras conocer el identificador de nuestro emulador- .amos a acceder a su s'ell mediante el comando >adb -s identi icador-del-emulador shell>1 <na .ez conectados- ya podemos acceder a nuestra base de datos utilizando el comando s4lite6 pasndole la ruta del fic'ero- para nuestro e8emplo >s+lite' /data/data/net.sgoliver.android/databases/J;-suarios>1 "i todo 'a ido bien- debe aparecernos el prompt de ",Lite >s+lite2>- lo 4ue nos indicar 4ue ya podemos escribir las consultas ",L necesarias sobre nuestra base de datos1 3osotros .amos a comprobar
http://www.sgoliver.net/ log/!p"1313 #$gina 130 de 156

Desarrollo en Android

4ue e#iste la tabla -suarios y 4ue se 'an insertado los cinco re%istros de e8emplo1 &ara ello 'aremos la si%uiente consulta: >D838@5 ? FRA< -suarios;>1 "i todo es correcto esta instruccin debe de.ol.ernos los cinco usuarios e#istentes en la tabla1 En la ima%en si%uiente se muestra todo el proceso descrito (clicO para ampliar):

Con esto ya 'emos comprobado 4ue nuestra base de datos se 'a creado correctamente- 4ue se 'an insertado todos los re%istros de e8emplo y 4ue todo funciona se%!n se espera1 En los si%uientes art0culos comentaremos las distintas posibilidades 4ue tenemos a la 'ora de manipular los datos de la base de datos (insertar- eliminar y modificar datos) y cmo podemos realizar consultas sobre los mismos- ya 4ue Hcomo siempreI tendremos .arias opciones disponibles1

ases de !atos en Android <II=: Insertar3Actualizar3#liminar


En el art0culo anterior del curso de pro%ramacin en Android .imos cmo crear una base de datos para utilizarla desde nuestra aplicacin Android1 En este se%undo art0culo de la serie .amos a describir las posibles alternati.as 4ue proporciona la A&I de Android a la 'ora de insertaractualizar y eliminar re%istros de nuestra base de datos ",Lite1 La A&I de ",Lite de Android proporciona dos alternati.as para realizar operaciones sobre la base de datos 4ue no de.uel.en resultados (entre ellas la insercin@actualizacin@eliminacin de re%istros- pero tambi/n la creacin de tablas- de 0ndices- etc)1 El primero de ellos- 4ue ya comentamos bre.emente en el art0culo anterior- es el m/todo e#ec",L() de la clase ",LiteDatabase1 Este m/todo permite e8ecutar cual4uier sentencia ",L sobre la base de datos- siempre 4ue /sta no de.uel.a resultados1 &ara ello- simplemente aportaremos como parmetro de entrada de este m/todo la cadena de te#to correspondiente con la sentencia ",L1 Cuando creamos la base de datos en el post anterior ya .imos al%!n e8emplo de esto para insertar los re%istros de prueba1 6tros e0e'plos podr5an ser los sig)ientes:
http://www.sgoliver.net/ log/!p"1313 #$gina 131 de 156

Desarrollo en Android
//Cnsertar un registro db.execDc3B0C:D8R5 C:5A -suarios BusuarioGemailE 6>3-8D B^usu*^G^usu*7email.com^E 0E; //8liminar un registro db.execDc3B0J83858 FRA< -suarios L,8R8 usuario#^usu*^ 0E; //>ctualiNar un registro db.execDc3B0-KJ>58 -suarios D85 email#^nuevo7email.com^ L,8R8 usuario#^usu*^ 0E;

La se%unda de las alternati.as disponibles en la A&I de Android es utilizar los m/todos insertBE- updateBE y deleteBE proporcionados tambi/n con la clase Dc3iteJatabase1 Estos m/todos permiten realizar las tareas de insercin- actualizacin y eliminacin de re%istros de una forma al%o ms param/trica 4ue execDc3BE- separando tablas.alores y condiciones en parmetros independientes de estos m/todos1 Empecemos por el m/todo insertBE para insertar nue.os re%istros en la base de datos1 Este m/todo recibe tres parmetros- el primero de ellos ser el nombre de la tabla- el tercero sern los .alores del re%istro a insertar- y el se%undo lo ob.iaremos por el momento ya 4ue tan slo se 'ace necesario en casos muy puntuales (por e8emplo para poder insertar re%istros completamente .ac0os)- en cual4uier otro caso pasaremos con .alor null este se%undo parmetro1 Los .alores a insertar los pasaremos como elementos de una coleccin de tipo ContentValues1 Esta coleccin es de tipo diccionario- donde almacenaremos pare8as de clave0valor- donde la clave ser el nombre de cada campo y el valor ser el dato correspondiente a insertar en dic'o campo1 *ea'os )n e0e'plo:
//@reamos el registro a insertar como objeto @ontent6alues @ontent6alues nuevoRegistro # new @ontent6aluesBE; nuevoRegistro.putB0usuario0G 0usu*$0E; nuevoRegistro.putB0email0G0usu*$7email.com0E; //Cnsertamos el registro en la base de datos db.insertB0-suarios0G nullG nuevoRegistroE;

Los m/todos updateBE y deleteBE se utilizarn de forma muy parecida a /sta- con la sal.edad de 4ue recibirn un parmetro adicional con la condicin WHE'E de la sentencia ",L1 &or e8emplo- para actualizar el email del usuario de nombre X$s$;X 'ar0amos lo si%uiente:
//8stablecemos los campos-valores a actualiNar @ontent6alues valores # new @ontent6aluesBE; valores.putB0email0G0usu*(nuevo7email.com0E; //>ctualiNamos el registro en la base de datos db.updateB0-suarios0G valoresG 0usuario#^usu*^0E;

http://www.sgoliver.net/ log/!p"1313 #$gina 132 de 156

Desarrollo en Android

Como podemos .er- como tercer parmetro del m/todo updateBE pasamos directamente la condicin del *"DATE tal como lo 'ar0amos en la clusula WHE'E en una sentencia ",L normal1 El m/todo deleteBE se utilizar0a de forma anlo%a1 &or e8emplo para eliminar el re%istro del usuario X$s$<X 'ar0amos lo si%uiente:
//8liminamos el registro del usuario ^usu&^ db.deleteB0-suarios0G 0usuario#^usu&^0E;

Como .emos- .ol.emos a pasar como primer parmetro el nombre de la tabla y en se%undo lu%ar la condicin WHE'E1 &or supuesto- si no necesitramos nin%una condicin- podr0amos de8ar como null en este parmetro1 <n !ltimo detalle sobre estos m/todos1 (anto en el caso de e#ec",L() como en los casos de update() o delete() podemos utilizar ar%umentos dentro de las condiones de la sentencia ",L1 Esto no son ms 4ue partes varia!les de la sentencia ",L 4ue aportaremos en un array de .alores aparte- lo 4ue nos e.itar pasar por la situacin t0pica en la 4ue tenemos 4ue construir una sentencia ",L concatenando cadenas de te#to y .ariables para formar el comando ",L final1 Estos ar%umentos ",L se indicarn con el s0mbolo XLY- y los .alores de dic'os ar%umentos deben pasarse en el array en el mismo orden 4ue aparecen en la sentencia ",L1 As51 por
e0e'plo1 pode'os es(ri ir instr)((iones (o'o la sig)iente:

//8liminar un registro con execDc3BEG utiliNando argumentos DtringUV args # new DtringUV!0usu*0"; db.execDc3B0J83858 FRA< -suarios L,8R8 usuario#/0G argsE; //>ctualiNar dos registros con updateBEG utiliNando argumentos @ontent6alues valores # new @ontent6aluesBE; valores.putB0email0G0usu*(nuevo7email.com0E; DtringUV args # new DtringUV!0usu*0G 0usu&0"; db.updateB0-suarios0G valoresG 0usuario#/ AR usuario#/0G argsE;

Esta forma de pasar a la sentencia ",L determinados datos .ariables puede ayudarnos adems a escribir cdi%o ms limpio y e.itar posibles errores1

http://www.sgoliver.net/ log/!p"1313 #$gina 133 de 156

Desarrollo en Android

ases de !atos en Android <III=: Consultar39ecuperar registros


En el anterior art0culo del curso .imos todas las opciones disponibles a la 'ora de insertaractualizar y eliminar datos de una base de datos ",Lite en Android1 En esta nue.a entre%a .amos a describir la !ltima de las tareas importantes de tratamiento de datos 4ue nos 4ueda por .er- la seleccin y recuperacin de datos1 De forma anlo%a a lo 4ue .imos para las sentencias de modificacin de datos- .amos a tener dos opciones principales para recuperar re%istros de una base de datos ",Lite en Android1 La primera de ellas utilizando directamente un comando de seleccin ",L- y como se%unda opcin utilizando un m/todo espec0fico donde parametri=aremos la consulta a la base de datos1 &ara la primera opcin utilizaremos el m/todo raE,uery() de la clase ",LiteDatabase1 Este m/todo recibe directamente como parmetro un comando ",L completo- donde indicamos los campos a recuperar y los criterios de seleccin1 El resultado de la consulta lo obtendremos en forma de cursor- 4ue posteriormente podremos recorrer para procesar los re%istros recuperados1
/irva la sig)iente (ons)lta a 'odo de e0e'plo: http://www.sgoliver.net/ log/!p"1313 #$gina 134 de 156

Desarrollo en Android
@ursor c # db.rawcueryB0 D838@5 usuarioGemail FRA< -suarios L,8R8 usuario#^usu*^ 0E;

Como en el caso de los m/todos de modificacin de datos- tambi/n podemos aDadir a este m/todo una lista de ar%umentos .ariables 4ue 'ayamos indicado en el comando ",L con el s0mbolo X/X- por e8emplo as0:
DtringUV args # new DtringUV !0usu*0"; @ursor c # db.rawcueryB0 D838@5 usuarioGemail FRA< -suarios L,8R8 usuario#/ 0G argsE;

s adelante en este art0culo .eremos cmo podemos manipular el ob8eto @ursor para recuperar los datos obtenidos1 Como se%unda opcin para recuperar datos podemos utilizar el m/todo +ueryBE de la clase Dc3iteJatabase1 Este m/todo recibe .arios parmetros: el nombre de la tabla- un array con los nombre de campos a recuperar- la clusula WHE'E- un array con los ar%umentos .ariables incluidos en el WHE'E (si los 'ay- null en caso contrario)- la clusula >'4*" :- si e#iste- la clusula HA I?> si e#iste- y por !ltimo la clusula 4'DE' :- si e#iste1 *pcionalmente- se puede incluir un parmetro al final ms indicando el n!mero m#imo de re%istros 4ue 4ueremos 4ue nos de.uel.a la consulta1 Veamos el mismo e8emplo anterior utilizando el m/todo +ueryBE:

DtringUV campos # new DtringUV !0usuario0G 0email0"; DtringUV args # new DtringUV !0usu*0"; @ursor c # db.+ueryB0-suarios0G camposG 0usuario#/0G argsG nullG nullG nullE;

Como .emos- los resultados se de.uel.en nue.amente en un ob8eto @ursor 4ue deberemos recorrer para procesar los datos obtenidos1 &ara recorrer y manipular el cursor de.uelto por cual4uiera de los dos m/todos mencionados tenemos a nuestra disposicin .arios m/todos de la clase @ursor- entre los 4ue destacamos dos de los dedicados a recorrer el cursor de forma secuencial y en orden natural:

move5oFirstBE: mue.e el puntero del cursor al primer re%istro de.uelto1 move5o:extBE: mue.e el puntero del cursor al si%uiente re%istro de.uelto1

Los m/todos move5oFirstBE y move5o:extBE de.uel.en 5R-8 en caso de 'aber realizado el mo.imiento correspondiente del puntero sin errores- es decir- siempre 4ue e#ista un primer re%istro o un re%istro si%uiente- respecti.amente1
http://www.sgoliver.net/ log/!p"1313 #$gina 135 de 156

Desarrollo en Android

<na .ez posicionados en cada re%istro podremos utilizar cual4uiera de los m/todos getRRRBXndice(columnaE e#istentes para cada tipo de dato para recuperar el dato de cada campo del re%istro actual del cursor1 As0- si 4ueremos recuperar por e8emplo la se%unda columna del re%istro actual- y /sta contiene un campo alfanum/rico- 'aremos la llamada getDtringB*E H3*(A: los 0ndices comienzan por R- por lo 4ue la se%unda columna tiene 0ndice CI- en caso de contener un dato de tipo real llamar0amos a getJoubleB*E- y de forma anlo%a para todos los tipos de datos e#istentes1 Con todo esto en cuenta- .eamos cmo podr0amos recorrer el cursor de.uelto por el e8emplo anterior:
DtringUV campos # new DtringUV !0usuario0G 0email0"; DtringUV args # new DtringUV !0usu*0"; @ursor c # db.+ueryB0-suarios0G camposG 0usuario#/0G argsG nullG nullG nullE; //:os aseguramos de +ue existe al menos un registro i Bc.move5oFirstBEE ! //Recorremos el cursor hasta +ue no haya mSs registros do ! Dtring usuario # c.getDtringB$E; Dtring email # c.getDtringB*E; " whileBc.move5o:extBEE; "

Adems de los m/todos comentados de la clase @ursor e#isten muc'os ms 4ue nos pueden ser !tiles en muc'as ocasiones1 &or e8emplo- get@ountBE te dir el n!mero total de re%istros de.ueltos en el cursor- get@olumn:ameBiE de.uel.e el nombre de la columna con 0ndice imove5oKositionBiE mue.e el puntero del cursor al re%istro con 0ndice i- etc1 &od/is consultar la lista completa de m/todos disponibles en la clase Cursor en la documentacin oficial de Android1 Con esto- terminamos la serie de art0culos bsicos dedicados a las tareas de mantenimiento de datos en aplicaciones Android mediante bases de datos ",Lite1 "oy consciente de 4ue de8amos en el tintero al%unos temas al%o ms a.anzados (como por e8emplo el uso de transacciones- 4ue intentar/ tratar ms adelante)- pero con los m/todos descritos podremos realizar un porcenta8e bastante alto de todas las tareas necesarias relati.as al tratamiento de datos estructurados en aplicaciones Android1

http://www.sgoliver.net/ log/!p"1313 #$gina 136 de 156

Desarrollo en Android

Localizacin geogr"fica en Android <I=


La localizacin %eo%rfica en Android es uno de esos ser.icios 4ue- a pesar de re4uerir poco cdi%o para ponerlos en marc'a- no son para nada intuiti.os ni fciles de lle%ar a comprender por completo1 2 esto no es debido al diseDo de la plataforma Android en s0- sino a la propia naturaleza de este tipo de ser.icios1 &or un lado- e#isten multitud de formas de obtener la localizacin de un dispositi.o m.il- aun4ue la ms conocida y popular es la localizacin por =&"- tambi/n es posible obtener la posicin de un dispositi.o por e8emplo a tra./s de las antenas de telefon0a m.il o mediante puntos de acceso $iAPi cercanos- y todos cada uno de estos mecanismos tiene una precisin- .elocidad y consumo de recursos distinto1 &or otro lado- el modo de funcionamiento de cada uno de estos mecanismos 'ace 4ue su utilizacin desde nuestro cdi%o no sea todo lo directa e intuiti.a 4ue se desear0a1 Iremos comentando todo esto a lo lar%o del art0culo- pero .ayamos paso a paso1 EFuG mecanismos de localizacin tenemos disponi;lesH

http://www.sgoliver.net/ log/!p"1313 #$gina 137 de 156

Desarrollo en Android

Lo primero 4ue debe conocer una aplicacin 4ue necesite obtener la localizacin %eo%rfica es 4u/ mecanismos de localizacin (pro.eedores de localizacin- o location providers) tiene disponibles en el dispositi.o1 Como ya 'emos comentado- los ms comunes sern el =&" y la localizacin mediante la red de telefon0a- pero podr0an e#istir otros se%!n el tipo de dispositi.o1 La forma ms sencilla de saber los pro.eedores disponibles en el dispositi.o es mediante una llamada al m/todo get>llKrovidersBE de la clase 3ocation<anager- clase principal en la 4ue nos basaremos siempre a la 'ora de utilizar la A&I de localizacin de Android1 &ara elloobtendremos una referencia al location manager llamando a getDystemDerviceB3A@>5CA:(D8R6C@8E- y posteriormente obtendremos la lista de pro.eedores mediante el m/todo citado para obtener la lista de nombres de los pro.eedores:
3ocation<anager loc<anager # B3ocation<anagerEgetDystemDerviceB3A@>5CA:(D8R6C@8E; 3ist.Dtring2 listaKroviders # loc<anager.get>llKrovidersBE;

<na .ez obtenida la lista completa de pro.eedores disponibles podr0amos acceder a las propiedades de cual4uiera de ellos (precisin- coste- consumo de recursos- o si es capaz de obtener la altitud- la .elocidad- G)1 As0- podemos obtener una referencia al pro.ider mediante su nombre llamando al m/todo getKroviderBnombreE y posteriormente utilizar los m/todos disponibles para conocer sus propiedades- por e8emplo get>ccuracyBE para saber su precisin (tenemos disponibles las constantes @riteria.>@@-R>@_(FC:8 para precisin alta- y @riteria.>@@-R>@_(@A>RD8 para precisin media)- supports>ltitudeBE para saber si obtiene la altitud- o getKowerRe+uirementBE para obtener el ni.el de consumo de recursos del pro.eedor1 La lista completa de m/todos para obtener las caracter0sticas de un pro.eedor se puede consultar en la documentacin oficial de la clase Location&ro.ider1

3ocation<anager loc<anager # B3ocation<anagerEgetDystemDerviceB3A@>5CA:(D8R6C@8E; 3ist.Dtring2 listaKroviders # loc<anager.get>llKrovidersBE; 3ocationKrovider provider # loc<anager.getKroviderBlistaKroviders.getB$EE; int precision # provider.get>ccuracyBE; boolean obtiene>ltitud # provider.supports>ltitudeBE; int consumoRecursos # provider.getKowerRe+uirementBE;

Al mar%en de esto- 'ay 4ue tener en cuenta 4ue la lista de pro.eedores de.uelta por el m/todo get>llKrovidersBE contendr todos los pro.eedores de localizacin conocidos por el dispositi.o- incluso si /stos no estn permitidos (se%!n los permisos de la aplicacin) o no estn acti.ados- por lo 4ue esta informacin puede 4ue no nos sea de muc'a ayuda1 EFuG pro7eedor de localizacin es meIor para mi aplicacinH

http://www.sgoliver.net/ log/!p"1313 #$gina 138 de 156

Desarrollo en Android

Android proporciona un mecanismo alternati.o para obtener los pro.eedores 4ue cumplen unos determinados re4uisitos entre todos los disponibles1 &ara ello nos permite definir un criterio de b!s4ueda- mediante un ob8eto de tipo @riteria- en el 4ue podremos indicar las caracter0sticas m0nimas del pro.eedor 4ue necesitamos utilizar (pod/is consultar la documentacin oficial de la clase Criteria para saber todas las caracter0sticas 4ue podemos definir)1 As0- por e8emplo- para buscar uno con precisin alta y 4ue nos proporcione la altitud definir0amos el si%uiente criterio de b!s4ueda: C@riteria re+ # new @riteriaBE; Bre+.set>ccuracyB@riteria.>@@-R>@_(FC:8E; 6re+.set>ltitudeRe+uiredBtrueE; (ras esto- podremos utilizar los m/todos %et&ro.iders() o %et+est&ro.ider() para obtener la lista de pro.eedores 4ue se a8ustan me8or al criterio definido o el pro.eedor 4ue me8or se a8usta a dic'o criterio- respecti.amente1 Adems- ambos m/todos reciben un se%undo parmetro 4ue indica si 4ueremos 4ue slo nos de.uel.an pro.eedores 4ue estn acti.ados actualmente1
*ea'os (.'o se )tili7ar5an estos ',todos:
//<ejor proveedor por criterio Dtring mejorKrovider@rit # loc<anager.get;estKroviderBre+G

alseE;

//3ista de proveedores por criterio 3ist.Dtring2 listaKroviders@rit # loc<anager.getKrovidersBre+G alseE;

Con esto- ya tenemos una forma de seleccionar en cada disposti.o a4uel pro.eedor 4ue me8or se a8usta a nuestras necesidades1

E#st" disponi;le 2 acti7ado un pro7eedor determinadoH Aun4ue- como ya 'emos .isto- tenemos la posibilidad de buscar dinmicamente pro.eedores de localizacin se%!n un determinado criterio de b!s4ueda- es bastante com!n 4ue nuestra aplicacin est/ diseDada para utilizar uno en concreto- por e8emplo el =&"- y por tanto necesitaremos al%!n mecanismo para saber si /ste est acti.ado o no en el dispositi.o1 &ara esta tarea- la clase 3ocation<anager nos proporciona otro m/todo llamado isKrovider8nabledBE 4ue nos permite 'acer e#actamente lo 4ue necesitamos1 &ara ellodebemos pasarle el nombre del pro.ider 4ue 4ueremos consultar1 &ara los ms comunes tenemos .arias constantes ya definidas:

3ocation<anager.:85LARY(KRA6CJ8R1 Localizacin por la red de telefon0a1 3ocation<anager.HKD(KRA6CJ8R1 Localizacin por =&"1

http://www.sgoliver.net/ log/!p"1313 #$gina 139 de 156

Desarrollo en Android

De esta forma- si 4uisi/ramos saber si el =&" est 'abilitado o no en el dispositi.o (y actuar en consecuencia)- 'ar0amos al%o parecido a lo si%uiente:
//Di el HKD no estS habilitado i BPloc<anager.isKrovider8nabledB3ocation<anager.HKD(KRA6CJ8REE ! mostrar>visoHpsJeshabilitadoBE; "

En el cdi%o anterior- .erificamos si el =&" est acti.ado y en caso ne%ati.o mostramos al usuario un mensa8e de ad.ertencia1 Este mensa8e podr0amos mostralo sencillamente en forma de notificacin de tipo toast- pero en el pr#imo art0culo sobre localizacin .eremos cmo podemos- adems de informar de 4ue el =&" est desacti.ado- in.itar al usuario a acti.arlo diri%i/ndolo automticamente a la pantalla de confi%uracin del dispositi.o1 #l GP' 2a est" acti7adoJ E2 a5ora KuGH <na .ez 4ue sabemos 4ue nuestro pro.eedor de localizacin fa.orito est acti.ado- ya estamos en disposicin de intentar obtener nuestra localizacin actual1 2 a4u0 es donde las cosas empiezan a ser menos intuiti.as1 &ara empezar- en Android no e#iste nin%!n m/todo del tipo >o!tener"osici@nAct$alAB>1 *btener la posicin a tra./s de un dispositi.o de localizacin como por e8emplo el =&" no es una tarea inmediata- sino 4ue puede re4uerir de un cierto tiempo de procesamiento y de espera- por lo 4ue no tendr0a sentido proporcionar un m/todo de ese tipo1 "i buscamos entre los m/todos disponibles en la clase Location ana%er- lo ms parecido 4ue encontramos es un m/todo llamado get3astYnown3ocationBDtring providerE- 4ue como se puede suponer por su nombre- nos de.uel.e la 3ltima posici@n conocida del dispositi.o de.uelta por un pro.ider determinado1 Es importante entender esto: este m/todo 3* de.uel.e la posicin actual- este m/todo 3* solicita una nue.a posicin al pro.eedor de localizacin- este m/todo se limita a de.ol.er la !ltima posicin 4ue se obtu.o a tra./s del pro.eedor 4ue se le indi4ue como parmetro1 2 esta posicin se pudo obtener 'ace pocos se%undos- 'ace d0as- 'ace meses- o incluso nunca (si el dispositi.o 'a estado apa%ado- si nunca se 'a acti.ado el =&"- G)1 &or tanto- cuidado cuando se 'a%a uso de la posicin de.uelta por el m/todo get3astYnown3ocationBE1 Entonces- Kde 4u/ forma podemos obtener la posicin real actualizadaL &ues la forma correcta de proceder .a a consistir en al%o as0 como acti.ar el pro.eedor de localizacin y suscribirnos a sus notificaciones de cambio de posicin1 * dic'o de otra forma- .amos a suscribirnos al e.ento 4ue se lanza cada .ez 4ue un pro.eedor recibe nue.os datos sobre la localizacin actual1 2 para ello.amos a darle pre.iamente unas indicaciones (4ue no ordenes- ya .eremos esto en el pr#imo art0culo) sobre cada cuanto tiempo o cada cuanta distacia recorrida necesitar0amos tener una actualizacin de la posicin1 (odo esto lo .amos a realizar mediante una llamada al m/todo re+uest3ocation-pdatesBE- al 4ue deberemos pasar [ parmetros distintos:

3ombre del pro.eedor de localizacin al 4ue nos 4ueremos suscribir1

http://www.sgoliver.net/ log/!p"1313 #$gina 140 de 156

Desarrollo en Android

(iempo m0nimo entre actualizaciones- en milise%undos1 Distancia m0nima entre actualizaciones- en metros1 Instancia de un ob8eto 3ocation3istener- 4ue tendremos 4ue implementar pre.iamente para definir las acciones a realizar al recibir cada nue.a actualizacin de la posicin1

(anto el tiempo como la distancia entre actualizaciones pueden pasarse con .alor R- lo 4ue indicar0a 4ue ese criterio no se tendr en cuenta a la 'ora de decidir la frecuencia de actualizaciones1 "i ambos .alores .an a cero- las actualizaciones de posicin se recibirn tan pronto y tan frecuentemente como est/n disponibles1 Adems- como ya 'emos indicado- es importante comprender 4ue tanto el tiempo como la distancia especificadas se entendern como simples indicaciones o >pistas? para el pro.eedor- por lo 4ue puede 4ue no se cumplan de forma estricta1 En el pr#imo art0culo intentaremos .er esto con ms detalle para entenderlo me8or1 &or a'ora nos basta con esta informacin1 En cuanto al listener- /ste ser del tipo 3ocation3istener y contendr una serie de m/todos asociados a los distintos e.entos 4ue podemos recibir del pro.eedor:

on3ocation@hangedBlocationE1 Lanzado cada .ez 4ue se recibe una actualizacin de la posicin1 onKroviderJisabledBproviderE1 Lanzado cuando el pro.eedor se des'abilita1 onKrovider8nabledBproviderE1 Lanzado cuando el pro.eedor se 'abilita1 onDtatus@hangedBproviderG statusG extrasE1 Lanzado cada .ez 4ue el pro.eedor cambia su estado- 4ue puede .ariar entre A-5(AF(D8R6C@858<KAR>RC3_(-:>6>C3>;38- >6>C3>;381

&or nuestra parte- tendremos 4ue implementar cada uno de estos m/todos para responder a los e.entos del pro.eedor- sobre todo al ms interesante- on3ocation@hangedBE- 4ue se e8ecutar cada .ez 4ue se recibe una nue.a localizacin desde el pro.eedor1 Veamos un e8emplo de cmo implementar un listener de este tipo:
3ocation3istener loc3istener # new 3ocation3istenerBE ! public void on3ocation@hangedB3ocation locationE ! mostrarKosicionBlocationE; " public void onKroviderJisabledBDtring providerE!

http://www.sgoliver.net/ log/!p"1313 #$gina 141 de 156

Desarrollo en Android
lbl8stado.set5extB0Krovider AFF0E;

"

public void onKrovider8nabledBDtring providerE! lbl8stado.set5extB0Krovider A:0E; " public void onDtatus@hangedBDtring providerG int statusG ;undle extrasE ! "; " lbl8stado.set5extB0Krovider Dtatus4 0 9 statusE;

Como pod/is .er- en nuestro caso de e8emplo nos limitamos a mostrar al usuario la informacin recibida en el e.ento- bien sea un simple cambio de estado- o una nue.a posicin- en cuyo caso llamamos al m/todo au#iliar mostrarKosicionBE para refrescar todos los datos de la posicin en la pantalla1 &ara este e8emplo 'emos construido una interfaz muy sencilla- donde se muestran 6 datos de la posicin (latitud- lon%itud y precisin) y un campo para mostrar el estado del pro.eedor1 Adems- se incluyen dos botones para comenzar y detener la recepcin de nue.as actualizaciones de la posicin1 3o incluyo a4u0 el cdi%o de la interfaz para no alar%ar ms el art0culo- pero puede consultarse en el cdi%o fuente suministrado al final del te#to1 El aspecto de nuestra .entana es el si%uiente:

En el m/todo mostrar&osicion() nos .amos a limitar a mostrar los distintos datos de la posicin pasada como parmetro en los controles correspondientes de la interfaz- utilizando para ello los m/todos proporcionados por la clase Location1 En nuestro caso utilizaremos %etLatitude()%etAltitude() y %etAccuracy() para obtener la latitud- lon%itud y precisin respecti.amente1 &or supuesto- 'ay otros m/todos disponibles en esta clase para obtener la altura- orientacin.elocidad- etcG 4ue se pueden consultar en la documentacin oficial de la clase Location1
*ea'os el (.digo: http://www.sgoliver.net/ log/!p"1313 #$gina 142 de 156

Desarrollo en Android
private void mostrarKosicionB3ocation locE ! i Bloc P# nullE ! lbl3atitud.set5extB03atitud4 0 9 Dtring.valueA Bloc.get3atitudeBEEE; lbl3ongitud.set5extB03ongitud4 0 9 Dtring.valueA Bloc.get3ongitudeBEEE; lblKrecision.set5extB0Krecision4 0 9 Dtring.valueA Bloc.get>ccuracyBEEE; " else ! lbl3atitud.set5extB03atitud4 Bsin(datosE0E; lbl3ongitud.set5extB03ongitud4 Bsin(datosE0E; lblKrecision.set5extB0Krecision4 Bsin(datosE0E; " "

K&or 4u/ comprobamos si la localizacin recibida es nullL Como ya 'emos dic'o anteriomenteno tenemos muc'o control sobre el momento ni la frecuencia con la 4ue .amos a recibir las actualizaciones de posicin desde un pro.eedor- por lo 4ue tampoco estamos se%uros de tenerlas disponibles desde un primer momento1 &or este moti.o- una t/cnica bastante com!n es utilizar la posicin 4ue de.uel.e el m/todo get3astYnown3ocationBE como posicin >pro.isional? de partida y a partir de a'0 esperar a recibir la primera actualizacin a tra./s del 3ocation3istener1 2 como tambi/n di8imos- la !ltima posicin conocida podr0a no e#istir en el dispositi.o- de a'0 4ue comprobemos si el .alor recibido es null1 &ara entender me8or esto- a continuacin ten/is la estructura completa del m/todo 4ue lanzamos al comenzar la recepcin de actualizaciones de posicin (al pulsar el botn >Acti.ar? de la interfaz):
private void comenNar3ocaliNacionBE ! //Abtenemos una re erencia al 3ocation<anager loc<anager # B3ocation<anagerEgetDystemDerviceB@ontext.3A@>5CA:(D8R6C@8E; //Abtenemos la [ltima posiciTn conocida 3ocation loc # loc<anager.get3astYnown3ocationB3ocation<anager.HKD(KRA6CJ8RE ; //<ostramos la [ltima posiciTn conocida mostrarKosicionBlocE; //:os registramos para recibir actualiNaciones de la posiciTn loc3istener # new 3ocation3istenerBE ! public void on3ocation@hangedB3ocation locationE ! mostrarKosicionBlocationE; " //Resto de mZtodos del listener //... ";

http://www.sgoliver.net/ log/!p"1313 #$gina 143 de 156

Desarrollo en Android
loc<anager.re+uest3ocation-pdatesB 3ocation<anager.HKD(KRA6CJ8RG '$$$$G $G loc3istenerE; "

Como se puede obser.ar- al comenzar la recepcin de posiciones- mostramos en primer lu%ar la !ltima posicin conocida- y posteriormente solicitamos al =&" actualizaciones de poscin cada 6R se%undos1 &or !ltimo- nos 4uedar0a !nicamente comentar cmo podemos detener la recepcin de nue.as actualizaciones de posicin1 Al%o 4ue es tan sencillo como llamar al m/todo remove-pdatesBE del location manager1 De esta forma- la implementacin del botn >Desacti.ar? ser0a tan sencilla como esto:
btnJesactivar.setAn@lick3istenerBnew An@lick3istenerBE ! 7Averride public void on@lickB6iew vE ! loc<anager.remove-pdatesBloc3istenerE; " "E;

Con esto 'abr0amos concluido nuestra aplicacin de e8emplo1 "in embar%o- si descar%is el cdi%o completo del art0culo y e8ecutis la aplicacin en el emulador .er/is 4ue- a pesar funcionar todo correctamente- slo recibir/is una lectura de la posicin (incluso puede 4ue nin%una)1 Esto es debido a 4ue la e8ecucin y prueba de aplicaciones de este tipo en el emulador de Android- al no tratarse de un dispositi.o real y no estar disponible un receptor =&"- re4uiere de una serie de pasos adicionales para sim$lar cambios en la posicin del dispositi.o1 (odo esto- adems de al%unas aclaraciones 4ue nos 'an 4uedado pendientes en esta primera entre%a sobre localizacin- lo .eremos en el pr#imo art0culo1 &or a'ora os de8o el cdi%o fuente completo para 4ue podis 'acer .uestras propias pruebas1

http://www.sgoliver.net/ log/!p"1313 #$gina 144 de 156

Desarrollo en Android

Localizacin geogr"fica en Android <II=


s%oli.er .iles- &ro%ramacin BRCCAR7ARe En el art0culo anterior del curso de pro%ramacin en Android comentamos los pasos bsicos necesarios para construir aplicaciones 4ue accedan a la posicin %eo%rfica del dispositi.o1 2a comentamos al%unas particularidades de este ser.icio de la A&I de Android- pero de8amos en el tintero al%unas aclaraciones ms detalladas y un tema importante y fundamental- como es la depuracin de este tipo de aplicaciones 4ue mane8an datos de localizacin1 En este nue.o art0culo intentar/ abarcar estos temas y de8ar/ para un tercer art0culo al%unas otras caracter0sticas ms a.anzadas de los ser.icios de localizacin1 Como base para este art0culo .oy a utilizar la misma aplicacin de e8emplo 4ue construimos en la anterior entre%a- 'aciendo tan slo unas pe4ueDas modificaciones:

:educiremos el tiempo entre actualizaciones de posicin a la mitad- C7 se%undos- para e.itar tiempos de espera demasiado lar%os durante la e8ecucin de la aplicacin1 =eneraremos al%unos mensa8es de lo% en puntos cla.e del cdi%o para poder estudiar con ms detalle el comportamiento de la aplicacin en tiempo de e8ecucin1

http://www.sgoliver.net/ log/!p"1313 #$gina 145 de 156

Desarrollo en Android

La %eneracin de mensa8es de lo% resulta ser una 'erramienta perfecta a la 'ora de depurar aplicaciones del tipo 4ue estamos tratando- ya 4ue en estos casos el cdi%o no facilita demasiado la depuracin t0pica paso a paso 4ue podemos realizar en otras aplicaciones1 En nuestro caso de e8emplo slo .amos a %enerar mensa8es de lo% cuando ocurran dos ciscunstancias:

Cuando el pro.eedor de localizacin cambie de estado- e.ento onDtatus@hangedBEmostraremos el nue.o estado1 Cuando se reciba una nue.a actualizacin de la posicin- e.ento on3ocation@hangedBE- mostraremos las nue.as coordenadas recibidas1

3uestro cdi%o 4uedar0a por tanto tal como si%ue:


private void actualiNarKosicionBE ! //Abtenemos una re erencia al 3ocation<anager location<anager # B3ocation<anagerEgetDystemDerviceB@ontext.3A@>5CA:(D8R6C@8E; //Abtenemos la [ltima posiciTn conocida 3ocation location # location<anager.get3astYnown3ocationB3ocation<anager.HKD(KRA6CJ8RE; //<ostramos la [ltima posiciTn conocida muestraKosicionBlocationE; //:os registramos para recibir actualiNaciones de la posiciTn location3istener # new 3ocation3istenerBE ! public void on3ocation@hangedB3ocation locationE ! muestraKosicionBlocationE; " public void onKroviderJisabledBDtring providerE! lbl8stado.set5extB0Krovider AFF0E; "

http://www.sgoliver.net/ log/!p"1313 #$gina 146 de 156

Desarrollo en Android
public void onKrovider8nabledBDtring providerE! lbl8stado.set5extB0Krovider A:0E; " public void onDtatus@hangedBDtring providerG int statusG ;undle extrasE ! " "; location<anager.re+uest3ocation-pdatesB 3ocation<anager.HKD(KRA6CJ8RG *W$$$G $G location3istenerE; 3og.iB03oc>ndroid0G 0Krovider Dtatus4 0 9 statusE; lbl8stado.set5extB0Krovider Dtatus4 0 9 statusE;

"

private void muestraKosicionB3ocation locE ! i Bloc P# nullE ! lbl3atitud.set5extB03atitud4 0 9 Dtring.valueA Bloc.get3atitudeBEEE; lbl3ongitud.set5extB03ongitud4 0 9 Dtring.valueA Bloc.get3ongitudeBEEE; lblKrecision.set5extB0Krecision4 0 9 Dtring.valueA Bloc.get>ccuracyBEEE; 3og.iB03oc>ndroid0G Dtring.valueA B loc.get3atitudeBE 9 0 - 0 9 Dtring.valueA Bloc.get3ongitudeBEEEE; " else ! lbl3atitud.set5extB03atitud4 Bsin(datosE0E; lbl3ongitud.set5extB03ongitud4 Bsin(datosE0E; lblKrecision.set5extB0Krecision4 Bsin(datosE0E; " "

"i e8ecutamos en este momento la aplicacin en el emulador y pulsamos el botn Activar .eremos cmo los cuadros de te#to se rellenan con la informacin de la !ltima posicin conocida (si e#iste)- pero sin embar%o estos datos no cambiarn en nin%!n momento ya 4ue por el momento el emulador de Android tan slo cuenta con esa informacin1 KCmo podemos simular la actualizacin de la posicin del dispositi.o para .er si nuestra aplicacin responde e#actamente como esperamosL &ues bien- para 'acer esto tenemos .arias opciones1 La primera de ellas- y la ms sencilla- es el en.0o manual de una nue.a posicin al emulador de Android- para simular 4ue /ste 'ubiera cambiado su localizacin1 Esto se puede realizar desde la perspecti.a de DD "- en la pestaDa Em$lator (ontrol- donde podemos encontrar una seccin llamada /ocation (ontrols- mostrada en la ima%en si%uiente (clicO para ampliar):

http://www.sgoliver.net/ log/!p"1313 #$gina 147 de 156

Desarrollo en Android

Con estos controles podemos en.iar de forma manual al emulador en e8ecucin unas nue.as coordenadas de posicin- para simular 4ue /stas se 'ubieran recibido a tra./s del pro.eedor de localizacin utilizado1 De esta forma- si introducimos unas coordenadas de lon%itud y latitud y pulsamos el botn Send mientras nuestra aplicacin se e8ecuta en el emulador- esto pro.ocar la e8ecucin del e.ento on3ocation@hangedBE y por consi%uiente se mostrarn estos mismos datos en sus controles correspondientes de la interfaz- como .emos en la si%uiente captura de pantalla:

&or supuesto- si 'acemos nue.os en.0os de coordenadas desde Eclipse .eremos cmo /sta se .a actualizando en nuestra aplicacin sin nin%!n tipo de problamas1 "in embar%o este m/todo de
http://www.sgoliver.net/ log/!p"1313 #$gina 148 de 156

Desarrollo en Android

manual no resulta demasiado adecuado ni cmodo para probar toda la funcionalidad de nuestra aplicacin- por e8emplo la actualizacin de posicin cada C7 se%undos1 &or ello- Android proporciona otro m/todo al%o menos manual de simular cambios frecuentes de posicin para probar nuestras aplicaciones1 Este m/todo consiste en proporcionar- en .ez de una sla coordenada cada .ez- una lista de coordenadas 4ue se iran en.iando automticamente al emulador una tras otra a una determinada .elocidad- de forma 4ue podamos simular 4ue el dispositi.o se mue.e constantemente y 4ue nuestra aplicacin responde de forma correcta y en el momento adecuado a esos cambios de posicin1 2 esta lista de coordenadas se puede proporcionar de dos formas distintas- en formato =&) o como fic'ero ; L1 Ambos tipos de fic'ero son ampliamente utilizados por aplicaciones y dispositi.os de localizacin- como =&"aplicaciones de carto%raf0a y mapas- etc1 Los fic'eros ; L podemos %enerarlos por e8emplo a tra./s de la aplicacin =oo%le Eart' o manualmente con cual4uier editor de te#to- pero recomiendo consultar los dos enlaces anteriores para obtener ms informacin sobre cada formato1 &ara este e8emplo- yo 'e %enerado un fic'ero ; L de muestra con una lista de CRRR posiciones %eo%rficas al azar1

&ara utilizar este fic'ero como fuente de datos para simular cambios en la posicin del dispositi.o- accedemos nue.amente a los Location Controls y pulsamos sobre la pestaDa =&) o ; L- se%!n el formato 4ue 'ayamos ele%ido- 4ue en nuestro caso ser ; L1 &ulsamos el botn >/oad KM/? para seleccionar nuestro fic'ero y .eremos la lista de coordenadas como en la si%uiente ima%en:

http://www.sgoliver.net/ log/!p"1313 #$gina 149 de 156

Desarrollo en Android

<na .ez car%ado el fic'ero- tendremos disponibles los cuatro botones inferiores para (de iz4uierda a derec'a):

A.anzar automticamente por la lista1 Ir a la posicin anterior de la lista de forma manual1 Ir a la posicin si%uiente de la lista de forma manual1 Establecer la .elocidad de a.ance automtico1

Entendido esto- .amos a utilizar la lista de posiciones para probar nuestra aplicacin1 &ara elloe8ecutamos la aplicacin en el emulador- pulsamos nuestro botn >Activar? para comenzar a detectar cambios de posicin- y pulsamos el botn de a.ance automtico (botn .erde) 4ue acabamos de comentar1 "i obser.amos rpidamente la pantalla de nuestra aplicacin .eremos cmo se actualizan .arias .eces los .alores de latitud y lon%itud actuales1 KCmo es posibleL K3o 'ab0amos confi%urado el 3ocation3istener para obtener actualizaciones de posicin cada C7 se%undosL Antes de contestar a esto- de8emos 4ue la aplicacin se e8ecute durante un minuto ms1 (ras unos 9R se%undos de e8ecucin detenemos la captura de posiciones pulsando nuestro botn >Desactivar>1

A'ora .ayamos a la .entana de lo% del DD " y .eamos los mensa8es de lo% 'a %enerado nuestra aplicacin para intentar saber 4u/ 'a ocurrido1 En mi caso- los mensa8es %enerados son los si%uientes (en tu caso deben ser muy parecidos):
$W-$1 *$4W$4'%.Q&*4 C:FA/3oc>ndroidB&W*E4 %.$ - -**.QQQQQ1'''''''') $W-$1 *$4W$4'1.$)*4 C:FA/3oc>ndroidB&W*E4 Krovider Dtatus4 & $W-$1 *$4W$4'1.Q$*4 C:FA/3oc>ndroidB&W*E4 %.$$$$$*aaaaaaaaa -

http://www.sgoliver.net/ log/!p"1313 #$gina 150 de 156

Desarrollo en Android
-**.QQQQQaaaaaaaaa1 $W-$1 *$4W$4'Q.Q)*4 -**.QQQQQaaaaaaaaa1 $W-$1 *$4W$4)*.$**4 -**.QQQQQW$$$$$$$$& $W-$1 *$4W$4)'.$**4 -**.QQQQQ''''''''') $W-$1 *$4W$4)W.$$*4 -**.QQQQQ*aaaaaaaaW $W-$1 *$4W$4)a.$a*4 -**.QQQQ1QQQQQQQQQQ $W-$1 *$4W$4)%.*'*4 -**.QQQQ1QQQQQQQQQQ $W-$1 *$4W$4)%.*1&4 $W-$1 *$4W*4$&.&'&4 $W-$1 *$4W*4$&.1*&4 -**.QQQQ%'''''''''' $W-$1 *$4W*4$&.1%&4 $W-$1 *$4W*4$'.1%&4 -**.QQQQ%'''''''''' $W-$1 *$4W*4$).Q*&4 -**.QQQQ%*aaaaaaaaW $W-$1 *$4W*4$W.Q&&4 -**.QQQQ%*aaaaaaaaW $W-$1 *$4W*4$a.Q1&4 $W-$1 *$4W*4$1.$'&4 -**.QQQQa1''''''''' $W-$1 *$4W*4$Q.$a&4 $W-$1 *$4W*4*$.*'&4 -**.QQQQaaaaaaaaaa% $W-$1 *$4W*4*&.&)&4 -**.QQQQaW$$$$$$$$* $W-$1 *$4W*4*'.&Q&4 -**.QQQQa'''''''''W $W-$1 *$4W*4*'.')&4 $W-$1 *$4W*4&1.'%&4 -**.QQQQW$$$$$$$$$& $W-$1 *$4W*4&1.Q1&4 -**.QQQQW$$$$$$$$$& $W-$1 *$4W*4&Q.$'&4 $W-$1 *$4W*4'$.$$&4 -**.QQQQ)1'''''''') $W-$1 *$4W*4'*.$$&4 -**.QQQQ)aaaaaaaaaW $W-$1 *$4W*4''.***4 -**.QQQQ))QQQQQQQQQ $W-$1 *$4W*4').*W*4 -**.QQQQ))QQQQQQQQQ $W-$1 *$4W*4'W.&$*4 $W-$1 *$4W*4'a.&W*4 -**.QQQQ)*aaaaaaaa% $W-$1 *$4W*4'%.'**4 -**.QQQQ)*aaaaaaaa% $W-$1 *$4W*4'1.'a*4 $W-$1 *$4W*4'1.)'*4

C:FA/3oc>ndroidB&W*E4 %.$$$$$*aaaaaaaaa C:FA/3oc>ndroidB&W*E4 %.$$$$$'''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$$W$$$$$$$$* C:FA/3oc>ndroidB&W*E4 %.$$$$$aaaaaaaaa% C:FA/3oc>ndroidB&W*E4 %.$$$$$1''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$$1''''''''' C:FA/3oc>ndroidB&W*E4 Krovider Dtatus4 * C:FA/3oc>ndroidB&W*E4 %.$$$$&'''''''''' - -**.QQQQ%W C:FA/3oc>ndroidB&W*E4 %.$$$$&'''''''''' C:FA/3oc>ndroidB&W*E4 Krovider Dtatus4 & C:FA/3oc>ndroidB&W*E4 %.$$$$&)QQQQQQQQQ C:FA/3oc>ndroidB&W*E4 %.$$$$&aaaaaaaaa1 C:FA/3oc>ndroidB&W*E4 %.$$$$&aaaaaaaaa1 C:FA/3oc>ndroidB&W*E4 %.$$$$&1'''''''') - -**.QQQQ% C:FA/3oc>ndroidB&W*E4 %.$$$$&1'''''''') C:FA/3oc>ndroidB&W*E4 %.$$$$' - -**.QQQQa1''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$'*aaaaaaaa% C:FA/3oc>ndroidB&W*E4 %.$$$$''''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$''''''''''' C:FA/3oc>ndroidB&W*E4 Krovider Dtatus4 * C:FA/3oc>ndroidB&W*E4 %.$$$$)1''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$)1''''''''' C:FA/3oc>ndroidB&W*E4 Krovider Dtatus4 & C:FA/3oc>ndroidB&W*E4 %.$$$$W$$$$$$$$$* C:FA/3oc>ndroidB&W*E4 %.$$$$W*aaaaaaaa% C:FA/3oc>ndroidB&W*E4 %.$$$$W'''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$W'''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$WW - -**.QQQQ)'''''''''' C:FA/3oc>ndroidB&W*E4 %.$$$$Waaaaaaaaa%W C:FA/3oc>ndroidB&W*E4 %.$$$$Waaaaaaaaa%W C:FA/3oc>ndroidB&W*E4 %.$$$$W1'''''''''W - -**.QQQQ) C:FA/3oc>ndroidB&W*E4 Krovider Dtatus4 *

http://www.sgoliver.net/ log/!p"1313 #$gina 151 de 156

Desarrollo en Android

Estudiemos un poco este lo%1 "i obser.amos las marcas de fec'a 'ora .emos .arias cosas:

<n primer %rupo de actualizaciones entre las CR:7R:6^ y las CR:7R:[^- con e lecturas1 <n se%undo %rupo de actualizaciones entre las CR:7C:RB y las CR:7C:C6- con CC lecturas1 <n tercer %rupo de actualizaciones entre las CR:7C:Be y las CR:7C:6e- con CR lecturas1 Entre cada %rupo de lecturas transcurren apro#imadamente C7 se%undos1 Los %rupos estn formados por un n!mero .ariable de lecturas1

&or tanto ya podemos sacar al%unas conclusiones1 Indicar al location listener una frecuencia de C7 se%undos entre actualizaciones no 4uiere decir 4ue .ayamos a tener una sola lectura cada C7 se%undos- sino 4ue al menos tendremos una nue.a con dic'a frecuencia1 "in embar%o- como podemos comprobar en los lo%s- las lecturas se recibirn por %rupos separados entre s0 por el inter.alo de tiempo indicado1 s conclusiones- a'ora sobre el estado del pro.eedor de localizacin1 "i buscamos en el lo% los momentos donde cambia el estado del pro.eedor .emos dos cosas importantes:

Despu/s de recibir cada %rupo de lecturas el pro.eedor pasa a estado C (58<KAR>RC3_(-:>6>C3>;38)1 (ras empezar a recibir de nue.o lecturas el pro.eedor pasa a estado B (>6>C3>;38)1

Estos cambios en el estado de los pro.eedores de localizacin pueden ayudarnos a realizar di.ersas tareas1 <n e8emplo t0pico es utilizar el cambio de estado a C (es decir- cuando se 'a terminado de recibir un %rupo de lecturas) para seleccionar la lectura ms precisa del %rupo recibido- al%o especialmente importante cuando se estn utilizando .arios pro.eedores de localizacin simultneamente- cada uno con una precisin distinta1 A modo de resumen- en este art0culo 'emos .isto cmo podemos utilizar las distintas 'erramientas 4ue proporciona la plataforma Android y el entorno de desarrollo Eclipse para simular cambios de posicin del dispositi.o durante la e8ecucin de nuestras aplicaciones en el emulador1 (ambi/ 'emos .isto cmo la %eneracin de mensa8es de lo% pueden ayudarnos a depurar este tipo de aplicaciones- y finalmente 'emos utilizado esta 'erramienta de depuracin para entender me8or el funcionamiento de los location listener y el comportamiento de los pro.eedores de localizacin1

!epuracin en Android: Logging


Facemos un pe4ueDo alto en el camino en el Curso de &ro%ramacin Android para 'ablar de un tema 4ue- si bien no es espec0fico de Android- s0 nos .a a resultar bastante !til a la 'ora de e#plorar otras caracter0sticas de la plataforma1
http://www.sgoliver.net/ log/!p"1313 #$gina 152 de 156

Desarrollo en Android

<na de las t/cnicas ms !tiles a la 'ora de depurar y@o realizar el se%uimiento de aplicaciones sobre cual4uier plataforma es la creacin de logs de e8ecucin1 Android por supuesto no se 4ueda atrs y nos proporciona tambi/n su propio ser.icio y A&I de logging a tra./s de la clase android.util.3og1 En Android- todos los mensa8es de lo% lle.arn asociada la si%uiente informacin:

Pec'a@Fora del mensa8e1 Criticidad1 3i.el de %ra.edad del mensa8e (se detalla ms adelante)1 &ID1 Cdi%o interno del proceso 4ue 'a introducido el mensa8e1 (a%1 Eti4ueta identificati.a del mensa8e (se detalla ms adelante)1 ensa8e1 El te#to completo del mensa8e1

De forma similar a como ocurre con otros frameEorOs de lo%%in%- en Android los mensa8es de lo% se .an a clasificar por su criticidad- e#istiendo as0 .arias cate%orias (ordenadas de mayor a menor criticidad): C1 B1 61 [1 71 Error $arnin% Info Debu% Verbose

&ara cada uno de estos tipos de mensa8e e#iste un m/todo esttico independiente 4ue permite aDadirlo al lo% de la aplicacin1 As0- para cada una de las cate%or0as anteriores tenemos disponibles los m/todos eBE- wBE- iBE- dBE y vBE respecti.amente1 Cada uno de estos m/todos recibe como parmetros la eti4ueta (tag) y el te#to en s0 del mensa8e1 Como eti4ueta de los mensa8es- aun4ue es un campo al 4ue podemos pasar cual4uier .alor- suele utilizarse el nombre de la aplicacin o de la acti.idad concreta 4ue %enera el mensa8e1 Esto nos permitir ms tarde crear filtros personalizados para identificar y poder .isualizar !nicamente los mensa8es de lo% 4ue nos interesan- entre todos los %enerados por Android H4ue son muc'osI durante la e8ecucin de la aplicacin1

Fa%amos un minipro%rama de e8emplo para .er cmo fuenciona esto1 El pro%rama ser tan simple como aDadir .arios mensa8es de lo% dentro del mismo onCreate de la acti.idad principal y .er 4u/ ocurre1 6s ')estro el (.digo (o'pleto:
public class 3ogs>ndroid extends >ctivity ! private static inal Dtring 3AH5>H # 03ogs>ndroid0;

http://www.sgoliver.net/ log/!p"1313 #$gina 153 de 156

Desarrollo en Android

7Averride public void on@reateB;undle savedCnstanceDtateE ! super.on@reateBsavedCnstanceDtateE; set@ontent6iewBR.layout.mainE; 3og.eB3AH5>HG 3og.wB3AH5>HG 3og.iB3AH5>HG 3og.dB3AH5>HG 3og.vB3AH5>HG 0<ensaje 0<ensaje 0<ensaje 0<ensaje 0<ensaje de de de de de error0E; warning0E; in ormaciTn0E; depuraciTn0E; verbose0E;

" "

"i e8ecutamos la aplicacin anterior en el emulador .eremos cmo se abre la pantalla principal 4ue crea Eclipse por defecto y aparentemente no ocurre nada ms1 KDnde podemos .er los mensa8es 4ue 'emos aDadido al lo%L &ues para .er los mensa8es de lo% nos tenemos 4ue ir a la perspecti.a de Eclipse llamada DDMS1 <na .ez en esta perspecti.a- podemos acceder a los mensa8es de lo% en la parte inferior de la pantalla- en una .ista llamada /og(at1 En esta .entana se muestran todos los mensa8es de lo% 4ue %enera Android durante la e8ecucin de la aplicacin4ue son muc'os- pero si buscamos un poco en la lista encontraremos los %enerados por nuestra aplicacin- tal como se muestra en la si%uiente ima%en (clicO para ampliar):

Como se puede obser.ar- para cada mensa8e se muestra toda la informacin 4ue indicamos al principio del art0culo- adems de estar diferenciados por un color distinto se%!n su criticidad1 En este caso de e8emplo- los mensa8es mostrados son pocos y fciles de localizar en el lo%- pero para una aplicacin real- el n!mero de estos mensa8es puede ser muc'o mayor y aparecer intercalados caticamente entre los dems mensa8es de Android1 &ara estos casos- la .entada de Lo%Cat ofrece una serie de funcionalidades para facilitar la .isualizacin y b!s4ueda de determinados mensa8es1

&or e8emplo- podemos restrin%ir la lista para 4ue slo muestre mensa8es con una determinada criticidad m0nima1 Esto se consi%ue pulsando al%uno de los 7 primeros botones 4ue se obser.an en la parte superior derec'a de la .entana de lo%1 As0- si por e8emplo pulsamos sobre el botn de la cate%or0a Info (en .erde)- en la lista slo se mostrarn los mensa8es con criticidad ErrorWarning e Info1

http://www.sgoliver.net/ log/!p"1313 #$gina 154 de 156

Desarrollo en Android

*tro m/todo de filtrado ms interesante es la definicin de filtros personalizados (botn >N? .erde)- donde podemos filtrar la lista para mostrar !nicamente los mensa8es con un &ID o (a% determinado1 "i 'emos utilizado como eti4ueta de los mensa8es el nombre de nuestra aplicacin o de nuestras acti.idades esto nos proporcionar una forma sencilla de .isualizar slo los mensa8es %enerados por nuestra aplicacin1 As0- para nuestro e8emplo- podr0amos crear un filtro indicando como (a% la cadena >Lo%sAndroid?- tal como se muestra en la si%uiente ima%en:

Esto crear una nue.a .entana de lo% con el nombre 4ue 'ayamos especificado en el filtro- donde slo aparecern nuestros 7 mensa8es de lo% de e8emplo (clicO para ampliar):

&or !ltimo- cabe mencionar 4ue e#iste una .ariante de cada uno de los m/todos de la clase Lo% 4ue recibe un parmetro ms en el 4ue podemos pasar un ob8eto de tipo e#cepcin1 Con esto conse%uimos 4ue- adems del mensa8e de lo% indicado- se muestre tambi/n la traza de error %enerada con la e#cepcin1

Veamos esto con un e8emplo- y para ello .amos a forzar un error de di.isin por cero- .amos a capturar la e#cepcin y .amos a %enerar un mensa8e de lo% con la .ariante indicada:
try !

int a # */$; " catchB8xception exE

http://www.sgoliver.net/ log/!p"1313 #$gina 155 de 156

Desarrollo en Android
! exE; "

3og.eB3AH5>HG 0JivisiTn por ceroP0G

"i .ol.emos a e8ecutar la aplicacin y .emos el lo% %enerado- podermos comprobar cmo se muestra la traza de error corespondiente %enerada con la e#cepcin (clicO para ampliar)1

En definiti.a- podemos comprobar como la %eneracin de mensa8es de lo% puede ser una 'erramienta sencilla pero muy efecti.a a la 'ora de depurar aplicaciones 4ue no se a8ustan muc'o a la depuracin paso a paso- o simplemente para %enerar trazas de e8ecucin de nuestras aplicaciones para comprobar de una forma sencilla cmo se comportan1

http://www.sgoliver.net/ log/!p"1313 #$gina 156 de 156

También podría gustarte