Anda di halaman 1dari 276

2014

Manual Inicio Android


Pasos bsicos para crear una aplicacin
Android con ejemplos.


El presente d ocumento trata de introducir al alumno al desarrollo de aplicaciones
Android, guindolo en el desarrollo de una aplicacin con varios ejemplos bsicos
que abarca en gran medida los conceptos bsicos en el desarrollo de aplicaciones
Android utilizando el ADT (Android Developer Tools) de Eclipse.

NELSON CROZBY PADILLA ALVAREZ


UTM
12/02/2014

Tabla de contenido
Qu es Android? .................................................................................................................................. 8
El sistema operativo Android ....................................................................................................................... 8
Task (tarea) .................................................................................................................................................. 8
Componentes de la plataforma Android ...................................................................................................... 8
Google Play .................................................................................................................................................. 9
Android Development Tools .......................................................................................................... 10
Android SDK ............................................................................................................................................... 10
Android debug bridge (adb) ....................................................................................................................... 10
Android Developer Tools y Android Studio ................................................................................................ 10
Dalvik Virtual Machine ............................................................................................................................... 11
Android Runtime ........................................................................................................................................ 11
Como desarrollar aplicaciones Android ..................................................................................................... 11
Proceso de conversin desde cdigo fuente hasta una aplicacin Android .............................................. 11
Seguridad y permisos ....................................................................................................................... 12
Concepto de seguridad en Android ........................................................................................................... 12
Concepto de permiso en Android .............................................................................................................. 12
Instalacin ........................................................................................................................................... 13
Consideraciones previas y de instalacin ................................................................................................... 13
Preparar IDE ............................................................................................................................................... 14
Emulador de dispositivo Android y Dispositivo Virtual Android (Android Virtual
Devices, AVD) ...................................................................................................................................... 16
Emulador Android y Android Virtual Device .............................................................................................. 16
Atajos para el emulador de dispositivos Android ...................................................................................... 17
Google vs. Android AVD ............................................................................................................................. 18
Optimizacin de Velocidad ........................................................................................................................ 18
Emulador Intel ............................................................................................................................................ 19
Emulador Alternativo ................................................................................................................................. 20
Ejercicio: Crear e iniciar Android Virtual Device ................................................................... 20
Target (objetivo) ........................................................................................................................................ 20
Crear el AVD ............................................................................................................................................... 20
Iniciar tu AVD ............................................................................................................................................. 22
Ejercicio: Crear aplicacin Android en Eclipse ....................................................................... 23
Asistente de proyectos Android ................................................................................................................. 23
Crear proyecto Android ............................................................................................................................. 23
Ejercicio: Inicie la aplicacin Android generada .................................................................... 28
Iniciar AVD .................................................................................................................................................. 28
Inicicar la aplicacin ................................................................................................................................... 29

Integracin de ADT dentro de Eclipse ........................................................................................ 31


Integracin de Android dentro de la perspectiva Java ............................................................................... 31
Asistentes de Android ................................................................................................................................ 31
Perspectiva DDMS ............................................................................................................................. 31
Perspectiva Android ................................................................................................................................... 32
File Explorer ............................................................................................................................................... 32
Partes de una aplicacin Android ................................................................................................ 32
Aplicacin Android ..................................................................................................................................... 32
Componentes de software Android ........................................................................................................... 33
Contexto ..................................................................................................................................................... 33
Vistazo a los componentes de una aplicacin Android ........................................................ 33
Activity (Actividad) ..................................................................................................................................... 33
BroadcastReceiver ..................................................................................................................................... 33
Service (Servicio) ........................................................................................................................................ 34
ContentProvider ......................................................................................................................................... 34
Componentes base en las interfaces de usuario en Android .............................................. 34
Acitivity (Actividad) .................................................................................................................................... 34
Fragments (Fragmentos) ............................................................................................................................ 34
Views y control de distribucin .................................................................................................................. 35
Diseos especficos de configuracin de dispositivos ................................................................................ 36
Otros elementos importantes de Android ................................................................................ 36
Pantalla principal y la pantalla de bloqueo de widgets .............................................................................. 36
Live Wallpapers .......................................................................................................................................... 36
El Android Manifest .......................................................................................................................... 36
La configuracin de la aplicacin para Android ......................................................................................... 36
Declarar los componentes en el archivo de manifiesto ............................................................................. 36
Permisos ..................................................................................................................................................... 37
Ejemplo del archivo AndroidManifes.xml .................................................................................................. 37
El manifiesto de Android ................................................................................................................ 38
Versin y paquete ...................................................................................................................................... 38
Aplicacin y componentes ......................................................................................................................... 38
Minimun y target SDK ................................................................................................................................ 38
Permisos ..................................................................................................................................................... 39
Configuraciones requeridas del dispositivo ............................................................................................... 39
Localizacin de instalacin ......................................................................................................................... 39
Ms informacin ........................................................................................................................................ 40
Recursos ............................................................................................................................................... 40
Archivos de recursos .................................................................................................................................. 40

Ejemplo de recurso .................................................................................................................................... 41


Calificadores de recursos ........................................................................................................................... 41
Ids de recursos y R.java .............................................................................................................................. 41
Buenas practicas para los Ids de los recursos ............................................................................................ 42
Recursos del sistema .................................................................................................................................. 42

Views (vistas) ...................................................................................................................................... 42


Clase View .................................................................................................................................................. 42
Views estndar de Android ........................................................................................................................ 42
Views personalizadas ................................................................................................................................. 42
Archivos de recursos layouts ........................................................................................................ 43
Actividades y layouts .................................................................................................................................. 43
Archivos layout XML ................................................................................................................................... 43
Definiendo Ids ............................................................................................................................................ 44
Buena prctica: predefinir los IDs a travs de un archivo separado. ......................................................... 44
Consideraciones de desempeo con layouts ............................................................................................. 45
Ejercicio: Usar layout y agregar interaccin ............................................................................ 45
Cambiar layout ........................................................................................................................................... 45
Agregando botn interactivo ..................................................................................................................... 45
Validando interaccin del botn ................................................................................................................ 46
Desplegar texto desde el campo EditText .................................................................................................. 46
Validar mensaje emergente ....................................................................................................................... 47
Ejercicio: Influir en la vista del layout en tiempo de ejecucin ......................................... 47
Agregar radio group y radio buttons al layout ........................................................................................... 47
Cambiar la orientacin del radio group dinamcamente ........................................................................... 49
Validar ........................................................................................................................................................ 50
Usando Resources ............................................................................................................................. 50
Referencias a recursos en cdigo ............................................................................................................... 50
Accediendo views desde el layout en una actividad .................................................................................. 50
Referencia a recursos en archivos XML ...................................................................................................... 51
Referencia a recursos del sistema Android en archivos XML ..................................................................... 51
Assets ..................................................................................................................................................... 51
Qu son los assets? .................................................................................................................................. 51
Accesando assets ....................................................................................................................................... 52
Ejercicio: Usando recursos en archivos XML y en cdigo .................................................... 52
Agregando imgenes y views a su proyecto .............................................................................................. 52
Asignando la imagen a un view imagen. .................................................................................................... 53
Agregar imgenes al proyecto ................................................................................................................... 53
Validar ........................................................................................................................................................ 53

Ejercicio: Crear un convertidor de temperatura. ................................................................... 53


Crear proyecto ........................................................................................................................................... 53
Crear atributos ........................................................................................................................................... 55
Usando el editor de layouts ....................................................................................................................... 56
Agregar views al archivo layout ................................................................................................................. 57
Editar propiedades de las views ................................................................................................................. 60
Crear clase utilitaria ................................................................................................................................... 63
Cambiar el cdigo de la activity ................................................................................................................. 63
Iniciar aplicacin ........................................................................................................................................ 65
Manejador de Layouts y ViewGroups ......................................................................................... 65
Qu es un manejador de layouts? ............................................................................................................ 65
Importantes manejadores de layout. ......................................................................................................... 65
Atributos del layout ................................................................................................................................... 66
FrameLayout .............................................................................................................................................. 67
LinearLayout ............................................................................................................................................... 67
RelativeLayout ............................................................................................................................................ 68
GridLayout .................................................................................................................................................. 69
ScrollView ................................................................................................................................................... 71
Ejercicio: Usando ScrollView ......................................................................................................... 71
Desplegar ............................................................................................................................................. 73
Revisin general ......................................................................................................................................... 73
Despliegue va ADT ..................................................................................................................................... 74
Exportar aplicaciones ................................................................................................................................. 75
Va fuentes externas .................................................................................................................................. 75
Google Play (Market) ................................................................................................................................. 75
Ciclo de vida de una Activity .......................................................................................................... 75
Entendiendo el flujo del ciclo de vida ........................................................................................................ 76
Creacin y manejo de Base de Datos ........................................................................................... 77
Crear la BD con SQLite en Navicat. ............................................................................................................. 77
Cargar la base de datos en el proyecto de Android ................................................................................... 82
Cargar la base de datos en la aplicacin para poder usarla ....................................................................... 83
Creacin de la Base de Datos con cdigo desde la aplicacin ................................................................... 90
Manejo de SQLite en Android .................................................................................................................... 94
SQLiteOpenHelper ..................................................................................................................................... 94
SQLDatabase y Cursor ................................................................................................................................ 94
Creando un Navigation Drawer .................................................................................................... 98
Abrir y Cerrar men desde un cono. ....................................................................................................... 110
Asignar accin a la pulsacin de un Item del men de navegacin ......................................................... 112

Interactuar con una Base de Datos ............................................................................................ 119


Agregar recursos a la aplicacin ............................................................................................................... 119
Diseo de layouts ..................................................................................................................................... 121
Agregar clases para manejo de interaccin con la base de datos ............................................................ 122
Trazar una ruta ................................................................................................................................ 132
Utils.java .............................................................................................................................................. 136
ConnectionDetecter.java ...................................................................................................................... 138
GMapsDirection.java ............................................................................................................................ 139
Creacin de elementos visuales ........................................................................................................... 145
Agregar funcionalidad a las pantallas, creacin de clases. .................................................................. 154
Crear un lector QR ........................................................................................................................... 171
Qu son los cdigos QR? ........................................................................................................................ 172
Librera ZXing ........................................................................................................................................... 172
Permisos en el AndroidManifest .......................................................................................................... 172
Creacin de interfaces grficas ................................................................................................................ 173
Clases para el lector de QR ................................................................................................................... 176
Adapters ............................................................................................................................................. 194
Entender el comportamiento interno de un Android Adapter ................................................................ 195
Mapas en Android (Google Maps Android API v2) ............................................................... 196
Pasos para instalar y/o configurar la API de Google Maps Android. ........................................................ 196
Pasos para construir una aplicacin bsica usando la API de Google Maps ............................................ 206
Interactuando con el Mapa (pasar coordenadas) .................................................................................... 208
Localizacin geogrfica en Android .......................................................................................... 209
Qu mecanismos de localizacin tenemos disponibles? ....................................................................... 209
Qu proveedor de localizacin es mejor para mi aplicacin? ................................................................ 210
Est disponible y activado un proveedor determinado? ........................................................................ 211
El GPS ya est activado, y ahora qu? .................................................................................................... 211
AsyncTask .......................................................................................................................................... 220
Tipos genricos ........................................................................................................................................ 220
Etapas del ASyncTask ............................................................................................................................... 220
Las reglas del juego .................................................................................................................................. 221
Consumir informacin con la creacin de un Rest API con Google AppScript y uso de
Volley Framework en Android .................................................................................................... 221
Volley: un cliente HTTP para Android. ..................................................................................................... 226
Agregando la Librera ............................................................................................................................... 227
Preparando Volley .................................................................................................................................... 229
Continuamos con el diseo ...................................................................................................................... 230
Modelo Persona ................................................................................................................................... 230

CustomAdapter .................................................................................................................................... 231


Diseo de cada Row de la lista ............................................................................................................. 232
Finalmente ........................................................................................................................................... 233
Layout de MainActivity ........................................................................................................................ 236

Navegacin ......................................................................................................................................... 237


Navegacin con Back y Up ....................................................................................................................... 237
Up vs. Back ............................................................................................................................................... 238
Navegacin dentro de su aplicacin ........................................................................................................ 239
Navegando dentro de la aplicacin va Widgets en la pantalla Home y las Notificaciones. .................... 242
Notificaciones Indirectas .......................................................................................................................... 243
Notificaciones pop-up .............................................................................................................................. 244
Navegando entre aplicaciones ................................................................................................................. 245
Estilos en Android ........................................................................................................................... 249
Dispositivos y Pantallas ............................................................................................................................ 249
Temas ....................................................................................................................................................... 250
Retroalimentacin al Toque ..................................................................................................................... 252
Estados ................................................................................................................................................. 253
Comunicacin ......................................................................................................................................... 253
Lmites .................................................................................................................................................. 254
Mtricas y Rejillas .................................................................................................................................... 254
48dp Rhythm ............................................................................................................................................ 255
Por qu 48dp? .................................................................................................................................... 255
Cuidado con el hueco ........................................................................................................................... 256
Tipografa ................................................................................................................................................. 257
Colores de tipo predeterminado ........................................................................................................... 258
Escala Tipogrfica ................................................................................................................................ 258
Color ......................................................................................................................................................... 258
Paleta ................................................................................................................................................... 259
Iconografa ............................................................................................................................................... 259
Lanzador ............................................................................................................................................... 260
Action Bar ............................................................................................................................................. 262
Iconos pequeos/contextuales ............................................................................................................. 263
Iconos de notificacin ........................................................................................................................... 264
Consejos de Diseo ............................................................................................................................... 265
Su imagen de marca ................................................................................................................................. 268
Color ..................................................................................................................................................... 268
Logo ...................................................................................................................................................... 269
Iconos ................................................................................................................................................... 270
Estilos de Escritura. .................................................................................................................................. 271
La voz de Android. ................................................................................................................................ 271


Qu es Android?
El sistema operativo Android
Android es un sistema operativo basado en el kernel de Linux. El proyecto responsable del desarrollo del
sistema Android es llamado Android Open Source Project (AOSP) y es principalmente liderado por
Google.
El sistema operativo Android soporta procesamiento en background; proporciona una librera de
interfaces de usuario enriquecida, soporta grficos 2D y 3D usando el estndar OpenGL-ES y garantiza
acceso a los archivos del sistema as como la base de datos embebida SQLite
Una aplicacin Android tpicamente consiste de diferentes componentes visuales y no visuales y se
pueden volver a utilizar componentes de otras aplicaciones.

Task (tarea)
La reutilizacin de los componentes de otras aplicaciones nos lleva al concepto de task (tarea) en
Android. Una aplicacin puede acceder a otros componentes de Android para lograr una task. Por
ejemplo, a partir de un componente de nuestra aplicacin, puede desencadenar otro componente en el
sistema Android, el cual gestiona sus fotos, aunque este componente no es parte de su aplicacin. En
este componente se selecciona una foto y volver a la aplicacin para utilizar la foto seleccionada.
Tal flujo de eventos se representa en el siguiente grfico.

2.- inicia galera


1.- Usuario dispara
Recoger foto va

botn

4.- Regresa la foto


seleccionada

Componentes de la plataforma Android



3.- Usuario
selecciona una foto

El sistema Android es una completa pila de software, que suele estar dividido en las cuatro reas como
se muestra en el siguiente grfico.


Los niveles pueden ser descritos como:

Applications (Aplicaciones) - El Proyecto Open Source Android contiene varias aplicaciones por
defecto, como el Navegador, Cmara, Galera, Msica, telfono y mucho ms.
Application framework (Marco de aplicacin) - API que permite la interaccin de alto nivel con el
sistema Android desde las aplicaciones de Android.
Libraries and runtime (Libreras y tiempo de ejecucin) - Bibliotecas para Application framework
con muchas funciones comunes (renderizado grfico, almacenamiento de datos, navegacin
web, etc), as como el runtime Dalvik y las bibliotecas fundamentales de Java para la ejecucin
de aplicaciones Android.
Kernel Linux - capa de la Comunicacin para el hardware subyacente.

El kernel de Linux, las bibliotecas y el runtime se encapsulan en el Application framework. El


desarrollador de aplicaciones Android normalmente trabaja con las dos capas en la parte superior para
crear nuevas aplicaciones de Android.

Google Play

Google ofrece el servicio de Google Play, un mercado en el que los programadores pueden ofrecer sus
aplicaciones Android para los usuarios de Android. Los clientes utilizan la aplicacin Google Play lo que
les permite comprar e instalar las aplicaciones del servicio Google Play.
Google Play tambin ofrece un servicio de actualizacin. Si un programador carga una nueva versin de
su aplicacin a Google Play, este servicio avisa a los usuarios existentes que hay una actualizacin
disponible y permite que se instalen la actualizacin.
Google Play permite el acceso a los servicios y bibliotecas para los programadores de aplicaciones para
Android, tambin. Por ejemplo, se ofrece un servicio para usar y mostrar Google Maps y otro para
sincronizar el estado de la aplicacin entre las diferentes instalaciones Android. La provisin de estos
servicios a travs de Google Play tiene la ventaja de que estn disponibles para las versiones de Android
ms viejas y pueden ser actualizados por Google sin la necesidad de una actualizacin de la versin de
Android en el telfono.

Android Development Tools


Android SDK
El Kit de desarrollo de software Android (Android SDK) contiene las herramientas necesarias para crear,
compilar y empaquetar aplicaciones de Android. La mayora de estas herramientas estn basadas en
lnea de comandos. La principal manera de desarrollar aplicaciones de Android se basa en el lenguaje de
programacin Java.

Android debug bridge (adb)


El SDK de Android contiene el Android debug bridge (adb), que es una herramienta que le permite
conectarse a un dispositivo Android virtual o real, con la finalidad de gestionar el dispositivo o la
depuracin de la aplicacin.

Android Developer Tools y Android Studio


Google proporciona dos entornos de desarrollo integrado (IDE) para desarrollar nuevas aplicaciones.
Las herramientas de desarrollo de Android (ADT) se basan en el IDE de Eclipse. ADT es un conjunto de
componentes (plug-ins), que amplan el IDE Eclipse con capacidades de desarrollo de Android.
Google tambin es compatible con un IDE llamado Android Estudio para la creacin de aplicaciones de
Android. Este IDE se basa en la IDE IntelliJ.
Ambas herramientas proporcionan editores especializados para archivos especficos Android. La
mayora de los archivos de configuracin de Android estn basados en XML. En este caso, estos editores
permiten alternar entre la representacin XML del archivo y una interfaz de usuario estructurado para
introducir los datos.

10

Ambos IDEs contienen toda la funcionalidad necesaria para crear, compilar, depurar y desplegar
aplicaciones de Android. Tambin permiten a los desarrolladores crear e iniciar los dispositivos Android
virtuales para pruebas.

Dalvik Virtual Machine


El sistema Android utiliza una mquina virtual especial, es decir, El sistema Android utiliza una mquina
virtual especial, es decir, la mquina virtual de Dalvik (Dalvik) para ejecutar aplicaciones basadas en Java.
Dalvik utiliza un formato de bytecode a medida que es diferente del bytecode de Java.
Por lo tanto no se puede ejecutar archivos de clase Java en Android directamente, sino que necesitan
ser convertidos en el formato de bytecode de Dalvik.
Dalvik funciona de forma similar a la mquina virtual de Java en cuanto a la optimizacin de
aplicaciones. Optimiza la aplicacin en tiempo de ejecucin. Esto se conoce como Just In Time (JIT). Si
una parte de la aplicacin se llama con frecuencia, Dalvik optimizar esta parte del cdigo y lo compila a
cdigo mquina que ejecuta mucho ms rpido.

Android Runtime
Aplicaciones de Android estn escritas principalmente en el lenguaje de programacin Java.
Con Android 4.4, Google present el Android Runtime (ART) como un runtime opcional para Android
4.4. Se espera que las versiones posteriores 4.4 usarn ART como runtime predeterminado.
ART utiliza Ahead Of Time compilation. Durante el despliegue de una aplicacin en un dispositivo
Android, el cdigo de la aplicacin es traducida a cdigo mquina. Esto da lugar a aprox. 30% de cdigo
de compilacin ms grande, pero permite una ejecucin ms rpida desde el principio de la aplicacin.
Recordemos que, para efectos de este curso estaremos usando Android 4.0 (API 14), esto es slo para
informacin.

Como desarrollar aplicaciones Android


Durante el desarrollo el desarrollador crea los archivos de configuracin especficos para Android y
escribe la lgica de la aplicacin en el lenguaje de programacin Java.

Las herramientas ADT o el Studio Android convierten esos archivos de la aplicacin de forma
transparente para el usuario en una aplicacin Android. Cuando los desarrolladores inician el despliegue
en su IDE, toda la aplicacin Android es compilada, empaquetada, desplegada e iniciada.

Proceso de conversin desde cdigo fuente hasta una aplicacin Android



11

Los archivos de cdigo fuente de Java son convertidos en archivos de clases de Java por el compilador
Java.
El SDK de Android contiene una herramienta llamada dx que convierte archivos de clase Java en un
archivo .dex (Dalvik ejecutable). Todos los archivos de clase de la aplicacin se colocan en el archivo
.dex. Durante este proceso de conversin la informacin redundante en los archivos de clase sern
optimizados en el archivo .dex.
Por ejemplo, si la misma String se encuentra en archivos de clase diferentes, el archivo .dex contiene
slo una referencia a esta String.
Estos archivos .dex son por lo tanto mucho ms pequeo en tamao que los archivos de clases
correspondientes.
El archivo de .dex y los recursos de un proyecto Android, esto es, las imgenes y los archivos XML, se
empaquetan en un archivo .apk (Android Package). El programa aapt (Android Asset Packaging Tool)
realiza este paso.
El archivo .apk resultante contiene todos los datos necesarios para ejecutar la aplicacin Android y se
puede implementar en un dispositivo Android a travs de la herramienta adb.

Seguridad y permisos
Concepto de seguridad en Android
El sistema Android instala cada aplicacin Android con un nico usuario y ID de grupo. Cada archivo de
aplicacin es privado para este usuario generado, esto es, otras aplicaciones no pueden acceder a estos
archivos. Adems, cada aplicacin Android se inicia en su propio proceso.
Por lo tanto por medio del kernel de Linux subyacente, cada aplicacin Android se asla de otras
aplicaciones en ejecucin.
Si se deben compartir los datos, la aplicacin debe hacer esto de manera explcita a travs de un
componente de Android que se encarga de la distribucin de los datos, por ejemplo, a travs de un
servicio o de un proveedor de contenido.

Concepto de permiso en Android


Android contiene un sistema de permisos y predefine permisos para ciertas tareas. Cada aplicacin
puede solicitar permisos necesarios, as como definir nuevos permisos. Por ejemplo, una aplicacin
puede declarar que requiere acceso a Internet.
Los permisos tienen diferentes niveles. Algunos permisos se conceden automticamente por el sistema
Android, algunos sern rechazados automticamente. En la mayora de los casos los permisos solicitados

12

se presentan al usuario antes de instalar la aplicacin. El usuario tiene que decidir si estos permisos
sern otorgados a la aplicacin.
Si el usuario deniega una autorizacin necesaria, la aplicacin relacionada no se puede instalar. La
comprobacin de la autorizacin slo se realiza durante la instalacin, los permisos no pueden ser
negados u otorgados despus de la instalacin.
Una aplicacin Android declara los permisos necesarios en su archivo de configuracin
AndroidManifest.xml. Tambin puede definir los permisos adicionales que puede utilizar para restringir
el acceso a determinados componentes.
Nota
No todos los usuarios presten atencin a los permisos requeridos durante la instalacin. Sin embargo,
algunos usuarios hacen y escriben comentarios negativos en Google Play si creen que la aplicacin es
demasiado invasiva.

Instalacin
Consideraciones previas y de instalacin
1.

2.

Para los fines de este curso se considera que se debe de tener instalado java con la versin
jdk1.7.0_51, en caso de no tenerlo instalado ir al siguiente enlace
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-
1880260.html y escoger la opcin que ms se apegue a su sistema.
Verificar tener instalado el ADT (Android Developer Tool), que es la herramienta (IDE) de
desarrollo basada en Eclipse que nos servir para el desarrollo de nuestra aplicacin, en este
punto tambin es bueno verificar que se tenga instalado el SDK de Android. En caso de no
tenerla instalado nada de esto, esta es la url que nos lleva a la pgina de descarga oficial del
ADT http://developer.android.com/sdk/index.html.
a. En esta pgina hacer click en el botn que se muestra en la Imagen 1.


Imagen 1

b. Aceptar los trminos y/o condiciones adems de escoger la versin de 32-bit o de 64-
bit, como se muestra en la Imagen 2 esto se define basndose en la versin de java que
tengan instalado en su sistema. Es importante que escoger bien porque si no coinciden
las versiones del jdk con el ADT no se podr ni instalar.

13


Imagen 2

c. Ahora hacer click en el botn mostrado en la Imagen 3, y esperar a descargar para


instalarlo


Imagen 3

Preparar IDE
1. Para consideraciones de este manual se trabajar con la versin de Android 4.0 Ice Cream
Sandwich (API 14).
2. Lo primero ser ejecutar la aplicacin ADT (Imagen 4).


Imagen 4

3. Ya en marcha podremos comprobar si tenemos instalado el SDK adecuado haciendo click en la


herramienta Android SDK Manager que se puede ejecutar haciendo click en el cono de la
Imagen 5.

14


Imagen 5

4. La ventana mostrada en la Imagen 6 nos muestra todos los SDKs existentes y algunas
herramientas disponibles, pero lo que nos interesa es lo que est encerrado en el cuadro rojo,
hay dos opciones una que ya est instalado el SDK que ocupamos (y diga Installed), y la otra es
que an no lo est que es el caso que muy probablemente tengamos por ser de reciente
instalacin, para tal caso debemos de marcar las casillas de los checkboxes en las opciones SDK
Platform, ARM EABI v7a System Image y Google APIs, seleccionadas estas opciones se procede a
seleccionar el botn Install que ahora debe de decir Install 2 packages,


Imagen 6


a. Aparecer en este momento una ventana que nos pide que aceptemos las condiciones
de uso de los paquetes a instalar y seleccionamos Accept All, y luego click al botn
Install, como se muestra en la Imagen 7

15


Imagen 7

b. Esperamos un tiempo mientras descarga el sdk de internet y se instala.


Terminada la descarga e instalacin cerramos el Android SDK Manager.

Emulador de dispositivo Android y


Dispositivo Virtual Android (Android
Virtual Devices, AVD)
Emulador Android y Android Virtual Device
El SDK de Android contiene un emulador de dispositivos Android. Este emulador se puede utilizar para
ejecutar un dispositivo virtual de Android (AVD), que emula un telfono Android real. Este emulador se
muestra en la siguiente captura de pantalla.

16


AVDs le permiten probar sus aplicaciones de Android en diferentes versiones y configuraciones de
Android sin acceso al hardware real.
Durante la creacin de su AVD se define la configuracin para el dispositivo virtual. Esto incluye, por
ejemplo, la resolucin, la versin de la API de Android y la densidad de la pantalla.
Se pueden definir varios AVDs con diferentes configuraciones y comenzar en paralelo. Esto le permite
probar diferentes configuraciones de los dispositivos a la vez.

Atajos para el emulador de dispositivos Android


La siguiente tabla muestra los accesos directos tiles para trabajar con una AVD.

17

Tabla 1. Atajos para el emulador de dispositivos de Android

ATAJO

DESCRIPCIN

ALT+ENTER MAXIMIZA EL EMULADOR.


CTRL+F11 CAMBIA LA ORIENTACIN DEL EMULADOR DE HORIZONTAL A VERTICAL Y VICEVERSA.
F8

ENCIENDE Y APAGA LA RED

Google vs. Android AVD


Durante la creacin de una AVD usted decide si desea crear un dispositivo Android o un dispositivo de
Google.
Un AVD creado para Android contiene los programas del proyecto de Android Open Source. Un AVD
creada para la API de Google contiene cdigo especfico adicional de Google.
AVDs creadas con la API de Google le permiten probar aplicaciones que utilizan Google Play Services,
por ejemplo, la nueva API de Google Maps o los nuevos servicios de localizacin.

Optimizacin de Velocidad
Durante la creacin de un emulador se puede elegir si se desea, ya sea Snapshot o habilitar Use Host
GPU. Si selecciona la opcin de Snapshot, la segunda vez que se inicia el dispositivo se inicia muy rpido,
debido a que la AVD almacena su estado en caso que lo cierre. Si selecciona Usar Host GPU la AVD utiliza
la tarjeta grfica de su ordenador directamente, hace el renderizado en el dispositivo emulado mucho
ms rpido.

18

Emulador Intel
El emulador de Intel que puede ser instalado a travs del Administrador SDK de Android es mucho ms
rpido en la ejecucin en el hardware de Intel / AMD. Si lo instala a travs del SDK, es necesario instalar
tambin el controlador que se encuentra en el directorio de instalacin del dispositivo.

19

Emulador Alternativo
Hay alternativas disponibles al emulador por defecto de Android. Por ejemplo, el emulador Genymotion
es relativamente rpido en la puesta en marcha y ejecucin de proyectos de Android

Ejercicio: Crear e iniciar Android Virtual


Device
Target (objetivo)
En este ejercicio se crear e iniciar un AVD. Aunque si se tiene un dispositivo Android real disponible, te
debera de ser familiar la creacin y uso de los AVDs. Los dispositivos virtuales dan la posibilidad para
probar su aplicacin en otras versiones de Android y especificar configuraciones.

Crear el AVD
Definir un nuevo Android Virtual Device (AVD) abriendo el AVD Manager via Window>Android Virtual
Device Manager y presionar el botn New


Ingresar valores similares a los de la siguiente toma de pantalla.

20


Nota
Asegurarse que la opcin Use Host GPU este seleccionada. Esto permite que el AVD use la unidad de
procesamiento grfico (GPU) de su computadora y hace el renderizado mucho ms rpido.
Despus presionar el botn OK. Esto crear la configuracin del AVD y lo desplegar bajo la lista de
dispositivos virtuales disponibles.

21

Iniciar tu AVD
Seleccionar la nueva entrada y presionar el botn Start. Seleccionar Launch en el siguiente dialogo.


Advertencia
No interrumpa el proceso de inicio, esto podra corrompir el AVD. El primer inicio puede tomar arriba de
10 minutos en mquinas viejas. En una maquina moderna tpicamente toma 1 3 minutos para un
nuevo AVD al iniciar.
Despus de iniciado el AVD, puedes controlar la GUI con el mouse. El emulador puede proveer acceso a
los botones del telfono va un men del lado derecho del emulador.

22


Tip
Una vez inicializado, no detener el AVD durante el desarrollo. Si se cambia algo en la aplicacin y quiere
probar una nueva versin, simplemente hay que correr o ejecutar de nuevo la aplicacin en el AVD.

Ejercicio: Crear aplicacin Android en


Eclipse
Asistente de proyectos Android
Las herramientas de Android en Eclipse proporciona asistentes para aplicaciones de Android. En este
ejercicio se utiliza el asistente de creacin de proyecto para crear una aplicacin de Android basada en
una plantilla.
Nota
El propsito de este ejercicio es demostrar el proceso de desarrollo. Los elemnots creados se explicarn
ms adelante.

Crear proyecto Android

23

Para crear un nuevo proyecto Android seleccione File New Other... Android Android Project
en el men. Introduzca los datos de ajuste de la siguiente tabla en la primera pgina del asistente.
Tabla 2. Ajuste para su proyecto Android

Property

Value

Application Name

Test App

Project Name

com.utm.primero

Package Name

com.utm.primero

API (Minimum, Target, Compile with) 14



Pulse el botn Siguiente y asegrese de habilitar la opcin Create a launcher icon (Crear un icono de
lanzador ) y Create activity (Crear actividad).

24


Pulse el botn Next y seleccione la plantilla BlankActivity. Pulse el botn Next para proceder.

25


Introduce los siguientes datos en el cuadro de dilogo para la plantilla BlankActivity. La seleccin se
representa en la pantalla despus de la tabla.
Tabla 3. Valores para la plantilla

Parameter

Value

Activity

MainActivity

Layout

activity_main

Navigation Type none


26


Pulse el botn Finish. El asistente le puede pedir que instale la biblioteca de compatibilidad. Si es as,
seleccione para instalarla.

27

Ejercicio: Inicie la aplicacin Android


generada
Iniciar AVD
Si an no lo ha hecho, cree e inicie un dispositivo virtual de Android (AVD). La versin de Android que
usted seleccione debe adaptarse a la versin mnima API de la aplicacin Android.
Despus del arranque aparece la pantalla de bienvenida de su AVD como se muestra en la siguiente
captura de pantalla.


Una vez que est listo, desbloque su emulador.

28

Inicicar la aplicacin
Seleccione el proyecto Android, haga clic derecho sobre l y seleccione Run-As Android Aplication.

29

Se le puede pedir si el Android Developer Tools deben supervisar los mensajes. Seleccione Yes en este
caso y pulse el botn OK.


As se inicia la aplicacin en la AVD. La aplicacin iniciada es una aplicacin muy simple que slo muestra
la cadena Hola, mundo! .

30

Integracin de ADT dentro de Eclipse


Integracin de Android dentro de la perspectiva Java
La herramienta Android se integra con la perspectiva Java. Incluye botones en la barra de herramientas
para administrar la configuracin de Android con el gestor Android SDK, crea nuevos AVDs y archivos de
configuracin, as como contiene asistentes para crear nuevos proyectos Android.
La siguiente captura de pantalla resalta la barra de herramientas de Android
1 2

1. Android SDK Manager
2. Manejo e inicio de AVDs

Asistentes de Android
Se encontrarn los asistentes especficos de Android bajo File New Other... Android como se
muestra en la siguiente captura de pantalla. Estos asistentes le permiten crear proyectos para Android.

Perspectiva DDMS

31

Perspectiva Android
ADT agrega la perspectiva DDMS (Dalvik Device Monitoring Service) para interactuar con tu dispositivo
Android (virtual) y tu aplicacin Android. Selecciona Window Open Perspective Other... DDMS
para abrir esta perspectiva. Aqu se agrupan varias vistas que pueden ser usadas de forma
independiente.
En la parte izquierda se muestran los dispositivos Android conectados y los procesos en ejecucin en el
dispositivo. El lado derecho es un conjunto de vistas con diferentes propsitos. Puede seleccionar
procesos y desencadenar acciones de la barra de herramientas, por ejemplo, iniciar una traza o detener
el proceso.

File Explorer
El explorar de archivos permite navegar el sistema de archivos del dispositivo de Android ya sea virtual o
real conectado.

Partes de una aplicacin Android


Aplicacin Android
Una aplicacin para Android es una sola unidad instalable que se puede iniciar y utilizar de forma
independiente de otras aplicaciones de Android.
Una aplicacin Android puede tener una clase de la aplicacin la cual puede ser instanciada tan pronto
como se inicia la aplicacin y es el ltimo componente que se detiene si la aplicacin se detiene.

32

Una aplicacin Android consta de componentes de software de Android y de archivos de recursos.


Los componentes de una aplicacin Android pueden conectar a otras aplicaciones Android. De esta
manera se puede crear tareas entre aplicaciones.

Componentes de software Android


Los siguientes componentes de software pueden ser definidos en las aplicaciones Android

Activities (Actividades)
Services (Servicios)
Broadcast Receivers (receivers)
Content providers (providers)

Contexto
Instancia de la clase android.content.Context que proporciona la conexin con el sistema Android
el cual ejecuta la aplicacin. Por ejemplo, se puede revisar el tamao de la pantalla del dispositivo actual
via el Context.
Tambin da acceso a los recursos del proyecto. Es la interfaz a la informacin global sobre el entorno de
la aplicacin.
La clase Context tambin proporciona acceso a los servicios, esto es, el manejador de alarmas para
disparar eventos basados en el tiempo.
Las actividades y servicios extienden de la clase Context. Por lo tanto, se pueden utilizar directamente
para acceder al Context.

Vistazo a los componentes de una


aplicacin Android
Activity (Actividad)
Una activity es la representacin visual de una aplicacin Android. Una aplicacin Android ouede tener
varias actividades.
Las actividades usan views (vistas) y fragments (fragmentos) para crear la interfaz de usuario e
interactuar con el usuario.

BroadcastReceiver
Un broadcast receiver (receiver) puede ser registrado para escuchar los mensajes del sistema y los
intents. Un receiver ser notificado por el sistema Android si el evento especificado ocurre

33

Por ejemplo, se puede registrar un receiver para el vento en el que el sistema android finaliza el proceso
de arranque. O se puede registrar para el evento en el que el estado del telefono cambia, esto es, que
alguien llama.

Service (Servicio)
Un servicio realiza tareas sin proporcionar una interfaz de usuario. Se pueden comunicar con otros
componentes Android, por ejemplo, a travs de los receptores de radiodifusin y notificar al usuario a
travs del marco de la notificacin de Android.

ContentProvider
Un content provider (provider) define una interfaz estructurada de datos de la aplicacin. Un proveedor
puede ser utilizado para acceder a datos dentro de una aplicacin, pero tambin se puede utilizar para
compartir datos con otras aplicaciones.

Componentes base en las interfaces de


usuario en Android
La siguiente descripcin da una visin general de la interfaz de usuario relacionada con los componentes
ms importantes y partes de una aplicacin Android.

Acitivity (Actividad)
Las activities son la base para las aplicaciones de usuario en Android. Estas ya fueron vistas en la seccin
anterior.

Fragments (Fragmentos)
Los Fragments son componentes los cuales corren en el contexto de una activity. Un fragment
encapsula cdigo de aplicaciones as qu es ms fcil reutilizar y soportar dispositivos de diferentes
tamaos.
La siguiente imagen muestra una activity llamada MainActivity. En una pantalla ms pequea que
muestra slo un fragmento y permite que el usuario se desplaza a otro fragmento. En una pantalla
panormica que muestra dos fragmentos.

34


Los fragmentos son componentes opcionales que le permiten reutilizar los componentes de interfaz de
usuario para diferentes configuraciones de dispositivos.

Views y control de distribucin


Las views son widgets de interfaz de usuario, por ejemplo, botones o campos de texto. Las views tienen
atributos que pueden utilizarse para configurar su apariencia y comportamiento.
A ViewGroup es responsable de la organizacin de otras vistas. Tambin se conoce como controlador de
distribucin (layout manager). La clase base para estos controladores de distribucin es la clase

35

android.view.ViewGroup que extiende (hereda) de la clase android.view.View que es la


clase base para las vistas.
Los layout manager pueden etar anidados para crear layout ms complejos.

Diseos especficos de configuracin de dispositivos


La interfaz de usuario para las activities suelen definirse a travs de archivos XML (archivos de diseo).
Es posible definir archivos de diseo para la configuracin de dispositivos diferentes, por ejemplo,
basados en la anchura disponible del dispositivo real que ejecuta la aplicacin.

Otros elementos importantes de Android


Pantalla principal y la pantalla de bloqueo de widgets
Los widgets son componentes interactivos que se utilizan principalmente en la pantalla de inicio de
Android. Ellos exhiben tpicamente algn tipo de datos y permiten al usuario realizar acciones con ellos.
Por ejemplo, un control puede mostrar un breve resumen de los nuevos mensajes de correo electrnico
y, si el usuario selecciona un correo electrnico, puede iniciar la aplicacin de correo electrnico con el
correo electrnico seleccionado.
Para evitar confusiones con los views (que tambin se llaman widgets), este texto utiliza el termino de
los widgets en la pantalla de inicio, si se habla de widgets.

Live Wallpapers
Los Live Wallpapers permiten crear fondos animados para la pantalla de inicio de Android.

El Android Manifest
La configuracin de la aplicacin para Android
Los componentes y configuracin de una aplicacin para Android, se describen en el archivo
AndroidManifest.xml. Este archivo se conoce como el archivo de manifiesto o el manifiesto.
El manifiesto tambin especifica metadatos adicionales para la aplicacin, por ejemplo, iconos y el
nmero de versin de la aplicacin.
Este archivo es ledo por el sistema Android durante la instalacin de la aplicacin. El sistema Android
evala este archivo de configuracin y determina las capacidades de la aplicacin.

Declarar los componentes en el archivo de manifiesto



36

Todas las activities, servicios y contenido de los content provider de la aplicacin se deben declarar de
forma esttica en este archivo. Los broadcast receivers pueden ser definidos estticamente en el archivo
de manifiesto o dinmicamente al tiempo de ejecucin de la aplicacin.

Permisos
El archivo de manifiesto de Android tambin debe contener los permisos necesarios para la aplicacin.
Por ejemplo, si la aplicacin requiere acceso a la red, se debe especificar aqu.

Ejemplo del archivo AndroidManifes.xml


El siguiente listado muestra un ejemplo para un simple archivo AndroidManifest.xml.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.rssfeed"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="RssApplication"
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="RssfeedActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DetailActivity"
android:label="Details" >
</activity>
<activity android:name="MyPreferenceActivity" >
</activity>
<service android:name="RssDownloadService" >
</service>
</application>
</manifest>

37

El manifiesto de Android
Versin y paquete
El atributo de package define el paquete base para los objetos Java que se hace referencia en este
archivo. Si un objeto de Java se encuentra dentro de un paquete diferente, se debe declarar con el
nombre completo del paquete calificado.
Google Play requiere que cada aplicacin Android utilice su propio nombre nico de paquete. Por lo
tanto es un buen hbito el usar su nombre de dominio inverso aqu. Esto evitar colisiones con otras
aplicaciones de Android.
android:versionName y android:versionCode especifican la version de su aplicacin.
versionName es lo que ve el usuario y puede ser cualquier cadena.
versionCode debe ser un entero. El Android Market determina si se debe llevar a cabo una
actualizacin de las aplicaciones para la instalacin existente basado en el versionCode. Por lo
general, comienza con "1" y aumenta este valor por uno si sale una nueva versin de su aplicacin.

Aplicacin y componentes
La seccin <application> permite definir metadatos para su aplicacin y, opcionalmente, definir
una clase de aplicacin explcita. Tambin es un contenedor para la declaracin de los componentes de
su Android.
La etiqueta <activity> define un componente activity. El atributo de nombre seala a la clase, la
cual (si no es totalmente calificado) es relativa al paquete definido en el atributo del paquete.
La parte de intent filter en el archivo de manifiesto de Android, dice a Android en tiempo de ejecucin
que esta actividad debe registrarse como un posible punto de entrada a la aplicacin y puesta a
disposicin en el lanzador del sistema Android. La accin que define esto (android: name =
"android.intent.action.MAIN") se puede iniciar y el parmetro category android:
name = parmetro "android.intent.category.LAUNCHER" le dice al sistema Android
para agregar la actividad al lanzador.
El valor @string/app_name se refiere a los archivos de recursos que contienen el valor real del
nombre de la aplicacin. El uso de un archivo de recursos hace que sea fcil para proporcionar
diferentes recursos (por ejemplo, secuencias, colores, iconos) los diferentes dispositivos y hace que sea
fcil de traducir las aplicaciones.
Al igual que en la etiqueta <activity>, puede utilizar el service, el receiver y provider para declarar
otros componentes Android.

Minimun y target SDK



38

La seccin uses-sdk en el manifiesto te permite especificar el minSdkVersion y targetSdkVersion la


versin de tu aplicacin.
Tabla 4. Minimun y versin target

Valor

Descripcin

minSdkVersion

Define la versin mnima de Android en la que funciona tu aplicacin. Este atributo se


utiliza como filtro en Google Play, es decir, un usuario no puede instalar la aplicacin
en un dispositivo con un nivel de API inferior a la especificada en este atributo.

Especifica la versin en la cual se prob y desarroll. Si es igual a la versin de API del


dispositivo Android, el sistema Android podra aplicar cambios de compatibilidad
targetSdkVersion haca adelante o haca atrs. Es una buena prctica siempre declararlo a la ltima
versin de API de Android para tomar ventajas de los cambios en en las mejoras de las
ltimas mejoras de Android.


Permisos
Su aplicacin puede declarar permisos con la etiqueta <permission> y declarar que se requiere un
permiso de operaciones con la etiqueta <uses-permission>.

Configuraciones requeridas del dispositivo


La seccin uses-configuration en el manifiesto le permite especificar los mtodos de entrada
requeridos para su dispositivo. Por ejemplo, el siguiente fragmento sera necesario que el dispositivo
disponga un teclado de hardware.
<uses-configuration android:reqHardKeyboard="true"/>


La seccin uses-feature le permite especificar la configuracin del hardware requerida para su
dispositivo. Por ejemplo, el siguiente fragmento sera necesario que el dispositivo disponga una cmara.
<uses-feature android:name="android.hardware.camera" />


Localizacin de instalacin
A travs del atributo installLocation de su aplicacin, puede especificar si la aplicacin se puede
instalar en la memoria externa del dispositivo. Utilice auto o preferExternal para permitir esto.
Advertencia

39

En realidad esta opcin se utiliza muy poco, como una aplicacin instalada en el almacenamiento
externo se detiene una vez que el dispositivo est conectado a un ordenador y se monta como
almacenamiento USB.

Ms informacin
Se puede encontrar ms informacin acerca de los atributos y secciones del manifesto en la
documentacin del Android Manifest.

Recursos

Archivos de recursos
Recursos, como imgenes y archivos de configuracin XML, se mantienen separados a partir del cdigo
fuente de las aplicaciones de Android.
Los archivos de recursos se deben colocar en el directorio en la subcarpeta predefinida /res. La
subcarpeta especfica depende del tipo de recurso que se almacena.
La siguiente tabla ofrece una visin general de los recursos admitidos y sus prefijos de carpetas
estndar.
Tabla 5. Recusros

Recursos

Folder

Description

Drawables

/res/drawables

Las imgenes (por ejemplo, JPEG o PNG archivos) o archivos XML que
describen un objeto Drawable.

Valores
Simples

/res/values

Se utiliza para definir las cadenas, colores, dimensiones, estilos y arreglos


estticos de cadenas o enteros a travs de archivos XML. Por convencin
cada tipo se almacena en un archivo independiente, por ejemplo, las
cadenas se definen en el archivo res/values/strings.xml.

Layouts

/res/layout

Archivos XML con descripciones de los layout que se utilizan para definir
la interfaz de usuario para las Actividades y fragmentos.

/res/values

Los archivos que definen la apariencia de la aplicacin Android.

Estilos
temas

Animaciones /res/animator Define animaciones en XML para la API de animacin que permite animar

40

Recursos

Folder

Description
las propiedades arbitrarias de objetos con el tiempo.

Raw data

/res/raw

Archivos arbitrarios guardados en su forma cruda. Usted accede a ellos a


travs de un objeto InputStream.

Menus

/res/menu

Define las propiedades de entrada para un men.


Ejemplo de recurso
La siguiente lista es un ejemplo para el archivo llamado values.xml en los /res/values que
definen un par de constantes de cadena, una matriz de String, un color y una dimensin.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Test</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string-array name="operationsystems">
<item>Ubuntu</item>
<item>Android</item>
<item>Microsoft Windows</item>
</string-array>
<color name="red">#ffff0000</color>
<dimen name="mymargin">10dp</dimen>
</resources>

Calificadores de recursos
Tambin es posible aadir calificadores adicionales a nombre de la carpeta para indicar que los recursos
relacionados se deben usar para configuraciones especiales. Por ejemplo, se puede especificar que
archivo de diseo slo es vlido para un determinado tamao de la pantalla.

Ids de recursos y R.java


Cada archivo de recursos recibe un identificador asignado por el sistema de generacin Android. El
directorio de generacin en un proyecto de Android contiene el archivo de referencias R.java que
contiene estos valores generados. Estas referencias son valores enteros estticas.

41

Si se agrega un nuevo archivo de recursos, la referencia correspondiente se crea automticamente en


un archivo R.java. Cambios manuales en el archivo R.java no son necesarios y sern reemplazados por
la herramienta.
El sistema Android proporciona mtodos para acceder a los archivos de recursos correspondientes a
travs de estos identificadores.
Por ejemplo, para acceder a un String con el ID R.string.yourString en el cdigo fuente, debe
utilizar el mtodo getString(R.string.yourString) definido en la clase Context.

Buenas practicas para los Ids de los recursos


El SDK de Android utiliza la notacin camelCase para la mayora de sus identificaciones, por ejemplo,
buttonRefresh. Es una buena prctica a seguir este enfoque.

Recursos del sistema


Android tambin proporciona recursos. stos se llaman los recursos del sistema. Los recursos del
sistema se distinguen de los recursos locales mediante el prefijo de nombre de espacio de android.
Por ejemplo, android.R.string.cancel define la cadena de plataforma para una operacin de
cancelacin.

Views (vistas)
Clase View
Un view en Android representa un widget, por ejemplo, un botn, o un layout manager.
Todos los views en Android extienden de la clase android.view.View. Esta clase es relativamente
grande (ms de 18 000 lneas de cdigo) y proporciona una gran cantidad de funcionalidad base para las
subclases. El cliente puede implementar sus propios views extendiendo android.view.View.

Views estndar de Android


Android proporciona vistas estndar (widgets), por ejemplo, el botn, TextView, clases EditText y
widgets ms complejos, por ejemplo, ListView o GridView para mostrar datos estructurados.
Los principales paquetes para views son parte del espacio de nombres android.view para todas las
clases de base y android.widget para los widgets por defecto de la plataforma Android.
El uso de las views estndar se demuestra en los siguientes ejercicios.

Views personalizadas

42

Los desarrolladores son libres de desarrollar sus propios views mediante la ampliacin de la clase
android.view.View.
Definicin de los layouts a travs de archivos de diseo de XML es la manera preferida. Esto separa la
lgica de programacin a partir de la definicin de diseo. Tambin permite la definicin de diferentes
diseos para diferentes dispositivos.

Archivos de recursos layouts


Actividades y layouts
Actividades en Android definen su interfaz de usuario con views (widgets) y fragmentos. Esta interfaz de
usuario se puede definir a travs de archivos XML layouts de diseo en las carpetas res/layout/ o
por medio de cdigo Java. Tambin se pueden mezclar ambos enfoques.

Archivos layout XML


Un archivo de layout se conoce como diseo. Un layout especifica los ViewGroups, Views, sus
relaciones y sus atributos a travs de una representacin XML.
El cdigo siguiente es un ejemplo de un simple archivo layout.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/mytext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>


Un layout se asigna a una actividad a travs de la llamada del mtodo setContentView, como se
demuestra en el siguiente ejemplo de cdigo.
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {

43

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

Definiendo Ids
Si un view debe accederse a travs de cdigo Java, se tiene que dar a la View un identificador nico a
travs del atributo android:id. Para asignar un nuevo ID a una View de utilizar el atributo
android:id del elemento correspondiente en el archivo layout. A continuacin se muestra un
ejemplo en el que un botn recibe el ID boton1 establecida desde el parmetro
android:id="@+id/button1".
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Preferences" >
</Button>

La conversin de esta sentencia crea un nuevo ID si es necesario en el archivo R.java y asigna el ID


definido a la vista correspondiente.

Buena prctica: predefinir los IDs a travs de un archivo separado.


Como se describe en la ltima seccin Android permite definir los IDs de los componentes de interfaz de
usuario de forma dinmica en los archivos layout. Para tener un lugar central para definir ID, tambin se
puede definir en un archivo de configuracin.
Para controlar sus IDs, tambin se puede crear un archivo, normalmente llamado ids.xml, en la
carpeta /res/values y definir sus IDs en este archivo. El siguiente listado muestra un ejemplo de un
archivo de este tipo.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="button1" type="id"/>
</resources>


Esto permite utilizar el ID en el archivo layout.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"

44

tools:context=".MainActivity" >
<Button
android:id="@id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginRight="27dp"
android:text="Button" />
</RelativeLayout>

Consideraciones de desempeo con layouts


Clculando el layout y elaborando las views como una operacin intensiva de recursos. Se debera
utilizar el diseo ms simple posible para lograr un buen rendimiento. Por ejemplo, se debe evitar
anidar layout managers demasiado profundo o evitar el uso de layout maangers complejos en este caso
un layout manager simple es suficiente.

Ejercicio: Usar layout y agregar


interaccin
Cambiar layout
En tu proyecto com.utm.primero, abre el archivo de layout activity_main.xml que se
encuentra en la carpeta res/layout .
Investigar el diseo XML en el editor visual, as como la estructura XML.
Retire todos los views, excepto el layout manager. En el modo de diseo visual puede quitar una view,
haciendo clic-derecho en l y seleccionando la entrada Eliminar del men contextual.
Aadir un EditText (Plain Text) y un botn para su layout. La forma ms fcil es encontrar estos
elementos en la Paleta y arrastrar y soltar en su layout.
Usar el editor XML para cambiar el ID del nuevo campo EditText a main_input. En el archivo XML se ver
similar a esto @+id/main_input.

Cambiar el color de fondo del linear layout a plata (#C0C0C0). Usar para esto la propiedad
android:background.

Agregando botn interactivo


Cambiar el texto del botn a Iniciar va la propiedad android:text de tu layout.

45

Asignar el nombre onClick a la propiedad android:onClick de tu Button.


Tip
Esto define que un mtodo public void onClick (View view)ser llamado en la activity una vez que
el botn sea presionado.

El layout resultante se vera como la siguiente toma de pantalla.


Implementar el siguiente mtodo en su clase MainActivity.
public void onClick (View view) {
Toast.makeText(this, "Botn 1 presionado",
Toast.LENGTH_LONG).show();
}

Validando interaccin del botn


Iniciar la aplicacin. Presionar el botn y validar que el mensaje aparezca (Toast).

Desplegar texto desde el campo EditText


Volver al cdigo fuente y utilizar el mtodo findViewById(id) con el id correcto y convertir el
objeto devuelto en EditText, por ejemplo, EditText text = (EditText) findViewById(id).
Puedes obtener el identificador correcto a travs de la clase R. Debe ser almacenado bajo ID y llam
main_input.

46

Usa el mtodo text.getText().toString()para leer la cadena que se encuentra en el campo editor y


agrega el texto al mensaje de tu Toast.

Validar mensaje emergente


Reinicie la aplicacin y asegurar que el Toast muestra el texto que contiene el campo EditText.

Ejercicio: Influir en la vista del layout en


tiempo de ejecucin
Agregar radio group y radio buttons al layout
Seguir usando el proyecto denominado com.utm.primero. En este ejercicio se agrega radio buttons
al layout. Dependiendo de la seleccin del usuario el acomodo de los radio buttons cambia de horizontal
a vertical.
Abrir el archivo del layout y agregar un radio group con dos radio buttons al layout
Tip
En caso de tener problemas con la creacin de los botones de radio con el editor visual, se encuentra el
fragmento de cdigo XML resultante adelante en este ejercicio.
El radio group es difcil de encontrar en la vista Paleta. El widget est resaltado en la siguiente captura
de pantalla. Si es necesario, quite los botones de opcin hasta que haya slo dos botones.


Tip

47

Para

asignar

Ids

las

views,

usar

el

atributo

android:id,

android:id="@+id/orientacion
Asignarlos basados en la siguiente tabla
Tabla 6 Asignacin de ID

ID

View

orientacion Radio Group


horizontal First radio button
vertical

Second radio button


Parte del resultado del layout sera similar al siguiente listado
<!-- Este fragmento es parte del archivo de layout ms grande -->
<RadioGroup
android:id="@+id/orientacion"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Horizontal" >
</RadioButton>
<RadioButton
android:id="@+id/vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Vertical" >
</RadioButton>
</RadioGroup>


El layout resultante debe ser similar a la siguiente captura de pantalla.

48

por

ejemplo:

Cambiar la orientacin del radio group dinamcamente


Cambiar el mtodo onCreate() en tu activity. Usa el mtodo findViewById() para encontrar el
RadioGroup en tu layout.
Implementar un listener en el radio group que cambia la orientacin de los radio buttons basado en la
seleccin actual de los botones. Qu botn est seleccionado, puede ser identificado por el parmetro
ID.
Tip
RadioGroup permite agregar un RadioGroup.OnCheckedChangeListener desde el paquete
android.widget.RadioGroup va el mtodo setOnCheckedChangeListener(). Este listener es

notificado si la seleccin del radio group cambia.


Puedes usar el siguiente cdigo como base para implementar el listener.
RadioGroup group1 = (RadioGroup) findViewById(R.id.orientation);
group1.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.horizontal:
group.setOrientation(LinearLayout.HORIZONTAL);
break;
case R.id.vertical:
group.setOrientation(LinearLayout.VERTICAL);

49

break;
}
}
});

Validar
Correr la aplicacin y seleccionar los diferentes radio buttons. Asegurarse que la orientacin de los
botones cambie en base a la seleccin.

Usando Resources
Referencias a recursos en cdigo
La clase Reosurces permite acceder a recursos individules. Una instancia de la clase Reosurces
puede ser recuperado va el mtodo getRosurces() de la clase Context. Como actividades y
servicios extienden de la clase de Context, puede utilizar este mtodo directamente en las
implementaciones de estos componentes.
Una instancia de la clase de Reosurces tambin es requerida por otras clases del framework de
Android. Por ejemplo, el siguiente cdigo muestra cmo crear un archivo de Bitmap a partir de un ID de
referencia.
// BitmapFactory requires an instance of the Resource class
BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_search);

Accediendo views desde el layout en una actividad


En su actividad (y/o fragmento) el cdigo frecuentemente necesita acceder a las vistas para acceder y
modificar sus propiedades.
En una actividad se puede utilizar la llamada al mtodo findViewById(id) para buscar un punto de
vista en el layout actual. El id es el atributo de ID de la vista en el layout. El uso de este mtodo se
demuestra por el siguiente cdigo.
package com.utm.primero;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

50

TextView textView = (TextView) findViewById(R.id.action_settings);


// TODO do something with the TextView
}
}
Tambin es posible realizar bsquedas en una jerarqua de vistas con el mtodo findViewById(id), como se
demuestra en el siguiente fragmento de cdigo.
// busqueda en el layout de la actividad
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.mylayout);
// luego buscar en LinearLayout para otra vista
TextView textView = (TextView) linearLayout.findViewById(R.id.
action_settings);
// note, que se podra buscar directamente por R.id.mytext, el cdigo de
arriba
// es slo para propositos demostrativos

Referencia a recursos en archivos XML


En los archivos XML, por ejemplo, los archivos de layout, se puede hacer referencia a otros recursos a
travs del signo @.
Por ejemplo, si desea hacer referencia a un color, que se define en un XML de recurso, puede hacer
referencia a la misma a travs de @color/your_id. O si ha definido un String con la clave
"titlepage" en un XML de recurso, se puede acceder a l a travs de @string/titlepage.

Referencia a recursos del sistema Android en archivos XML


Para usar el sistema de recursos de Android, incluyendo el espacio de nombres android dentro de las
referencias, esto es, android.R.string.cancel.

Assets
Qu son los assets?
Mientras el directorio res contiene valores estructurados los cuales son conocidos por la plataforma
Android, el directorio assets puede ser usado para almacenar cualquier tipo de dato.
Se pueden acceder a los archivos almacenados en esta carpeta basandose en su ruta. El directorio
assets tambin permite tener sub- carpetas.
Nota

51

Tambin se podra almacenar datos estructurados en la carpeta /res/raw, pero es considerada buena
practica usar el directorio assets para tales datos.

Accesando assets
Para accesar a estos datos se hace va el AssetsManager el cual puede accesar va el mtodo
getAssets() desde una instancia de la clase Context.
La clase AssetsManager te permite leer un archivo en la carpeta assets como un InputStream con
el mtodo open(). El sisguiente cdifo muestra un ejemplo de esto.
// get the AssetManager
AssetManager manager = getAssets();
// read the "logo.png" bitmap from the assets folder
InputStream open = null;
try {
open = manager.open("logo.png");
Bitmap bitmap = BitmapFactory.decodeStream(open);
// assign the bitmap to an ImageView in this layout
ImageView view = (ImageView) findViewById(R.id.imageView1);
view.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (open != null) {
try {
open.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Ejercicio: Usando recursos en archivos


XML y en cdigo
Agregando imgenes y views a su proyecto
Continuamos usando el proyecto com.utm.primero.
Abrimos el archivo de layout y agregamos un nuevo Button y un ImageView a este.
Colocamos dos archivos .png de tu eleccin en la carpeta /res/drawable-xhdpi. La primera imagen
debera de llamarse inicial.png y la segunda debera ser llamada asignada.png.

Tip
Si no se tiene algn archivo .png a la mano, usa el buscador de Google para Android png files.

52

Asignando la imagen a un view imagen.


Asignar el archivo inicial.png al view Image, va el archivo layout como se muestra en el siguiente
segmento de XML.
<ImageView
android:id="@+id/myicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="93dp"
android:layout_marginTop="54dp"
android:src="@drawable/inicial" />

Agregar imgenes al proyecto


Si el botn es presionado, usar el mtodo findViewById() para buscar el ImageView. Usar su
mtodo setImageResource() para asignar el archivo png (el cual es representado en tiempo de
ejecucin va un objeto Drawable) para el ImageView.
Tip
El parametro del mtodo setImageResource() es la referencia a su archivo R , por ejemplo,
R.drawable.tu_archivo_png.

Validar
Asegurate que si presionas el nuevo botn, la imagen es reemplazada.

Ejercicio: Crear un convertidor de


temperatura.
Crear proyecto
Seleccionar File New Other... Android Android Application Project para crear un nuevo
proyecto Android con los siguientes datos
Propiedad

Valor

Nombre Aplicacin

Convertidor Temperatura

Nombre Proyecto

com.utm.android.convertidortemperatura

53

Propiedad

Valor

Nombre paquete

com.utm.android.convertidortemperatura

API (Minimum, Target, Compile with) Latest


Template

BlankActivity

Activity

MainActivity

Layout

activity_main

Tabla 7. Nuevo Proyecto Android

Despus de que el asistente termina, un proyecto con una estructura similar al de la siguiente imagen es
creado.

54

Crear atributos
Android permite crear recursos estticos para definir atributos, por ejemplo, Strings o colores. Esos
atributos pueden ser usados en otros archivos XML o por un cdigo fuente de Java.
Selecciona el archivo res/values/string.xml para editarlo. Si se quiere agregar una definicin al
archivo. Presionar el botn Add


Seleccionar la entrada Color en el siguiente dialogo y presionar el botn OK

55

Ingresar myColor como el nombre y #F5F5F5 como el valor.


Agregar ms atributos, en esta ocasin del tipo String. El atributo string pernite al desarrollador
traducir la aplicacin en un punto posterior.
Nombre

Valor

celsius

a Celsius

fahrenheit a Fahrenheit
calc

Calcular

Tabla 8. Atributos String

Cambiar a la representacin XML y validar que los valores son los correctos.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Convertidor Temperatura</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="celsius">a Celsius</string>
<string name="fahrenheit">a Fahrenheit</string>
<string name="calcular">Calcular</string>
<color name="myColor">#F5F5F5</color>
</resources>

Usando el editor de layouts

56

Seleccionar el archivo res/layout/activity_main.xml . Abrir el editos asociado va el doble-click


en el archivo. Este editor permite crear el layout atravs de arrastrar y soltar por medio del cdigo
fuente del XML. Puede cambira entre ambas representaciones por medio de las tabs en la parte inferior
del editor. Para cambiar la posicin y agrupamiento de elementos se puede usar la vista Eclipse Outline.
A continuacin se muestra una toma de pantalla del lado de la paleta del editor. Este elemento permite
arrastrar y soltar nuevos elementos View dentro de su layout. Para identificar los elementos View ms
fcilmente, se puede cambiar entre las representaciones para mostrar el icono y el texto como se ilustra
en la siguiente toma de pantalla.


Nota
La vista Paleta cambia frecuentemente, as que la vista podri ser un poco diferente.

Agregar views al archivo layout


En esta parte de los ejercicios ya podras crear la base de una interfaz de usuario para tus aplicaciones.
Click derecho en el objeto de texto existente Hello World! en el layout. Seleccionar Delete desde el
men emergente para remover el objeto de texto.
A continuacin seleccionar la seccin Text Fields en la Paleta y localizar Plain Text (va el tooltip)

57

Click en la cabecera de la seccin Text Fields para ver todos los text fields. Arrastrar el widget Plain Text
dentro del layout para crear un campo de entrada de texto.


Nota
Todas la entradas en la seccin Text Fields define campos de texto. Las diferentes entradas define
atributos adicionales para ellos, por ejemplo, si el campo de texto debera de contener solo nmeros.
A continuacin seleccionamos la seccin Form Widgets en la Paleta (Palette) y arrastar y soltar una
entrada RadioGroup dentro del layout. El nmero de radio buttons agregados al grupo de radio buttons
depende de la versin de Eclipse. Aseguremonos de que haya dos radio buttons, ya sea borrando o
agregando radio buttons al grupo.

58


Arrastrar un Button desde la seccin Form Widgets dentro del layout.
El resultado debera de lucir similar a la siguiente captura de pantalla.


Cambiando a la pestaa XML del archivo layout y verificando que el archivo luzca similar al siguiente
listado. ADT cambia los templates muy rpido, as que el XML podra lucir un poco diferente.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"

59

android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ems="10" />
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_below="@+id/editText1" >
<RadioButton
android:id="@+id/radio0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
</RadioGroup>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/radioGroup1"
android:layout_below="@+id/radioGroup1"
android:layout_marginTop="22dp"
android:text="Button" />
</RelativeLayout>

Nota
Podran verse algunos mensajes de advertencias porque se tienen algunas Strings como hard-coded.
Esto se soluciona en la siguiente seccin de este ejercicio.

Editar propiedades de las views


Se pueden agregar y cambiar propiedad de una view directamente en el archivo XML. Las herramientas
de Android tambin proporciona ayuda de contenido a travs del acceso directo Ctrl+Espacio.
Tip

60

Los atributos de una view pueden tambin ser cambiados va las view Eclipse Properties o va el men
de contexto de la view. Pero cambiar propiedades en el archivo XML es tipcamente ms rpido si sabes
lo que deseas cambiar.
Cambiando al archivo XML y asignando el valor @string/celsius a la propiedad android:text del
primer radio button. Asignar el atributo @string/fahrenheit a la propiedad android:text del
segundo radio button.
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_below="@+id/editText1"
android:layout_marginLeft="16dp"
android:layout_marginTop="41dp" >
<RadioButton
android:id="@+id/radio0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/celsius" />
<RadioButton
android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fahrenheit" />
</RadioGroup>

Nota
Desde ahora se asume que ya se es capaz de modificar las propiedades de las vistas en un archivo
layout.
Asegurarse que la propiedad Checked est puesta a true para el primer RadioButton.
Asignar @string/calc a la propiedad texto de su botn y asignar el valor onClick a la propiedad
onClick.
Poner la propiedad inputType a numberSigned y numberDecimal en el EditText. Como un
ejemplo se puede usar la ltima lnea en el siguiente segmente de XML.
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="19dp"
android:layout_marginTop="16dp"

61

android:ems="10"
android:inputType="numberSigned|numberDecimal" >

Todos los componentes de la interfaz de usuario estn contenidos en un layout. Asignar el color de
fondo a este Layout. Seleccionar Color y entonces seleccionar myColor en el dialogo. Como un
ejemplo se puede usar la ltima lnea del siguiente segmento de XML.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:background="@color/myColor" >

A continuacin el background debera de cambiar al color whitesmoke . Podra ser dificil notar la
diferencia.
Cambiar a la tab activity_main.xml y verificar que el XML est correcto.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:background="@color/myColor" >
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="19dp"
android:layout_marginTop="16dp"
android:ems="10"
android:inputType="numberSigned|numberDecimal" >
<requestFocus />
</EditText>
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_below="@+id/editText1"
android:layout_marginLeft="16dp"

62

android:layout_marginTop="41dp" >
<RadioButton
android:id="@+id/radio0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/celsius" />
<RadioButton
android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fahrenheit" />
</RadioGroup>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/radioGroup1"
android:layout_below="@+id/radioGroup1"
android:layout_marginTop="15dp"
android:onClick="onClick"
android:text="@string/calc" />
</RelativeLayout>

Crear clase utilitaria


Crear la siguiente clase utilitaria para convertir de celsius a fahrenheit y viceversa.
package com.utm.android.convertidortemperatura;
public class Convertidor {
//Convertir a Celsius
public static float convertirFahrenheitACelsius(float fahrenheit){
return ((fahrenheit - 32) * 5 / 9);
}
//Convertir a Fahrenheit
public static float convertirCelsiusAFahrenheit(float celsius){
return ((celsius * 9) / 5 ) + 32;
}
}

Cambiar el cdigo de la activity


El asistente del proyecto de Android cre la clase correspondiente MainActivity para codificar la
activity. Ajustar esta clase a lo siguiente.
package com.utm.android.convertidortemperatura;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

63

import
import
import
import

android.view.View;
android.widget.EditText;
android.widget.RadioButton;
android.widget.Toast;

public class MainActivity extends Activity {


private EditText texto;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
texto = (EditText) findViewById(R.id.editText1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is
present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onClick(View view){
switch (view.getId()) {
case R.id.button1:
RadioButton celsiusBtn = (RadioButton)
findViewById(R.id.radio0);
RadioButton fahrenheitBtn = (RadioButton)
findViewById(R.id.radio1);
if(texto.getText().length() == 0){
Toast.makeText(this, "Por favor ingrese un nmero
vlido", Toast.LENGTH_LONG).show();
return;
}
float inputValue =
Float.parseFloat(texto.getText().toString());
if(celsiusBtn.isChecked()){
texto.setText(String.valueOf(Convertidor.convertirFahrenheitACelsius(inp
utValue)));
celsiusBtn.setChecked(false);
fahrenheitBtn.setChecked(true);
}else{
texto.setText(String.valueOf(Convertidor.convertirCelsiusAFahrenheit(inp
utValue)));
fahrenheitBtn.setChecked(false);
celsiusBtn.setChecked(true);
}
break;
}
}
}

64

Nota
El onClick es llamado por un click en el botn a causa de la propiedad onClick del botn.

Iniciar aplicacin
Click derecho sobre el proyecto y seleccionar Run-As Android Application. Si un emulador an no est
corriendo, entonces se iniciar.
Escribir un nmero, seleccionar la conversin y presionar el botn. El resultado debera ser desplegadoy
la otra opcin debera ser seleccionada.

Manejador de Layouts y ViewGroups


Qu es un manejador de layouts?
Un manejador de layouts es una subclase de ViewGroup y es responsable de el mismo y de sus Views
hijos. Android soporta diferentes manejadores de layout.

Importantes manejadores de layout.


Desde Android 4.0 los manejadores de layout ms importantes son LinearLayout, FrameLayout,
RelativeLayout y GridLayout.
AbsoluteLayout est deprecado y TableLayout puede ser implementado ms eficientemente va un
GridLayout.

65

Advertencia

RelativeLayout es un manejador de layout complejo y debera ser solamamente usado si


la complejidad del layout lo requiere.
Atributos del layout
Todos los layouts permiten al desarrollador definir los atributos. Los hijos pueden tambin definir
atributos los cuales pueden ser evaluados por los layouts padres.
Los hijos pueden especificar sus ancho y alto deseado va los siguientes atributos.
Tabla 9. Definicin de alto y ancho

Atributo

Descripcin

android:layout_width Define el ancho del widget.


android:layout_height Define el alto del widget.

Los widgets pueden usar tamaos fijos, esto es, con la definicin dp, por ejemplo, 100dp. Mientras dp
es un tamao fijo este se escalar con las configuraciones de diferentes dispositivos.
El valor match_parent le dice a la aplicacin que maximise el widget al igual que si padre. El valor
wrap_content le dice al layout que asigne la cantidad mnima para que el widget est renderizado
correctamente. El efeto de esos elementos es demostrado en las siguientes grficas.

66

FrameLayout
FrameLayout es un manejador de layout el cual dibuja todos los elementos hijos uno arriba del otro.

Este permite crear agradables efectos visuales.


La siguiente captura de pantalla muestra la aplicacin de Gmail que usa el FrameLayout para desplegar
varios botones encima de otro layout.

LinearLayout
LinearLayout coloca a sus elementos hijos dentro de una simple columna o fila dependiendo del
atributo android:orientation. Los posibles valores para este atributo son horizontal y
vertical, horizontal es el valor por default.
Si horizontal es usado, los elementos hijos son dispuestos como se indica en la siguiente imagen.

67


Vertical podra resultar en un layout como se muestra en la siguiente imagen.


LinearLayout puede ser anidado para lograr layouts ms complejos.
LinearLayout soporta asignar un peso individual por hijo va el parmetro del layout
android:layout_weight. Este valor especifica cunto de espacio extra en el layout es asignado al
View. Si, por ejemplo, tienes dos widgets y el primero define un layout_weight de 1 y el segundo de

2, el primero tendr 1/3 de espacio disponible y el otro 2/3. Tambin se puede poner layout_width a
cero para tener una cierta proporcin.

RelativeLayout
RelativeLayout permite posicionar el widget relativo uno con otro. Esto puede ser usado para

layouts complejos.
Un uso simple para RelativeLayout es si se quiere centrar un simple componente. Slo se agrega un
componente al RelativeLayout y se pone el atributo android:layout_centerInParent a true.
<?xml version="1.0" encoding="utf-8"?>

68

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
</RelativeLayout>

GridLayout
GridLayout fue introducido con Android 4.0. Este layout permite orgnizar una vista dentro de un Grid.
GridLayout separa sus reas de dibujo en: filas, columnas, y celdas.

Se pueden especificar cuantas columnas se desean por cada una de las View, en cual fila o columna
debera ser colocada as como cuantas columnas y filas se deberan de usar. Si no se especifican,
GridLayout usa defaults, esto es, una columna, una fila y la posicin de una View depende del order
de la declaracin de las Views.
El siguiente archivo de layout define una layout usando GridLayout.
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/GridLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="4"
android:useDefaultMargins="true" >
<TextView
android:layout_column="0"
android:layout_columnSpan="3"
android:layout_gravity="center_horizontal"
android:layout_marginTop="40dp"
android:layout_row="0"
android:text="User Credentials"
android:textSize="32dip" />
<TextView
android:layout_column="0"
android:layout_gravity="right"
android:layout_row="1"
android:text="User Name: " >
</TextView>
<EditText
android:id="@+id/input1"

69

android:layout_column="1"
android:layout_columnSpan="2"
android:layout_row="1"
android:ems="10" />
<TextView
android:layout_column="0"
android:layout_gravity="right"
android:layout_row="2"
android:text="Password: " >
</TextView>
<EditText
android:id="@+id/input1"
android:layout_column="1"
android:layout_columnSpan="2"
android:layout_row="2"
android:ems="8" />
<Button
android:id="@+id/button1"
android:layout_column="2"
android:layout_row="3"
android:text="Login" />
</GridLayout>


Esto crea una interfaz de usuario como en la siguiente toma de pantalla.

70

ScrollView
La clase ScrollView puede ser usada para contener un View que podra ser ms grande o ancha que
la pantalla. En este caso ScrollView desplegar una barra de scroll para desplazarse en el contexto.
Por supuesto este View puede ser un layout que puede contener otros elementos.
El siguiente cdigo muestra un ejemplo de un archivo de layout el cual usa un ScrollView.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:orientation="vertical" >
<TextView
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:paddingTop="8dip"
android:text="This is a header"
android:textAppearance="?android:attr/textAppearanceLarge" >
</TextView>
</ScrollView>

El atributo android:fillViewport="true" asegura que el ScrollView es puesto para llenar la


completamente la pantalla an si los elementos son ms pequeos que la pantalla.

Ejercicio: Usando ScrollView


Este ejercicio demuestra demuestra el uso de la vista ScrollView para proveer un componente
desplazable en la interfaz de usuario. Crear un proyecto de android llamado com.utm.scrollview
con una actividad llamada ScrollViewActivity. Usar activity_main.xml como archivo de layout.
Cambiar el archivo de layout usado en la actividad como sigue:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/LinearLayout01"
android:layout_width="match_parent"
android:layout_height="wrap_content"

71

android:orientation="vertical" >
<TextView
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:paddingTop="8dip"
android:text="This is a header"
android:textAppearance="?android:attr/textAppearanceLarge" >
</TextView>
<TextView
android:id="@+id/TextView02"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:text="@+id/TextView02" >
</TextView>
<LinearLayout
android:id="@+id/LinearLayout02"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:text="Submit" >
</Button>
<Button
android:id="@+id/Button02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:text="Cancel" >
</Button>
</LinearLayout>
</LinearLayout>
</ScrollView>


Cambiar la clase ScrollViewActivity a como se muestra el siguiente cdigo.
package de.vogella.android.scrollview;
import
import
import
import

android.app.Activity;
android.os.Bundle;
android.view.View;
android.widget.TextView;

72

public class ScrollViewActivity extends Activity {


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView view = (TextView) findViewById(R.id.TextView02);
String s="";
for (int i=0; i < 500; i++) {
s += "utm.com ";
}
view.setText(s);
}
}


Iniciar su aplicacin y asegurarse que se pueda desplazar hacia abajo a los botones.

Desplegar
Revisin general
En general hay restricciones de como desplegar una aplicacin Android a tu dispositivo. Puedes usar el
USB, un correo a ti mismo con la aplicacin o usar uno de los muchos mercados de Android para instalar
la apliacin. La siguiente descripcin resalta las ms comunes.

73

Despliegue va ADT
Habilitar el USB Debugging en los settigs del dispositivo. Seleccionar Settings Development Options, y
habilitar la opcin USB-Debugging.
Podra tambier ser necesario instalar el driver para el telefono mvil. Linux y Mac OS usualmente
trabajan fuera de la caja, mientras Windows tpicamente requiere la instalacin de un driver.
Para detalles sobre la installacin en Windows por favor ver la gua Google de despliegue para
dispositivos.
Nota
La versin minima de la aplicacin Android necesita ajustarse a la versin Android de tu dispositivo.
Si se tienen varios dispositivos conectados a la computaodra, se puede seleccionar el que se desea usar.
Si solamente un dispositivo est conectado, la aplicacin es automaticamente desplegada en ese
dispositivo.

74

Exportar aplicaciones
Las aplicaciones android deben ser firmadas antes de que sean instaladas en un dispositivo Android.
Durante el desarrallo ADT firma las aplicaciones automticamente con una llave de pruebas.
Si se desea instalar la aplicacin sin el IDE de ADT, se puede hacer click derecho sobre el proyecto y
seleccionar Android Tools Export Signed Application Package.
Este asistente permite usar una llave existente o crear una nueva.
Es necesario tener en cuenta que se usa la misma llave para firmar en Google Play para las
actualizaciones de las aplicaciones. Si se pierde la llave, no se podr actualizar nunca ms la
actualizacin. Es necesario asegurarse de respaldar la llave.

Va fuentes externas
Android tambin permite instalar las aplicaciones directamente. Slo haciendo click en un una liga la
cual apunte un archivo .apk, esto es, en un adjunto de email o en una pgina web. Android preguntar
si deseas instalar dicha aplicacin.
Esti requiere que se configure en el dispositivo Android que permita la instalacin de aplicaciones que
no sean del market (Google Play). Tpicamente esta caracterstica puede ser encontrada bajo los settings
de Seguridad.

Google Play (Market)


Google Play requiere de una tarifa nica que actualmente es de 25 dlares. Despus de esto el
desarrollador ya puede directamente subir sus aplicaciones y los conos requeridos, de acuerdo a Google
Play Publishing.
Google desarrolla algunos scaneos automticos de aplicaciones, pero no hay proceso de aprobacin.
Toda aplicacin, la cual no contenga malware, ser publicado, usualmente en pocos minutos despus de
ser subido, y la aplicacin estar disponible.

Ciclo de vida de una Activity


A medida que el usuario navega a travs de, fuera de, y de regreso a su aplicacin, las instancias de las
Activities cambian entre los diferentes estados de su ciclo de vida en las transiciones de la aplicacin.
Por ejemplo, cuando su actividad se inicia por primera vez, se trata de un primer plano del sistema y
recibe la atencin del usuario. Durante este proceso, el sistema Android llama a una serie de mtodos
de ciclo de vida sobre la actividad en la que se configura la interfaz de usuario y otros componentes. Si el
usuario realiza una accin que inicia otra actividad o cambia a otra aplicacin, el sistema llama a otro
conjunto de mtodos de ciclo de vida en su activity a medida que avanza hacia el fondo (donde la
actividad ya no es visible, pero la instancia y su estado permanecen intactos).

75

Dentro de los mtodos de llamadas del ciclo de vida, puedes declarar cmo se comportar tu activity
cuando el usuario abandone o reingrese a la activity. Por ejemplo, si se est construyendo un
reproductor de vdeo con streaming, se podra hacer una pausa al vdeo y terminar la conexin de red
cuando el usuario cambia a otra aplicacin. Cuando el usuario vuelve, puede volver a conectarse a la red
y permitir al usuario reanudar el vdeo desde el mismo punto.

Entendiendo el flujo del ciclo de vida


Durante la vida de una actividad, el sistema llama a un conjunto bsico de los mtodos de ciclo de vida
en una secuencia similar a una pirmide escalonada. Es decir, cada etapa del ciclo de actividad es un
paso separado en la pirmide. A medida que el sistema crea una nueva instancia de una activity, cada
mtodo de devolucin de llamada mueve el estado de activity un paso hacia la cima. La parte superior
de la pirmide es el punto en el que la actividad se ejecuta en el primer plano y el usuario puede
interactuar con l (Imagen 8).


Imagen 8

Dependiendo de la complejidad de la actividad, probablemente no es necesario implementar todos los


mtodos del ciclo de vida. Sin embargo, es importante que se entienda cada uno y ponerlos en prctica
garantiza que la aplicacin se comporte de la forma en que los usuarios esperan. La implementacin de
los mtodos de ciclo de vida de la activity apropiadamente asegura que la aplicacin se comporte bien
en varias situaciones, incluyendo que:

No bloquee si el usuario recibe una llamada telefnica o cambia a otra aplicacin mientras se
utiliza la aplicacin.
No consume valiosos recursos del sistema cuando el usuario no est usando activamente.
No pierde el progreso del usuario si salen de su aplicacin y volver a ella ms adelante.
No bloquee o perder el progreso del usuario cuando la pantalla cambia entre orientacin
vertical u horizontal.

76

Hay varias situaciones en las que las transiciones de una activity entre los diferentes estados ocurren
como se ilustran en la Imagen 8. Sin embargo, slo tres de estos estados puede ser esttico. Es decir, la
activity puede existir en uno de los tres estados para un perodo de tiempo prolongado:

Resumed: En este estado, la activity est en el primer plano y el usuario puede interactuar con
l. (Tambin se refiere a veces como el estado "corriendo").
Paused: En este estado, la activity est parcialmente oculta por otra activity, la otra activity que
est en el primer plano es semi-transparente o no cubre toda la pantalla. La activity que se
detuvo no recibe la entrada del usuario y no se puede ejecutar ningn cdigo.
Stopped: En este estado, la activity est completamente oculta y no visible para el usuario, sino
que se considera que est en el fondo. Mientras est detenida, la instancia de la activity y toda
la informacin de su estado como variables de miembros se mantiene, pero no se puede
ejecutar ningn cdigo.

Los otros estados (creado e iniciado) son transitorios y el sistema rpidamente cambia de ellos al
siguiente estado llamando al siguiente ciclo de vida. Es decir, despus de que el sistema llama onCreate
(), rpidamente se llama OnStart (), que rpidamente es seguido por onResume ().

Creacin y manejo de Base de Datos


Existen dos formas para la creacin o utilizacin de bases de datos en Android:
1. Disear y crear la base de datos de manera externa usando alguna aplicacin (en este caso
Navicat).
2. Utilizacn de la clase SQLiteOpenHelper para crear la estructura de la base de datos desde
el cdigo.

Crear la BD con SQLite en Navicat.


1. Lo primero que hay que hacer es abrir el Navicat y crear una nueva conexin a una base de
datos SQLite, como vemos en la Imagen 9

77


Imagen 9

2. Escoger un nombre a la conexin en nuestro caso se llamar bd_alumnos, en la seccin Type


seleccionar la opcin New SQLite 3, y en la seccin de Database File debemos de especificar un
lugar donde guardaremos nuestra base de datos recientemente creada as mismo como el
nombre que le queremos dar al archivo en la Imagen 10 se muestra como queda configurada mi
base de datos.


Imagen 10

3. Para crear la tabla que requerimos hacemos doble-click en la nueva conexin recin creada,
despus aparece una opcin que dice main, tambin a esta le damos doble-click y se

78

despliegan varias opciones en la que dice Tables hacemos click con el botn derecho y del men
desplegable seleccionamos la opcin New Table (Ver Imagen 11).


Imagen 11

4.

Crearemos los campos que llevar la BD, debe de quedar igual a como se muestra en la
Imagen 12.


Imagen 12

5. Ahora crearemos una ndice, esto es necesario que sea realizado para todas las llaves primarias
que sean creadas con auto incremento, para realizar esto seleccionamos la pestaa Indexes, en

79

la columna Name pondremos un nombre al ndice en este caso ser id_alumno, en la columna
Fields al seleccionarla cambia a como se muestra en la Imagen 13 y damos un click al botn
encerrado en el cuadro rojo.


Imagen 13

6. En la ventana que es mostrada ahora, ver Imagen 14, marcamos el checkbox de la llave primaria
y en la columna Sort Order, seleccionamos la opcin ASC y aceptamos los cambios dando click
en el botn encerrado en el cuadro rojo.


Imagen 14


7. Al guardar las modificaciones si no exista previamente la tabla entonces nos pide que le
pongamos un nombre a la tabla as como se muestra en la Imagen 15.

80


Imagen 15

8. En este punto al crear la nueva tabla ctl_alumnos se crea una tabla dinmica sqlite_sequence,
esta tabla lleva el control de la secuencia de las llaves principales, por favor de no modificar esta
tabla (Imagen 16).


Imagen 16

9. Android solicita que la base de datos incluya una tabla que se llama android_metadata, esta
tabla debe de contener un solo campo de nombre locale y en la Imagen 17 se muestra cmo
debe de quedar configurada dicha tabla.

81


Imagen 17

Cargar la base de datos en el proyecto de Android


1. En este punto es necesario recordar la ubicacin en la que guardamos nuestra base de datos,
porque necesitamos copiar dicho archivo a la carpeta /res/assets del proyecto android que
estemos trabajando, esto lo podemos realizar desde el navegador de archivos del sistema
operativo que estemos usando. Ya copiado el archivo, que para casos prctico nuestro archivo
se debera de llamar bd_alumnos.bd, en la Imagen 18 vemos un ejemplo de cmo debera de
verse la estructura de archivos de nuestro proyecto despus de copiar el archivo.


Imagen 18

82

Cargar la base de datos en la aplicacin para poder usarla


1. Lo primero ser crear un paquete nuevo para separar los archivos relacionados con el manejo
de base de datos de los del manejo de las activities, el nombre del nuevo paquete ser
com.demo.proyectodemo.db.
2. Ahora crearemos la clase java DataBaseManager.java la cual tendr varias funciones y/o
mtodos:
Mtodo
DataBaseManager(Context
context)
createDataBase()
checkDataBase()
copyDataBase()

openDataBase()
close()

Funcionalidad
Constructor
Crea una base de datos vaca en el sistema y la reescribe con tu propia
base de datos
Verifica si la base de datos ya existe para evitar re-copiar el archivo
cada vez que abres la aplicacin
Copia tu base de datos desde la carpeta local assets a la base de datos
vaca recientemente creada en el sistema de carpetas, para que pueda
ser accesada y manipulada. Esto es hecho por transferencia de flujo de
bytes
Abre la base de datos
Cierra la base de datos
Tabla 10

3. Lo primero que haremos ser declarar unas variables globales que sern utilizadas en diferentes
partes de la clase, como se muestra en la Imagen 19.


Imagen 19

4. Lo siguiente que haremos ser declarar el constructor de la clase como lo vemos en la Imagen
20.

83


Imagen 20

5. Ahora crearemos una mtodo que verificar si la base de datos ya existe, esta clase solo regresa
true si ya existe o false en caso de no existir, dicho mtodo se llamar checkDataBase(), el
cdigo necesario en esta clase se muestra en la Imagen 21.


Imagen 21

6. El siguiente mtodo necesario es uno que nos ayude a copiar la base de datos que tenemos en
la carpeta assets al sistema de archivos del proyecto para que pueda ser usada y manipulada
nuestra base de datos, este mtodo tendr el nombre copyDataBase(), y la copia del archivo de
la base de datos desde assets haca el sistema de archivos de la aplicacin se realiza a travs de
un flujo de bytes, el cdigo de dicho mtodo lo podemos ver en la Imagen 22.

84


Imagen 22

7. Los dos mtodos anteriores son necesarios puesto que son utilizados por el mtodo
createDataBase() ya que primero valida si la base de datos ya existe y en caso de que no exista
entonces copia la base de datos. Esto lo podemos ver en la Imagen 23.


Imagen 23

85

8. Por ltimo falta agregar dos mtodos muy importantes para abrir y cerrar la base de datos,
estos mtodos son openDataBase() y close(), en la Imagen 24 podemos observar el cdigo de
estos dos mtodos.


Imagen 24


9. Ahora que ya tenemos todo lo necesario para agregar nuestra base de datos a nuestra
aplicacin ser necesario que creemos un mtoodo que inicie todo el proceso de revisin y
creacin de la base de datos, una buena opcin es hacerlo en el momento en el que se pone en
marcha la aplicacin, digamos que podemos crear un Splash y en este momento hacer lo
relacionado con la base de datos, esto con ayuda de la clase AsyncTask
10. Lo primero ser crear una activity llamada SplashScreen.java, y declararla como la
pantalla de inicio de nuestra aplicacin dentron del Manifest de nuestra aplicacin (en realidad
el Asynctask lo podemos usar en el momento que lo deseemos, podramos no usar una pantalla
de Splash, y hacerlo directamente en nuestra pantalla de inicio, esto es a decisin suya y de las
necesidades del proyecto).
11. Ahora es cuestin y decisin de su proyecto como disear la interfaz del layout del Splash que se
a creado, activity_splash_screen.xml, por cuestiones de economa de tiempo yo lo
disear muy simple:

86

12.
Y quedando el layout activity_splash_screen.xml
continuacin:

como se muestra a

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="#CECECE"
tools:context=".SplashScreen" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/hello_world"
android:textSize="40sp" />
</RelativeLayout>

87

13. El cdigo de la clase SplashScreen.java es muy simple, en el mtodo onCreate()se


carga el layout que se va a utilizar y se manda llamar a la subclase interna priva que se creeo
dentro de esta actividad.
14. Ya en la sublcase sobreescribimos los mtodos doInBackground y onPostExecute, en el
primero mtodo es donde se crea un hilo que en este caso ser el que se encargue de ejecutar
el mtodo de comprobar si ya existe la base de datos o hay que crearla, el segundo mtodo
indica que es lo que se har en el momento que se haya terminado de ejecutar el hilo, en
nuestro caso slo carga la siguiente activity.
15. Y este es el cdigo final que tenemos:
import java.io.IOException;
import com.utm.primero.database.DataBaseManager;
import
import
import
import
import

android.os.AsyncTask;
android.os.Bundle;
android.app.Activity;
android.content.Intent;
android.view.Menu;

public class SplashScreen extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
/*
* Se manda llamar o ejecutar la subclase que hereda
* de la clase AsynTask
* */
new VerificarBaseDatos().execute();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it
is present.
getMenuInflater().inflate(R.menu.splash_screen, menu);
return true;
}
/*
* Creamos la subclase que hereda de AsyncTask
* */
private class VerificarBaseDatos extends AsyncTask<Void, Void,

88

Void> {
/*
* No realizamos nada en el mtodo onPreExecute
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/*
* En el mtodo doInBackground es el momento
* donde verificaremos la existencia de la base de datos
* */
@Override
protected Void doInBackground(Void... params) {
DataBaseManager myDbHelper = new
DataBaseManager(SplashScreen.this);
try {
myDbHelper.createDataBase();
} catch (IOException e) {
throw new Error("Imposible crear la base de
datos");
}
return null;
}
/*
* Al momento de terminar la ejecucin del mtodo
* doInBackground ser momento de ejecutar al mtodo
* onPostExecute*/
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Despus de ejecutar la verificacin de la base de
datos
// cerrarremos esta actividad y lanzaremos la nnueva
actividad
Intent i = new Intent(SplashScreen.this,
MainActivity.class);
startActivity(i);
// cerrar definitivamente esta actividad
// para evitar que en el momento de dar Back se
ejecute de nuevo
}
}
}
16. Cabe recordar o hacer notar algunas cosas:

89

a. Esta es slo una forma de poder verificar si ya existe la base de datos instalada en
nuestro telfono, no basta con que la base de datos este en el proyecto o en la
aplicacin, tienen que estar instalada en el telfono y esto es lo que hace todo este
procedimiento.
b. La clase AsyncTask es una forma mucho ms fcil de hacer tareas asncronas, y puede
ser utiizada en cualquier parte de nuestro sistema, no solo en el splash o para verificar
que la base de datos est ya instalada.

Creacin de la Base de Datos con cdigo desde la aplicacin


Al tener ya creado algn proyecto que pueda utilizar o necesitar una base de datos de SQLite ser
necesario que creemos un nuevo paquete para guardar las clases que manejarn la base de datos. Como
caso de ejemplo se crear el paquete com.example.tareasqlite.database (claro, siempre y
cuando ya tengamos hecho un proyecto, en caso de no tenerlo debemos de iniciar un proyecto nuevo).
En este caso se crearn dos clases DataBaseHelper.java y DBAdapter.java como se muestra
en la siguiente imagen


Veamos que contienen las clases que acabamos de crear, la primera en analizar es la clase
DataBaseHelper.java dicha clase extiende (hereda) de la clase SQLiteOpenHelper. A
continuacin tenemos el contenido completo de la clase la cul vamos a ir explicando lneas abajo:
package com.example.tareasqlite.database;
import
import
import
import

android.content.Context;
android.database.sqlite.SQLiteDatabase;
android.database.sqlite.SQLiteOpenHelper;
android.util.Log;

public class DataBaseHelper extends SQLiteOpenHelper {


private static final String DATABASE_NAME = "applicationdata";
private static final int DATABASE_VERSION = 1;
//Sentencia para crear la BD
private static final String DATABASE_CREATE = "create table todo

90

(_id integer primary key autoincrement, "


+ "categoria text not null, resumen text not null,
descripcion text not null);";
public DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//Este mtodo es llamado cuando se crea la BD
@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE);
}
//Mtodo que se llama cada vez que se actualiza la BD
//Incrementa la versin
@Override
public void onUpgrade(SQLiteDatabase database, int oldVersion,
int newVersion) {
Log.w(DataBaseHelper.class.getName(),
"Actualizando la BD desde la versin " +
oldVersion + " a "+ newVersion + ", la cual destruir todos los datos
viejos");
database.execSQL("DROP TABLE IF EXISTS todo");
onCreate(database);
}
}

Esta clase bsicamente nos ayudar a definir la estructura de la base de datos. Al inicio de la clase
creamos tres constantes: un String llamado DATABASE_NAME que define el nombre de la base de
datos, un int llamado DATABASE_VERSION que pasar el nmero de versin de la base de datos
cuando es creada, y la consulta que nos servir para crear la base de datos.
Todo esto se define desde el constructor que se encuentra lneas abajo en esta clase.
El mtodo onCreate() es el que ejecuta la consulta CREATE para la base de datos. Por otro lado, el
mtodo onUpgrade() manejaremos todas las acciones que necesitemos cada vez que se actualice la
base de datos; en este caso, nicamente estamos mandando mensajes en el Log.
Ahora, pasemos a la clase DBAdapter.java que es la que contendr toda la funcionalidad para
realizar consultas, crear y editar cada uno de los items que manejar la aplicacin.
import
import
import
import
import

android.content.ContentValues;
android.content.Context;
android.database.Cursor;
android.database.SQLException;
android.database.sqlite.SQLiteDatabase;

91

public class DBAdapter {


//Campos de la BD
public static final String KEY_ROWID = "_id";
public static final String KEY_CATEGORY = "categoria";
public static final String KEY_SUMMARY = "resumen";
public static final String KEY_DESCRIPTION = "descripcion";
private static final String DATABASE_TABLE = "todo";
private Context context;
private SQLiteDatabase database;
private DataBaseHelper dbHelper;
public DBAdapter(Context context) {
this.context = context;
}
public DBAdapter open() throws SQLException{
dbHelper = new DataBaseHelper(context);
database = dbHelper.getWritableDatabase();
return this;
}
public void close(){
dbHelper.close();
}
/**
*
* Crea una nueva tarea, si esto va bien retorna
* la rowId de la tarea, de lo contrario retorna -1
*
* */
public long crearNuevaTarea(String categoria, String resumen,
String descripcion){
ContentValues inicialValues = crearContentValues(categoria,
resumen, descripcion);
return database.insert(DATABASE_TABLE, null, inicialValues);
}
//Actualiza la tarea
public boolean updateTarea(long rowId, String categoria, String
resumen, String descripcion){
ContentValues actulizaValues = crearContentValues(categoria,
resumen, descripcion);
return database.update(DATABASE_TABLE,actulizaValues,
KEY_ROWID + "=" +rowId, null) > 0;
}

92

//Borrar la tarea
public boolean deleteTarea(long rowId){
return database.delete(DATABASE_TABLE, KEY_ROWID + "="
+rowId, null) > 0;
}
// Retorna un cursor que contiene todos los items
public Cursor recuperaTodos(){
String[] columnas = {KEY_ROWID, KEY_CATEGORY, KEY_SUMMARY,
KEY_DESCRIPTION};
return database.query(DATABASE_TABLE, columnas, null, null,
null, null, null);
}
// Retorna un Cursor que contiene la info de una tarea
public Cursor recuperaTarea(long rowId) throws SQLException{
String[] columnas = {KEY_ROWID, KEY_CATEGORY, KEY_SUMMARY,
KEY_DESCRIPTION};
Cursor mCursor = database.query(true, DATABASE_TABLE,
columnas, KEY_ROWID + "=" +rowId, null, null, null, null, null);
if(mCursor != null){
mCursor.moveToFirst();
}
return mCursor;
}
private ContentValues crearContentValues(String categoria, String
resumen,
String descripcion) {
ContentValues values = new ContentValues();
values.put(KEY_CATEGORY, categoria);
values.put(KEY_DESCRIPTION, descripcion);
values.put(KEY_SUMMARY, resumen);
return values;
}
}
Vamos a explicar cada uno de los mtodos que estamos creando. La primera parte corresponde a la
creacin de las constantes y variables que vamos a utilizar. Las constantes son cada una de las columnas
de la tabla que almacenar la informacin de la aplicacin. Despus tenemos tres variables que
corresponden al contexto de la aplicacin, a la base de datos y al helper para manipular las consultas y
funciones con SQLite.
En el constructor nicamente definiremos el contexto de la aplicacin. Despus, tenemos el mtodo
open() que sirve para preparar la base de datos a modo que podamos escribir datos en ella, para ello

93

se abre la base de datos a travs del objeto de tipo DBHelper. En este mtodo ocupamos una
SQLException pues es probable que a veces ocurran errores en esta parte y esto nos servir para
conocerlos. El mtodo close() sirve para cerrar el helper. Si has trabajado con Java y MySQL, vers
que es algo muy parecido a lo que tenemos que hacer para manejar bases de datos a travs de un
conector.
Posteriormente, tenemos los mtodos para crear, actualizar, borrar y consultar los elementos de la base
de datos a travs de la clase ContentValues nos permitirn crear y actualizar valores dentro de la
base de datos. A travs de esta clase podemos manipular la correspondencia entre identificador/valor,
utilizando el nombre de la columna como el identificador al cul nicamente le definiremos el valor para
actualizar o crear un nuevo elemento dentro de la base de datos.

Manejo de SQLite en Android


SQLite es un motor de bases de datos muy popular en la actualidad por ofrecer caractersticas tan
interesantes como su pequeo tamao, no necesitar servidor, precisar poca configuracin, ser
transaccional y por supuesto ser de cdigo libre.
Android incorpora de serie todas las herramientas necesarias para la creacin y gestin de bases de
datos SQLite, y entre ellas una completa API para llevar a cabo de manera sencilla todas las tareas
necesarias. Por el momento nos limitaremos a ver el cdigo necesario para crear una base de datos,
insertaremos algn dato de prueba, y veremos cmo podemos comprobar que todo funciona
correctamente.
Por el momento hemos visto dos formas de crear y/o utilizar una base de datos SQLite en Android, ms
adelante en este manual veremos la forma de utilizar el segundo mtodo (Creacin de la Base de Datos
con cdigo desde la aplicacin) en un proyecto de ejemplo.

SQLiteOpenHelper
Para crear y trabajar con bases de datos en Android, es necesario hacer uso de la clase
SQLiteOpenHelper. En esta clase es necesario sobrescribir los mtodos onCreate() para crear la base
de datos, y onUpgrade() para actualizar la base de datos en caso de que existan cambios en el
esquema de la misma. Ambos mtodos reciben como parmetro un objeto SQLiteDatabase.
SQLiteOpenHelper
ofrece
los
mtodos getReadableDatabase()
y
getWriteableDatabase() para trabajar con un objeto SQLiteDatabase y poder tener acceso
de lectura y escritura sobre una base de datos.

SQLDatabase y Cursor
La clase SQLiteDatabase provee los mtodos insert(), update() y delete() y execSQL()
que nos ayuda a ejecutar sentencias SQL directamente. El objeto ContentValues permite definir claves y
valores en las sentencias Insert y Update. La clave (key) corresponde a la columna y el valor es el
valor para la columna.

94

Las consultas se pueden crear a travs del mtodo rawQuery() que acepta como parmetro una
sentencia en SQL o el mtodo query() que proporciona una interfaz para especificar los datos
dinmicos o un objeto de tipo SQLiteQueryBuilder. SQLiteBuilder es similar a la interfaz de un proveedor
de contenidos por lo que suele utilizarse con Content Providers. Hay que saber tambin que toda
consulta que realicemos nos retornar un objeto de tipo Cursor.
Para definir la llave primaria de una base de datos es indispensable hacer uso del identificador _id ya
que muchas de las funciones con las que trabajaremos toman en cuenta este estndar.
En Android, la forma tpica para crear, actualizar, y conectar con una base de datos SQLite ser a travs
de una clase auxiliar llamada SQLiteOpenHelper, o para ser ms exactos, de una clase propia que derive
de ella y que debemos personalizar para adaptarnos a las necesidades concretas de nuestra aplicacin.
La API de SQLite de Android proporciona dos alternativas para realizar operaciones sobre la base de
datos que no devuelven resultados (entre ellas la insercin/actualizacin/eliminacin de registros, pero
tambin la creacin de tablas, de ndices, etc).
El primero de ellos, es el mtodo execSQL() de la clase SQLiteDatabase. Este mtodo permite ejecutar
cualquier sentencia SQL sobre la base de datos, siempre que sta no devuelva resultados. Para ello,
simplemente aportaremos como parmetro de entrada de este mtodo la cadena de texto
correspondiente con la sentencia SQL.
La segunda de las alternativas disponibles en la API de Android es utilizar los mtodos insert(), update()
y delete() proporcionados tambin con la clase SQLiteDatabase. Estos mtodos permiten realizar las
tareas de insercin, actualizacin y eliminacin de registros de una forma algo ms paramtrica que
execSQL(), separando tablas, valores y condiciones en parmetros independientes de estos mtodos.
Empecemos por el mtodo insert() para insertar nuevos registros en la base de datos. Este mtodo
recibe tres parmetros, el primero de ellos ser el nombre de la tabla, el tercero sern los valores del
registro a insertar, y el segundo lo obviaremos por el momento ya que tan slo se hace necesario en
casos muy puntuales (por ejemplo para poder insertar registros completamente vacos), en cualquier
otro caso pasaremos con valor null este segundo parmetro.
Los valores a insertar los pasaremos como elementos de una coleccin de tipo ContentValues. Esta
coleccin es de tipo diccionario, donde almacenaremos parejas de clave-valor, donde la clave ser el
nombre de cada campo y el valor ser el dato correspondiente a insertar en dicho campo. Veamos la
Imagen 26:


Imagen 25

95

Los mtodos update() y delete() se utilizarn de forma muy parecida a sta, con la salvedad de que
recibirn un parmetro adicional con la condicin WHERE de la sentencia SQL. Por ejemplo, para
actualizar el email del usuario de nombre usu1 haramos lo siguiente:


Imagen 26

Como podemos ver, como tercer parmetro del mtodo update() pasamos directamente la condicin
del UPDATE tal como lo haramos en la clusula WHERE en una sentencia SQL normal. El mtodo
delete() se utilizara de forma anloga. Por ejemplo para eliminar el registro del usuario usu2 haramos
lo siguiente:


Imagen 27

Como vemos, volvemos a pasar como primer parmetro el nombre de la tabla y en segundo lugar la
condicin WHERE. Por supuesto, si no necesitramos ninguna condicin, podramos dejar como null en
este parmetro.
Un ltimo detalle sobre estos mtodos. Tanto en el caso de execSQL() como en los casos de update() o
delete() podemos utilizar argumentos dentro de las condiciones de la sentencia SQL. Esto no es ms que
partes variables de la sentencia SQL que aportaremos en un array de valores aparte, lo que nos evitar
pasar por la situacin tpica en la que tenemos que construir una sentencia SQL concatenando cadenas
de texto y variables para formar el comando SQL final. Estos argumentos SQL se indicarn con el smbolo
?, y los valores de dichos argumentos deben pasarse en el array en el mismo orden que aparecen en la
sentencia SQL. As, por ejemplo, podemos escribir instrucciones como la siguiente:


Imagen 28

Esta forma de pasar a la sentencia SQL determinados datos variables puede ayudarnos adems a escribir
cdigo ms limpio y evitar posibles errores.

96

De forma anloga a lo que vimos para las sentencias de modificacin de datos, vamos a tener dos
opciones principales para recuperar registros de una base de datos SQLite en Android. La primera de
ellas utilizando directamente un comando de seleccin SQL, y como segunda opcin utilizando un
mtodo especfico donde parametrizremos la consulta a la base de datos.
Para la primera opcin utilizaremos el mtodo rawQuery() de la clase SQLiteDatabase. Este mtodo
recibe directamente como parmetro un comando SQL completo, donde indicamos los campos a
recuperar y los criterios de seleccin. El resultado de la consulta lo obtendremos en forma de cursor,
que posteriormente podremos recorrer para procesar los registros recuperados. Sirva la siguiente
consulta a modo de ejemplo:

Imagen 29

Como en el caso de los mtodos de modificacin de datos, tambin podemos aadir a este mtodo una
lista de argumentos variables que hayamos indicado en el comando SQL con el smbolo ?, por ejemplo
as:


Imagen 30

Como segunda opcin para recuperar datos podemos utilizar el mtodo query() de la clase
SQLiteDatabase. Este mtodo recibe varios parmetros: el nombre de la tabla, un array con los nombre
de campos a recuperar, la clusula WHERE, un array con los argumentos variables incluidos en el WHERE
(si los hay, null en caso contrario), la clusula GROUP BY si existe, la clusula HAVING si existe, y por
ltimo la clusula ORDER BY si existe. Opcionalmente, se puede incluir un parmetro al final ms
indicando el nmero mximo de registros que queremos que nos devuelva la consulta. Veamos el
mismo ejemplo anterior utilizando el mtodo query():


Imagen 31

Como vemos, los resultados se devuelven nuevamente en un objeto Cursor que deberemos recorrer
para procesar los datos obtenidos.
Para recorrer y manipular el cursor devuelto por cualquiera de los dos mtodos mencionados tenemos a
nuestra disposicin varios mtodos de la clase Cursor, entre los que destacamos dos de los dedicados a
recorrer el cursor de forma secuencial y en orden natural:

moveToFirst(): mueve el puntero del cursor al primer registro devuelto.

97

moveToNext(): mueve el puntero del cursor al siguiente registro devuelto.

Los mtodos moveToFirst() y moveToNext() devuelven TRUE en caso de haber realizado el movimiento
correspondiente del puntero sin errores, es decir, siempre que exista un primer registro o un registro
siguiente, respectivamente.
Una vez posicionados en cada registro podremos utilizar cualquiera de los mtodos
getXXX(ndice_columna) existentes para cada tipo de dato para recuperar el dato de cada campo del
registro actual del cursor. As, si queremos recuperar por ejemplo la segunda columna del registro
actual, y sta contiene un campo alfanumrico, haremos la llamada getString(1) [NOTA: los ndices
comienzan por 0, por lo que la segunda columna tiene ndice 1], en caso de contener un dato de tipo
real llamaramos a getDouble(1), y de forma anloga para todos los tipos de datos existentes.
Con todo esto en cuenta, veamos cmo podramos recorrer el cursor devuelto por el ejemplo anterior:


Imagen 32

Adems de los mtodos comentados de la clase Cursor existen muchos ms que nos pueden ser tiles
en muchas ocasiones. Por ejemplo, getCount() te dir el nmero total de registros devueltos en el
cursor, getColumnName(i) devuelve el nombre de la columna con ndice i, moveToPosition(i) mueve el
puntero del cursor al registro con ndice i, etc. Podemos consultar la lista completa de mtodos
disponibles en la clase Cursor en la documentacin oficial de Android.

Creando un Navigation Drawer


No hace mucho para poder implementar este en nuestras aplicaciones de Android uno mismo
deba implementar toda la funcionalidad por su cuenta o utilizar alguna librera de alguien ya lo halla
hecho. Pero por suerte en el ultimo Google I/O 2013 se anuncio oficialmente que se incluira dentro de
la support library una funcionalidad llamada Navigation Drawer que es la que justamente nos permite
implementar esto, gracias a esto podemos dotar a nuestras apps desde versiones antiguas de Android
esta funcionalidad.

98

Lo primero que debemos de hacer es asegurarnos de que tenemos la versin r19.0.1 de Android
Support Library en el SDK Manager, en el caso de no tenerlo debemos de instalarla desde el SDK
Manager.


Nota
Para casos de este manual supondremos que ya tenemos un proyecto creado, en el caso de que no sea
as ser necesario que se cree uno nuevo y seguir el manual desde este punto.


Despus de verificar de que tenemos la Support Library instalada y disponible para nuestro proyecto
vamos a crear nuestro layout que ser el esqueleto de nuestra UI.
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Vista para el contenido principal -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"/>
<!-- Navigation Drawer -->
<ListView
android:id="@+id/drawerIzquierdo"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="#E5E5E5" >
</ListView>
</android.support.v4.widget.DrawerLayout>
El contenedor principal es el DrawerLayout este bsicamente es el que permite deslizar la vista en este
caso ser el ListView.

99

La posicin de
deslizamiento
dentro
del
layout
es
controlado
por
la
sig.
propiedad android:layout_gravity este puede ser: left , right o start y end.
Para darnos una idea al finalizar el tutorial seremos capaces
de implementar una
UI de este tipo.




FrameLayout

ListView



Como ven dentro del FrameLayout ira el contenido principal mientras que el Listview ser el que se
desplace horizontalmente ya sea clickeando en el botn del ActionBar o arrastrndolo tocando la
pantalla.
Ahora vamos a la parte de la Activity principal
import
import
import
import
import

android.app.Activity;
android.os.Bundle;
android.support.v4.widget.DrawerLayout;
android.view.Menu;
android.widget.ListView;

public class MainActivity extends Activity {


private ListView mDrawerList;
private DrawerLayout mDrawerLayout;
@Override

100

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Drawer Layout
mDrawerLayout = (DrawerLayout)
findViewById(R.id.drawer_layout);
//Lista
mDrawerList = (ListView) findViewById(R.id.drawerIzquierdo);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it
is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Es muy simple, con solamente declarar el layout ya funcionaria, en este caso declaramos el
DrawerLayout y ListView.
Si corremos la app en este punto y deslizamos el dedo de forma horizontal desde el extremo izquierdo
de la pantalla hacia dentro veremos como se desplaza el men, en este punto todava no se incluyo el
contenido del ListView ni el ActionBar.

101


A continuacin veremos el diseo del Men Vertical y como agregar opciones, el manejo de esto es
igual que en cualquier aplicacin comn definiendo su layout, implementar un Adaptador especifico
para este en el caso que fuese necesario, etc..
Diseo:
La idea es que por mas que sea un ejemplo puedan adquirir conocimientos para dotar a sus aplicaciones
con una interfaz moderna similar a las que ya todos conocemos, obviamente no llegaremos a tanto ya
que se necesita mucho diseo pero podemos tratar de inspirarnos de ellas, en este caso est basado en
la de Google+ como lo vemos en la siguiente imagen.

102


Para nuestro ejemplo lo que tendremos es lo siguiente:



encabezado_drawer.xml

item_drawer.xml






103

Como se puede ver al principio se incluye un header que solamente cumple una funcin esttica pero
podra incluirse la foto de perfil del usuario, nombre, etc. Mas adelante veremos como integrarlos
dentro del ListView.
/res/layout/encabezado_drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/headerBackground"
android:layout_width="fill_parent"
android:layout_height="150dp"
android:scaleType="centerCrop"
android:src="@drawable/header" />
</FrameLayout>
Como podemos ver nada del otro mundo un FrameLayout con una imagen dentro.
/res/layout/tem_drawer.xml

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/icon"
android:layout_width="25dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/title_item"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/icon"
android:textColor="#111"
android:gravity="center_vertical"
android:paddingRight="40dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"

104

android:text="@string/app_name" />
</RelativeLayout>

Para pode agregar opciones al men se agregan tanto las opciones como la imagen que cada botn
debe tener dentro del /res/values/string.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ToDoSQLite</string>
<string name="hello_world">Hello world!</string>
<string name="title_activity_tareas">TareasActivity</string>
<!-- Lista de elementos que aparecen en la navegacin -->
<string-array name="nav_options">
<item >ToDo</item>
<item >Conversor</item>
<item >Perfil</item>
<item >Configuracin</item>
<item >Conversor</item>
</string-array>
<!-- Lista de iconos de navegacion -->
<string-array name="nav_iconos">
<item >@drawable/ic_action_go_to_today</item>
<item >@drawable/ic_action_merge</item>
<item >@drawable/ic_action_person</item>
<item >@drawable/ic_action_good</item>
<item >@drawable/ic_action_cloud</item>
</string-array>
</resources>
En la primera seccin he declarado un array de Strings nav_options luego otro de drawables
nav_iconos, esta es una forma fcil y rpida de poder declarar estos aunque tambin pudo haberse
declarado mediante java en la actividad principal, en el caso que el contenido
fuese dinmico esta opcin del xml no seria viable.
Para poder facilitar el uso del men en el adaptador que veremos luego he creado una clase llamada
Items.java en esta bsicamente se declaran los mtodos para asignarle un nombre y una imagen.
public class Items {
private String titulo;
private int icono;
public Items(String titulo, int icono) {
this.titulo = titulo;
this.icono = icono;
}

105

public String getTitulo() {


return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public int getIcono() {
return icono;
}
public void setIcono(int icono) {
this.icono = icono;
}
}
Volviendo a nuestra activity prinicipal aadiremos el resto de cogido para obtener los datos desde el
archivos strings.xml:
import java.util.ArrayList;
import
import
import
import
import
import
import

android.app.Activity;
android.content.res.TypedArray;
android.os.Bundle;
android.support.v4.widget.DrawerLayout;
android.view.Menu;
android.view.View;
android.widget.ListView;

public class MainActivity extends Activity {


private String[] titulos;
private ListView mDrawerList;
private ArrayList<Items> NavItems;
TypedArray NavIconos;
NavigationAdapter NavAdapter;
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Drawer Layout
mDrawerLayout = (DrawerLayout)
findViewById(R.id.drawer_layout);
//Lista
mDrawerList = (ListView) findViewById(R.id.drawerIzquierdo);

106

//Declaramos el header el cual ser el layout de


encabezado_drawer.xml
View encabezado =
getLayoutInflater().inflate(R.layout.encabezado_drawer, null);
//Establecer el encabezado
mDrawerList.addHeaderView(encabezado);
//Tomamos listado de imgs desde drawable
NavIconos =
getResources().obtainTypedArray(R.array.nav_iconos);
//Tomamos listado de titulos desde el string-array de los
recursos @string/nav_options
titulos = getResources().getStringArray(R.array.nav_options);
//Listado de titulos de barra de navegacin
NavItems = new ArrayList<Items>();
//Agregamos objetos Item_objct al array
//ToDo
NavItems.add(new Items(titulos[0], NavIconos.getResourceId(0,
-1)));
//Conversor
NavItems.add(new Items(titulos[1], NavIconos.getResourceId(1,
-1)));
//Eventos
NavItems.add(new Items(titulos[2], NavIconos.getResourceId(2,
-1)));
//Lugares
NavItems.add(new Items(titulos[3], NavIconos.getResourceId(3,
-1)));
//Etiquetas
NavItems.add(new Items(titulos[4], NavIconos.getResourceId(4,
-1)));
//Declaramos y seteamos nuestro adaptador al cual le pasamos
el array con los titulos
NavAdapter= new NavigationAdapter(this,NavItems);
mDrawerList.setAdapter(NavAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it
is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Aqu podemos observar que ya estamos integrando encabezado_drawer.xml dentro del
ListView (mDrawerList.addHeaderView(encabezado);), luego tomamos desde los
resources el array de drawables, aadimos uno a uno los elementos del men al arraylist
NavItems en cada uno de estos agregamos un objeto Items en donde le pasamos
la posicin dentro del array de ttulos y la imagen. Al final declaramos el adaptador NavAdapter al
cual le pasamos el arraylist.
Una parte muy importante es el Adapter, por lo cual lo veremos en una seccin de Adapaters, en el

107

listado siguiente podemos ver el Adapter que se disea para nuestro ejemplo. Primero habr crear una
nueva clase que herede de la clase BaseAdapter,
dicha clase la llamaremos
NavigationAdapter.java

import java.util.ArrayList;
import
import
import
import
import
import
import

android.app.Activity;
android.view.LayoutInflater;
android.view.View;
android.view.ViewGroup;
android.widget.BaseAdapter;
android.widget.ImageView;
android.widget.TextView;

public class NavigationAdapter extends BaseAdapter {


private Activity mActivity;
ArrayList<Items> arrayItems;
public NavigationAdapter(Activity mActivity, ArrayList<Items>
arrayItems) {
super();
this.mActivity = mActivity;
this.arrayItems = arrayItems;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return arrayItems.size();
}
//Retorna objeto Items del array list
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return arrayItems.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//Declaramos clase esttica, la cual representa la fila
public static class Fila{
TextView tituloItem;
ImageView icono;
}

108

@Override
public View getView(int position, View convertView, ViewGroup
arg2) {
Fila view;
LayoutInflater inflator = mActivity.getLayoutInflater();
if(convertView == null){
view = new Fila();
//Crear objeto item y obtenerlo del array
Items item = arrayItems.get(position);
convertView = inflator.inflate(R.layout.item_drawer,
null);
//Titulo
view.tituloItem = (TextView)
convertView.findViewById(R.id.title_item);
//Establecer en el campo titulo el nombre
correspondiente obtenido del objeto item
view.tituloItem.setText(item.getTitulo());
//Icono
view.icono = (ImageView)
convertView.findViewById(R.id.icon);
//Seteo del icono
view.icono.setImageResource(item.getIcono());
convertView.setTag(view);
}else {
view = (Fila) convertView.getTag();
}
return convertView;
}
}
Lo que simplemente hace es tomar del objeto extrado del Arraylist el texto y la imagen para
luego asignrsela a su correspondiente elemento.
En este punto nuestra aplicacin permite utilizar la navegacin deslizable de momento solo funcionara
con versiones de Android superiores o iguales a 4.0, en el caso de que se necesite o se dese
implementar este control para versiones anteriores ser necesario seguir otro procedimiento para
agregar libreras para hacerla compatible con versiones anteriores de Android.
Al ejecutar nuestro proyecto esto es lo que veramos:

109



El siguiente paso ser el de incorporar el botn para abrir y cerrar el men de navegacin y como
asignarle una accin a la pulsacin sobre un item del men.

Abrir y Cerrar men desde un cono.


Ahora veremos como implementar el clasico botn para abrir y cerrar el men, el botn se mostrar en
la esquina superior izquierda junto al ttulo.





Para poder realizar esto utilizaremos una clase llamada ActionBarDrawerToggle, su uso es muy simple
como veremos a continuacin,
import
import
import
import
import

android.app.Activity;
android.os.Bundle;
android.support.v4.app.ActionBarDrawerToggle;
android.support.v4.widget.DrawerLayout;
android.util.Log;

110

import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
NavigationAdapter NavAdapter;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Aqu va el resto del cdigo previamente escrito...
//Declaramos mDrawableToggle y las imgs a utilizar
mDrawerToggle = new ActionBarDrawerToggle(
this,
/* Activity huesped*/
mDrawerLayout,
/* objeto DrawerLayout */
R.drawable.ic_drawer, /* imagen del nav drawer */
R.string.app_name,
/* "abrir drawer" descripcin
para accesibilidad */
R.string.hello_world
/* "cerrar drawer" descripcin
para accesibilidad */
) {
public void onDrawerClosed(View view) {
Log.e("Cerrado completo", "!!");
}
public void onDrawerOpened(View drawerView) {
Log.e("Apertura completa", "!!");
}
};
//Establecemos que mDrawerToggle declarado anteriormente
el DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
//Establecemos que el ActionBar muestre el botn
getActionBar().setDisplayHomeAsUpEnabled(true);

sea

home

}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it
is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

111

}

En el mtodo onCreate() se declara la variable mDrawerToggle a la cual hay que especificar el
contexto, el drawerLayout, el icono que se mostrar en el botn (disponible en el pack de iconos para
Actionbar ), y 2 Strings de descripcin (que en realidad no se usan en este ejemplo pero que hay que
especificarlos). Tambin podemos especificar una accin al abrir y cerrar el men
en onDrawerClosed() y onDrawerOpened(), dar un vistazo al Logcat durante el
funcionamiento de la aplicacin.
Mediante mDrawerLayout.setDrawerListener(mDrawerToggle; asignamos cual ser el
DrawerListener que utilizara en este caso ser nuestro mDrawerToggle .
Luego en getActionBar().setDisplayHomeAsUpEnabled(true); Establecemos que el
ActionBar muestre el botn del Home de nuestra aplicacin.
Si corremos la aplicacin en esta parte podemos ver como al presionar el icono el men se cierra y abre
tambin podrn observar que este se desplaza segn este el men abierto o no.

Asignar accin a la pulsacin de un Item del men de navegacin


Lo primero que debemos de hacer es asignar un evento a cada uno de los tems de la lista, para poder
especificar cada opcin de la lista, en este caso lo que haremos es segn la opcin del men que pulse
mostrar un fragment especifico, por lo que para cada pantalla habr que definir un fragment y un
layout para esa opcin. Para efectos del presente tutorial crearemos una clase nueva que reaccionar al
toque del primer tem de la lista, dicha clase la llamaremos TareasFragment.java y hereda de la
clase Fragment. A continuacin podemos ver el cdigo de dicha clase:
import
import
import
import
import

android.app.Fragment;
android.os.Bundle;
android.view.LayoutInflater;
android.view.View;
android.view.ViewGroup;

public class TareasFragment extends Fragment {


public TareasFragment(){}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_tareas,
container, false);
return rootView;
}

112

}
Ya cuando se tiene listo el fragment el cdigo que necesitamos que traiga nuestra clase principal ser
el siguiente:
//Establecemos la accion al clickear sobre cualquier item del menu.
//De la misma forma que hariamos en una app comun con un
listview.
mDrawerList.setOnItemClickListener(new
AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long id) {
MostrarFragment(position);
}
});
//Cuando la aplicacion
MostrarFragment(1);

cargue

por

defecto

mostrar

la

opcin

Home

Dentro de OnCreate() al mDrawerList le asignamos el mtodo OnItemClickListener y


dentro hacemos una llamada al mtodo MostrarFragment(position) al cual hay que pasarle
como parmetro la posicin de la opcin seleccionada en el men, en base a esto mostrara el
fragment especifico.
Luego fuera de esto indico que cuando la aplicacin cargue muestre la opcin ToDo por defecto, para
eso le paso el numero 1 el cual equivale a la primer opcin del men.
//Cuando la aplicacion
MostrarFragment(1);

cargue

por

defecto

mostrar

la

opcin

Home

Ver los comentarios en cada lnea par entender como funciona el mtodo MostrarFragment(int
position)que a continuacin se muestra, este mtodo tambin va en la clase
MainActivity.java de nuestro proyecto:
/*Pasando la posicion de la opcion en el menu nos mostrara el Fragment
correspondiente*/
private void MostrarFragment(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 1:
fragment = new TareasFragment();
break;
/*case 2:
fragment = new ProfileFragment();
break;*/

113

default:
//si no esta la opcion mostrara un toast y nos mandara a
Home
Toast.makeText(getApplicationContext(),"Opcion
"+titulos[position-1]+"no disponible!", Toast.LENGTH_SHORT).show();
fragment = new TareasFragment();
position=1;
break;
}
//Validamos si el fragment no es nulo
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame,
fragment).commit();
// Actualizamos el contenido segun la opcion elegida
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
//Cambiamos el titulo en donde decia "
setTitle(titulos[position-1]);
//Cerramos el menu deslizable
mDrawerLayout.closeDrawer(mDrawerList);
} else
//Si el fragment es nulo mostramos un mensaje de
error.
Log.e("Error

", "MostrarFragment"+position);

}
Con esto bsicamente ya podemos dotar a nuestra aplicacin de la lgica necesaria para poder mostrar
cada opcin del men, luego depende de cada uno lo que desee mostrar en sus aplicaciones.
Por
ltimo
hay
que
agregar
los
siguientes
mtodos:
onPostCreate,
onConfigurationChanged, onOptionsItemSelected para sobrescribirlos.
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync el estado del toggle despues de onRestoreInstanceState
haya ocurrido.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pasar el evento al ActionBarDrawerToggle, si este

114

// regresa true, entonces este manejara el evento del touch


// en el icono de la app
if (mDrawerToggle.onOptionsItemSelected(item)) {
Log.e("mDrawerToggle presionado", "x");
return true;
}
// Maneja los otros items de la action bar...
return super.onOptionsItemSelected(item);
}
En este punto nuestra clase MainActivity.java se vera como se muestra a continuacin.
import java.util.ArrayList;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.app.Activity;
android.app.Fragment;
android.app.FragmentManager;
android.content.res.Configuration;
android.content.res.TypedArray;
android.os.Bundle;
android.support.v4.app.ActionBarDrawerToggle;
android.support.v4.widget.DrawerLayout;
android.util.Log;
android.view.Menu;
android.view.MenuItem;
android.view.View;
android.widget.AdapterView;
android.widget.ListView;
android.widget.Toast;

public class MainActivity extends Activity {


private String[] titulos;
private ListView mDrawerList;
private ArrayList<Items> NavItems;
private TypedArray NavIconos;
NavigationAdapter NavAdapter;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Drawer Layout
mDrawerLayout = (DrawerLayout)
findViewById(R.id.drawer_layout);

115

//Lista
mDrawerList = (ListView) findViewById(R.id.drawerIzquierdo);
//Declaramos el header el cual ser el layout de
encabezado_drawer.xml
View encabezado =
getLayoutInflater().inflate(R.layout.encabezado_drawer, null);
//Establecer el encabezado
mDrawerList.addHeaderView(encabezado);
//Tomamos listado de imgs desde drawable
NavIconos =
getResources().obtainTypedArray(R.array.nav_iconos);
//Tomamos listado de titulos desde el string-array de los
recursos @string/nav_options
titulos = getResources().getStringArray(R.array.nav_options);
//Listado de titulos de barra de navegacion
NavItems = new ArrayList<Items>();
//Agregamos objetos Item_objct al array
//ToDo
NavItems.add(new Items(titulos[0], NavIconos.getResourceId(0,
-1)));
//Conversor
NavItems.add(new Items(titulos[1], NavIconos.getResourceId(1,
-1)));
//Eventos
NavItems.add(new Items(titulos[2], NavIconos.getResourceId(2,
-1)));
//Lugares
NavItems.add(new Items(titulos[3], NavIconos.getResourceId(3,
-1)));
//Etiquetas
NavItems.add(new Items(titulos[4], NavIconos.getResourceId(4,
-1)));
//Declaramos y seteamos nuestrp adaptador al cual le pasamos
el array con los titulos
NavAdapter= new NavigationAdapter(this,NavItems);
mDrawerList.setAdapter(NavAdapter);
//Siempre vamos a mostrar el mismo titulo
mTitle = mDrawerTitle = getTitle();
//Declaramos mDrawableToggle y las imgs a utilizar
mDrawerToggle = new ActionBarDrawerToggle(
this,
/* Activity huesped*/
mDrawerLayout,
/* objeto DrawerLayout */
R.drawable.ic_drawer, /* imagen del nav drawer */
R.string.app_name,
/* "abrir drawer" descripcin
para accesibilidad */
R.string.hello_world
/* "cerrar drawer" descripcin
para accesibilidad */
) {
public void onDrawerClosed(View view) {

116

Log.e("Cerrado completo", "!!");


}
public void onDrawerOpened(View drawerView) {
Log.e("Apertura completa", "!!");
}
};
//Establecemos que mDrawerToggle declarado anteriormente
el DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
//Establecemos que el ActionBar muestre el botn
getActionBar().setDisplayHomeAsUpEnabled(true);

sea

home

//Establecemos la accion al clickear sobre cualquier item del


menu.
//De la misma forma que hariamos en una app comun con un
listview.
mDrawerList.setOnItemClickListener(new
AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long id) {
MostrarFragment(position);
}
});
//Cuando la aplicacion cargue por defecto mostrar la opcion
Home
MostrarFragment(1);
}
/*Pasando la posicion de la opcion en el menu nos mostrara el
Fragment correspondiente*/
private void MostrarFragment(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 1:
fragment = new TareasFragment();
break;
/*case 2:
fragment = new ProfileFragment();
break;*/
default:
//si no esta la opcion mostrara un toast y nos mandara a
Home
Toast.makeText(getApplicationContext(),"Opcion

117

"+titulos[position-1]+"no disponible!", Toast.LENGTH_SHORT).show();


fragment = new TareasFragment();
position=1;
break;
}
//Validamos si el fragment no es nulo
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame,
fragment).commit();
// Actualizamos el contenido segun la opcion elegida
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
//Cambiamos el titulo en donde decia "
setTitle(titulos[position-1]);
//Cerramos el menu deslizable
mDrawerLayout.closeDrawer(mDrawerList);
} else
//Si el fragment es nulo mostramos un mensaje de
error.
Log.e("Error

", "MostrarFragment"+position);

}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync el estado del toggle despues de onRestoreInstanceState
haya ocurrido.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pasar el evento al ActionBarDrawerToggle, si este
// regresa true, entonces este manejara el evento del touch
// en el icono de la app
if (mDrawerToggle.onOptionsItemSelected(item)) {
Log.e("mDrawerToggle presionado", "x");
return true;
}
// Maneja los otros items de la action bar...
return super.onOptionsItemSelected(item);
}
@Override

118

public boolean onCreateOptionsMenu(Menu menu) {


// Inflate the menu; this adds items to the action bar if it
is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

Interactuar con una Base de Datos


En la seccin "Creacin y manejo de Base de DatosCreacin y manejo de Base de Datos" vimos y
aprendimos la forma de cmo crear y conectarse con una base de datos, adems de haber creado
algunos mtodos para realizar consultas, actualizaciones y borrado de datos en una tabla.
En esta parte del manual procederemos a utilizar estos mtodos y clases para utilizarlas en un ejemplo
como parte del proyecto que venimos desarrollando hasta ahora, para lo cual vamos a modificar algunas
clases y crear algunas nuevas, as como crear nuevos layouts y algunos nuevos archivos de recursos,
manos a la obra.
Lo primero que haremos es definir lo que necesitamos para esto necesitamos la siguiente estructura:
1. Una actividad para desplegar la lista de tareas que el usuario vaya agregando. En realidad esta
ya la tenemos creada (ver seccin "Asignar accin a la pulsacin de un Item del men de
navegacin"), pero vamos a modificarla.
2. Una actividad para agregar estas tareas.
3. Una clase para manejar la creacin de la base de datos y las versiones de la misma (ver
SQLiteOpenHelper.java ).
4. Una clase para manejar la lgica del uso de consultas en SQLite de la aplicacin DBAdapter.java
A esta altura del manual ya tenemos solventados los puntos 3 y 4, por lo tanto vamos a empezar a ver el
punto 1 y posteriormente el 2.

Agregar recursos a la aplicacin


Ahora, vamos a disear los recursos extras como cadenas de texto y otro tipo de informacin que
necesitar desplegar la aplicacin.
Primero, vamos a crear la estructura del men de opciones de la aplicacin. Definimos un archivo XML
llamado tareas.xml dentro del directorio res > menu. A continuacin vemos el cdigo que deber
contener este archivo:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/insertar"

119

android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_insertar"/>
</menu>
El archivo strings.xml que ya tenemos como parte de nuestro proyecto en el directorio res > values
deber de lucir y/o contener todo el siguiente cdigo:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string
<string
<string
<string

name="app_name">ToDoSQLite</string>
name="action_insertar">Insertar</string>
name="hello_world">Hello world!</string>
name="title_activity_tareas">TareasActivity</string>

<string-array name="prioridades">
<item>Urgente</item>
<item>Recordatorio</item>
</string-array>
<!-- Lista de elementos que aparecen en la navegacin -->
<string-array name="nav_options">
<item>ToDo</item>
<item>Conversor</item>
<item>Perfil</item>
<item>Configuracin</item>
<item>Conversor</item>
</string-array>
<!-- Lista de iconos de navegacion -->
<string-array name="nav_iconos">
<item>@drawable/ic_action_go_to_today</item>
<item>@drawable/ic_action_merge</item>
<item>@drawable/ic_action_person</item>
<item>@drawable/ic_action_good</item>
<item>@drawable/ic_action_cloud</item>
</string-array>
<string name="menu_insert">Agregar Tarea</string>
<string name="menu_delete">Borrar Tarea</string>
<string name="tarea_resumen">Nombre</string>
<string name="tarea_descripcion">Borrar</string>
<string name="tarea_editar_resumen">Nombre</string>
<string name="tarea_editar_descripcion">Descripcin</string>
<string name="tarea_editar_confirmar">Aceptar</string>
<string name="no_todos">An no existen elementos en la
lista</string>
</resources>


120

Diseo de layouts
Vamos a definir dos archivos de layout, uno para la lista, y uno para las filas. A continuacin veremos el
cdigo del archivo activity_tareas.xml del directorio res > layout que define la apariencia de la
lista que desplegar la informacin de la base de datos.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/list_color"
android:orientation="vertical" >
<ListView
android:id="@android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</ListView>
<TextView
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/no_todos" />
</LinearLayout>
En el siguiente layout vamos a hacer uso de un icono, se puede utilizar el que deseen incluso se puede
omitir y no hay ningn problema. El siguiente archivo de layout se llama row.xml y se usar para darle
estilo a cada una de las filas de la lista:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/icon"
android:src="@drawable/reminder"
android:layout_marginLeft="4dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/label"
android:text="@string/hello_world"
android:layout_height="wrap_content"
android:textSize="20sp"

121

android:layout_marginTop="6dp"
android:layout_width="wrap_content"
android:textColor="@color/negro" />
</LinearLayout>
Ahora que ya hemos definido los recursos, layouts y las clases que nos ayudarn a manipular la parte de
SQLite en Android. Estamos listos para crear las clases que nos ayudarn a juntar cada una de estas
piezas.

Agregar clases para manejo de interaccin con la base de datos


En este parte vamos a dar solucin a los puntos 1 y 2 que vimos al inicio de esta seccin (ver Interactuar
con una Base de Datos), para lo cual primero crearemos una nueva activity que se llamar
Details.java en dnde vamos a presentar el formulario de creacin y edicin de items para cada
uno de los elementos que seleccionemos en la lista principal.
En el momento de crear la nueva actividad nos crear un nuevo layout de nombre
activity_details.xml, vamos a editarlo para que se vea grficamente de la siguiente manera:


Si vemos el cdigo del xml veremos esto:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"

122

android:layout_height="fill_parent"
android:background="@color/list_color"
android:orientation="vertical" >
<Spinner
android:id="@+id/category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/prioridades" />
<LinearLayout
android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<EditText
android:id="@+id/todo_edit_summary"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:hint="Nombre" >
</EditText>
</LinearLayout>
<EditText
android:id="@+id/todo_edit_description"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="top"
android:hint="Descripcin" >
</EditText>
<Button
android:id="@+id/todo_edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tarea_editar_confirmar" />
</LinearLayout>
Ya tenemos diseada la parte del cmo se ver la activity, es momento de pasar a la etapa en la que
escribiremos el cdigo que controlar el proceso de consultas a la base de datos, de insercin y
modificacin de datos as como el de llenado del formulario en el momento que hagamos alguna edicin
de una tarea previamente creada.

123

En todo el siguiente listado se muestra el cdigo de la clase DetailsActivity.java, para su mayor


comprensin se recomienda que se lean los comentarios que es ah donde se explica lo mejor posible la
funcionalidad del cdigo.
import com.android.utm.todosqlite.database.DBAdapter;
import
import
import
import
import
import
import
import

android.app.Activity;
android.database.Cursor;
android.os.Bundle;
android.util.Log;
android.view.View;
android.widget.Button;
android.widget.EditText;
android.widget.Spinner;

public class DetailsActivity extends Activity {


private
private
private
private
private

EditText mTitleText;
EditText mBodyText;
Long mRowId;
DBAdapter mDbHelper;
Spinner mCategory;

@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
// Cargamos el layout de nuestro fragment
setContentView(R.layout.activity_details);
/*
* Inicializamos los objetos y los enlazamos con
* los elementos (views) del layout
* */
mCategory = (Spinner) findViewById(R.id.category);
mTitleText = (EditText)
findViewById(R.id.todo_edit_summary);
mBodyText = (EditText)
findViewById(R.id.todo_edit_description);
Button confirmButton = (Button)
findViewById(R.id.todo_edit_button);
/*
* Recuperamos los parmetros que enviamos a esta
* activity
* */
mRowId = null;
Bundle extras = getIntent().getExtras();
mRowId = (bundle == null) ? null : (Long)

124

bundle.getSerializable(DBAdapter.KEY_ROWID);
if (extras != null) {
mRowId = extras.getLong(DBAdapter.KEY_ROWID);
}
// Mandamos llamar al mtodo que se encargar de llenar los
campos en caso de ser una edicin
populateFields();
/*
* Le asignamos el evento de OnClickListener a nuetro botn
* esto con la finalidad de que guarde los valores que
tenemos
* en nuestro formulario
* */
confirmButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view) {
setResult(RESULT_OK);
saveState();
finish();
}
});
}
/*
* Mtodo que permite llenar los campos del formulario
* en el caso de que sea una edicin, si no es una
* edicin los campos ser dejados vacos
* */
private void populateFields() {
/*
* Confirmamos que a variable mRowId no est nula,
* esto confirma que se trata de una edicin
* */
if (mRowId != null) {
/*Recuperamos los datos de la tarea que coincide con
la variable mRowId*/
Cursor todo = mDbHelper.recuperaTarea(mRowId);
/*
* El mtodo startManagingCursor que se hereda de la
clase Activity
* nos sirve o nos ayuda para tener un mejor control
del cursor, pues
* este se adaptar al ciclo de vida de la activity,
esto es que si
* la activity es detenida el cursor automticamente
llamar al mtodo
* deactivate(), y cuando la activity se reinicie se
llamr al mtodo

125

* requery() para reiniciar el cursor. Tambin nos


ayudar al momento
* en que la activity sea destruida el Cursor ser
cerrado automticamente
*/
startManagingCursor(todo);
String category =
todo.getString(todo.getColumnIndexOrThrow(DBAdapter.KEY_CATEGORY));
for (int i = 0; i < mCategory.getCount(); i++) {
String s = (String)
mCategory.getItemAtPosition(i);
Log.e(null, s + " " + category);
if (s.equalsIgnoreCase(category)) {
/*
* Dependiendo de la categoria que haya sido
registrada en la
* BD, ser entonces que en el Spinner sea
seleccionada la misma
* opcin que se tenga en la BD
* */
mCategory.setSelection(i);
}
}
// Rellenamos los otros valores con lo que tengamos en
la BD
mTitleText.setText(todo.getString(todo
.getColumnIndexOrThrow(DBAdapter.KEY_SUMMARY)));
mBodyText.setText(todo.getString(todo
.getColumnIndexOrThrow(DBAdapter.KEY_DESCRIPTION)));
}
}
/*
* En este mtodo lo que se busca es que el id de la tarea sea
* guardado con la intencin de recuperarlo para cuando la
activity
* sea recreado
* */
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//saveState();
outState.putSerializable(DBAdapter.KEY_ROWID, mRowId);
}
@Override

126

protected void onPause() {


super.onPause();
//saveState();
}
/*
* Cuando la activity sea reiniciada mandar
* ejecutar el mtodo que rellena los campos
* de la activity
*/
@Override
protected void onResume() {
super.onResume();
populateFields();
}
/*
* Sobreescribimos este mtodo para que al presionar
* el btn de back sea ejecutado el mtodo de finish
* */
@Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
finish();
}
/*
* Este mtodo trata de guardar la informacin en la
* BD
* */
private void saveState() {
String category = (String) mCategory.getSelectedItem();
String summary = mTitleText.getText().toString();
String description = mBodyText.getText().toString();
/*
* Si la variable mRowId es nula entonces ejecutar el
mtodo crearNuevaTarea
* para insertar los datos nuevos en la tabla, pero si no es
null
* entonces se ejecutar el mtodo updateTarea para
actualizar la informacin
* de la tarea relacionada con el valor que tenga la
variable mRowId
* */
if (mRowId == null) {
long id = mDbHelper.crearNuevaTarea(category, summary,
description);
if (id > 0) {
mRowId = id;

127

}
} else {
mDbHelper.updateTarea(mRowId, category, summary,
description);
}
}
}
Es momento de realizar otras modificaciones, es turno de TareasFragment.java, el primero y que
es muy importante es cambiar la clase de la cual hereda, en este momento debera de estar
extendiendo de Fragment, pero ahora vamos a modificarlo por ListFragment esto se debe a que esta
clase muestra una lista de elementos que son administrados por un adaptador (como un
SimpleCursorAdapter), similar a ListActivity. Proporciona varios mtodos para la gestin de una vista de
lista, como la devolucin de llamada onListItemClick () para gestionar clic eventos sobre la lista, esta es
una de las casusas por la que en este caso heredaremos de esta clase (ListFragment). Ser necesario que
se revise el cdigo que se muestra a continuacin pues aqu ya se muestran todas las modificaciones y
anexiones que se le hicieron a la clase, para su mayor entendimiento se le agregaron varios comentarios
para que sean estudiados.
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.app.ListFragment;
android.content.Intent;
android.database.Cursor;
android.os.Bundle;
android.view.ContextMenu;
android.view.LayoutInflater;
android.view.Menu;
android.view.MenuItem;
android.view.View;
android.view.ViewGroup;
android.view.ContextMenu.ContextMenuInfo;
android.widget.ListView;
android.widget.SimpleCursorAdapter;
android.widget.AdapterView.AdapterContextMenuInfo;

import com.android.utm.todosqlite.database.DBAdapter;
public class TareasFragment extends ListFragment {
private static final int ACTIVITY_CREATE = 0;
private static final int ACTIVITY_EDIT = 1;
private static final int DELETE_ID = Menu.FIRST + 1;
private DBAdapter dbHelper;
private Cursor cursor;
public TareasFragment(){}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup

128

container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.activity_tareas,
container, false);
/**
* Se crea una instancia de la clase DBAdapter,
* el constructor de la clase mandar a crear la BD si no
existe,
* en caso de ya existir solo crear la conexin a la BD
* */
dbHelper = new
DBAdapter(getActivity().getApplicationContext());
// Abre la conexin a la BD
dbHelper.open();
return rootView;
}
/*
* Este mtodo nos ayuda a saber cuando la
* activity de nuestro fragment ha terminado de
* ejecutar su mtodo onCreate()*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
fillData();
registerForContextMenu(getListView());
}
/*
* Se llama cada vez que se selecciona un elemento en un men
contextual
* */
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo)
item
.getMenuInfo();
dbHelper.deleteTarea(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}

129

//ListView y la accin al seleccionar un item


/*
* Este mtodo se encarga de manejar los eventos de los
* "clicks" en cada uno de los items de la lista
* */
@Override
public void onListItemClick(ListView l, View v, int position,
long id) {
super.onListItemClick(l, v, position, id);
/*
* Al ser seleccionado uno de los elementos de la lista
* se procede a armar un Intent que abrir la activity
* DetailsActivity.java para que se editen los valores.
* Se manda un parmetro que es el id de la tarea a
* editar*/
Intent i = new Intent(getActivity().getApplicationContext(),
DetailsActivity.class);
i.putExtra(DBAdapter.KEY_ROWID, id);
//La actividad retorna un resultado cuando se llama
//startActivityForResult
startActivityForResult(i, ACTIVITY_EDIT);
}
/*
* Crea los elementos del men contextual
* */
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
@Override
public void onDestroy() {
super.onDestroy();
if (dbHelper != null) {
dbHelper.close();
}
}
/*
* En este mtodo se va a hacer una consulta a la BD en la
* cual se van a recuperar todas las tareas que existan en
* la BD, y estas luego sern agregadas al ListFragment.
* */
private void fillData() {
cursor = dbHelper.recuperaTodos();
getActivity().startManagingCursor(cursor);

130

String[] from = new String[] { DBAdapter.KEY_SUMMARY };


int[] to = new int[] { R.id.label };
//Creamos un array adapter para desplegar cada una de las
filas
SimpleCursorAdapter notes = new
SimpleCursorAdapter(getActivity().getApplicationContext(),
R.layout.row, cursor, from, to);
setListAdapter(notes);
}
}
Por ltimo hay que realizar algunas adecuaciones a la clase MainActivity.java, estas
modificaciones van enfocadas principalmente en agregar la funcionalidad al men Insertar, este
men es el que se encarga de llamar la activity DetailsActivity.java.
Slo mostrar el mtodo que hay que modificar y los mtodos nuevos que irn en esta clase.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pasar el evento al ActionBarDrawerToggle, si este
// regresa true, entonces este manejara el evento del touch
// en el icono de la app
if (mDrawerToggle.onOptionsItemSelected(item)) {
Log.e("mDrawerToggle presionado", "x");
return true;
}else{
switch (item.getItemId()) {
case R.id.insertar:
createTodo();
return true;
}
}
// Maneja los otros items de la action bar...
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it
is present.
getMenuInflater().inflate(R.menu.tareas, menu);
return true;
}
// Codificamos la accion al seleccionar el item del menu
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {

131

case R.id.insertar:
createTodo();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
private void createTodo() {
Intent i = new Intent(this, DetailsActivity.class);
startActivityForResult(i, ACTIVITY_CREATE);
}
//El siguiente metodo se llama con el resultado de otra actividad
// requestCode es el codigo original que se manda a la actividad
// resultCode es el codigo de retorno, 0 significa que todo sali
bien
// intent es usado para obtener alguna informacin del caller
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
//fillData();
//Cuando la aplicacion cargue por defecto mostrara la opcion
Home
MostrarFragment(1);
}

Trazar una ruta


En esta seccin agregaremos una opcin nueva a nuestro proyecto de ejemplo, en la cual
aprovecharemos para explicar como crear pestaas y swipe en la aplicacin, adems de explicar
algunas cosas relativas a los mapas (de Google). Este ejemplo mostrar dos opciones, una ser la de
mostrar el mapa con la ruta trazada dentro de la aplicacin y la otra ser lanzando la aplicacin de
Maps de Google para que nos muestre la ruta, bueno manos a la obra lo primero que hay que hacer
es lo que se indica en la seccin Pasos para instalar y/o configurar la API de Google Maps Android.
Ahora ser necesario agregar los permisos de para poder usar el GPS del celular (para una mayor
referencia para el uso y/o configuracin del GPS en Android, se debera de estudiar la seccin
Localizacin geogrfica en Android) .
En este punto ya deberamos de tener configurado en el Manifest del proyecto todos los permisos para
la recepcin de mapas, la conexin a internet, as como de tener ya configurada y obtenida nuestra API
Key de Google Maps, por lo cual procederemos a solicitar los permisos para poder utilizar la localizacin

132

con ayuda del GPS o de la red WIFI, por lo que deberemos de agregar los siguientes permisos en la
seccin de permisos del Manifest:
<!-- permite a la aplicacin conocer la ubicacin de manera "menos"
precisa. Por ejemplo, utilizando WIFI. -->
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- permite a la aplicacin que conozca de manera "precisa" la
ubicacin. Por ejemplo, utilizando GPS. -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
por lo que todo nuestro Manifest quedar como se muestra a continuacin:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.utm.todosqlite"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="14" />
<permission
android:name="com.android.utm.todosqlite.java.permission.MAPS_REC
EIVE"
android:protectionLevel="signature" />
<uses-permission
android:name="com.android.utm.todosqlite.java.permission.MAPS_REC
EIVE" />
<uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GS
ERVICES" />
<!-- permitimos abrir conexiones de red. -->
<uses-permission android:name="android.permission.INTERNET"
/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- permite a la aplicacin conocer la ubicacin de manera
"menos" precisa. Por ejemplo, utilizando WIFI. -->
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION" />

133

<!-- permite a la aplicacin que conozca de manera "precisa"


la ubicacin. Por ejemplo, utilizando GPS. -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<!Le indicamos a nuestro celular que vamos a usar la versin
OpenGL ES 2.0, esto es necesario para que el celular muestre de
forma adecuada los mapas -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!Declaracin de la API Key para los mapas-->
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AIzaSyA7h1--xnFvHT1-Y3lTTof2FrtIp7MofY" />
<activity
android:name="com.android.utm.todosqlite.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.android.utm.todosqlite.TareasFragment"
android:label="@string/title_activity_tareas" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.android.utm.todosqlite.MainActivity" />
</activity>
<activity
android:name="com.android.utm.todosqlite.DetailsActivity"

134

android:windowSoftInputMode="stateVisible|adjustResize" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.android.utm.todosqlite.TareasFragment" />
</activity>
<activity
android:name="com.android.utm.todosqlite.TrazarRutaFragment"
android:label="@string/title_activity_trazar_ruta" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.android.utm.todosqlite.MainActivity" />
</activity>
</application>
</manifest>
Como se podr notar en este momento ya hay varias actividades declaradas pero que an no las hemos
codificado, podemos ir adelantando esto para que no se nos olvide ms adelante, o si lo desean al
momento que sean declaradas y/o creadas las actividades podramos venir a esta seccin para
confirmar la manera en la que se declaran,
Nota
Es momento de recordar que todas las actividades, fragments (pantallas) o cualquier tipo de View que
se muestre en la pantalla de nuestro mvil debe de ser declarado en el Manifest de nuestro proyecto,
de lo contrario en el momento que deseemos abrir o mostrarla en pantalla la aplicacin completa
fallar y se cerrar.
En muchas ocasiones es necesario que se declare un nuevo paquete en el cual se colocan ciertas clases
que se pueden considerar individuales, puesto que realizan una funcin en especfico, y esta funcin en
muchos de los casos pueden ser usados por una gran cantidad de las otras clases, a este tipo de clases
se les suele llamar que son utileras, y lo nico que comparten con algunas otras clases es su
caracterstica de ser solas o nicas por lo que se acostumbra crear un paquete con terminacin util para
nuestro caso ser el siguiente: com.android.utm.todosqlite.util (recordemos que estos
nombre son los que tengo para mi proyecto, deberan de usar los que tengan para el suyo, no tienen por
qu ser iguales), para este proyecto vamos a tener tres clases en este paquete las cuales sern
Utils.java, ConnectionDetecter.java y GMapsDirection.java a continuacin
explicar a grandes rasgos de que tratan cada una, pero cabe mencionar que este tipo de clases pueden
reutilizarse en diferentes proyectos prcticamente sin ningn tipo de modificacin salvo pequeas
adecuaciones segn las necesidades especificas de algn proyecto.

135

Utils.java
De esta clase lo que nos interesa y ser lo nico que explique sern los mtodos
AdjustWidthScreen() y AdjustHeightScreen(), el primero de ellos lo que hace es
recibir de parmetros el alto, ancho de un elemento view de un layout as como un valor que representa
el ancho que deseamos que tenga el objeto con respecto a la pantalla, este valor representa el
porcentaje del ancho de la pantalla y tambin se recibe como parmetro, el ltimo parmetro recibido
es el objeto al cual queremos calcular el ancho. El segundo hace lo mismo pero en el alto del elemento
recibido como parmetro. Aqu presento el cdigo que tendr esta clase:
package com.android.utm.todosqlite.util;
import
import
import
import
import
import
import

android.annotation.TargetApi;
android.os.Build;
android.os.StrictMode;
android.widget.Button;
android.widget.ImageView;
android.widget.LinearLayout;
android.widget.TextView;

/**
* Class containing some static utility methods.
*/
public class Utils {
public Utils() {};
@TargetApi(11)
public static void enableStrictMode() {
if (Utils.hasGingerbread()) {
StrictMode.ThreadPolicy.Builder threadPolicyBuilder =
new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog();
StrictMode.VmPolicy.Builder vmPolicyBuilder =
new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog();
StrictMode.setThreadPolicy(threadPolicyBuilder.build());
StrictMode.setVmPolicy(vmPolicyBuilder.build());
}
}
public static boolean hasFroyo() {
// Can use static final constants like FROYO, declared in
later versions
// of the OS since they are inlined at compile time. This is
guaranteed behavior.

136

return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;


}
public static boolean hasGingerbread() {
return Build.VERSION.SDK_INT >=
Build.VERSION_CODES.GINGERBREAD;
}
public static boolean hasHoneycomb() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
public static boolean hasHoneycombMR1() {
return Build.VERSION.SDK_INT >=
Build.VERSION_CODES.HONEYCOMB_MR1;
}
/**
* Este mtodo nos ayuda a ajustar el ancho
* de algunos tipos de elementos pero dado
* un porcentaje con relacin a la pantalla
* */
public void AdjustWidthScreen(int width, int height, int percent,
Object theObject) {
if (theObject instanceof TextView) {
((TextView) theObject).setWidth((percent * width) /
100);
} else if (theObject instanceof LinearLayout) {
((LinearLayout) theObject).setMinimumWidth((percent *
width) / 100);
} else if (theObject instanceof Button) {
((Button) theObject).setWidth((percent * width) /
100);
} else if (theObject instanceof ImageView) {
((ImageView) theObject).getLayoutParams().width =
((percent * width) / 100);
} else {
return;
}
return;
}
/**
* Este mtodo nos ayuda a ajustar el alto
* de algunos tipos de elementos pero dado
* un porcentaje con relacin a la pantalla
* */
public void AdjustHeightScreen(int width, int height, int

137

percent, Object theObject){


if (theObject instanceof TextView) {
((TextView) theObject).setHeight((percent * height) /
100);
}
else if (theObject instanceof LinearLayout){
((LinearLayout) theObject).setMinimumHeight((percent *
height) / 100);
}
else if (theObject instanceof Button){
((Button) theObject).setHeight((percent * height) /
100);
}
else if (theObject instanceof ImageView){
((ImageView) theObject).getLayoutParams().height =
(percent * height) / 100;
}
return;
}
}

ConnectionDetecter.java
Esta clase es muy simple, de lo nico que se encarga es de detectar si hay conexin a internet, regresa
un valor boolean, si hay conexin retorna true, en caso contrario false, veamos el cdigo de dicha clase.
package com.android.utm.todosqlite.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class ConnectionDetector {
private Context context;
public ConnectionDetector(Context context){
this.context = context;
}
/**
* Revisa todos los posibles proveedores de internet
* en pocas palabras se encarga de revisar si tenemos
* conexin a internet en el dispositivo
* **/
public boolean isConnectedToInternet(){
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SER
VICE);

138

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();


boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
return isConnected;
}
}
GMapsDirection.java
Esta clase es un poco ms complicada, pues realiza ms cosas, en este caso debemos de mencionar y
tener mucho cuidado pues esta clase est enfocada en un mapa que est siendo renderizado sobre un
Fragment, en el caso de que sea otro tipo de View en el cual se est mostrando se deberan de tomar las
medidas pertinentes para asegurarse que este funcione adecuadamente.
Empezaremos diciendo que en el constructor recibe como parmetro el fragment sobre el cual se est
ejecutando o mostrando el mapa y sobre el cual se va a pintar la ruta de nuestro punto de origen a
nuestro punto de destino.
En el mtodo getDocument()armamos la url de peticin a Google donde le pedimos que nos de las
indicaciones de cmo llegar desde nuestro punto de origen hasta nuestro punto de destino, para lo cual
necesitamos las coordenadas de inicio y de destino es aqu donde antes de iniciar el proceso asncrono
de consultar a Google, donde hacemos la verificacin de conexin a internet con ayuda de la clase
ConnectionDetector(), si tenemos conexin iniciamos la consulta, si no, no se realiza la consulta.
Dentro de esta clase tenemos una clase interna que hereda de la clase AsyncTask, la cual recibe la url
de peticin para Google y entrega un objeto del tipo Document el cual contiene los pasos y
coordenadas de los puntos para llegar al destino especificado, ahora en esta otra clase tenemos tres
mtodos que sobreescribiremos el primero se llama onPreExecute en este mtodo lo nico que
haremos ser iniciar un PogressDialog, este estar visible mientras se ejecuta el proceso de preguntar a
Google y de que de su respuesta y as mismo de trazar la ruta sobre el mapa. El segundo mtodo es
doInBackGroound, este mtodo recibe como parmetro la url para realizar la consulta a Google, y
como resultado de su ejecucin dar un objeto del tipo Document el cual contendr la estructura del
documento XML que responde Google y que contiene la informacin de cmo llegar. Ya por ltimo
tenemos al mtodo doPostExecute, este mtodo recibe el objeto Document con la informacin del
XML de respuesta de Google. Otro mtodo que tenemos en esta clase es el mtodo getDirection y
este mtodo recibe el obejto Document con toda la informacin del XML de Google y lo que hace es
obtener la informacin contenida en l para obtener nicamente los puntos con sus coordenadas y que
sern puestos en el mapa para representar la ruta, as mismo tenemos los mtodos getNodeIndex y
decodePoly pero estos mtodos son auxiliares del getDirection. Y ya para terminar aqu m
uestro la clase completa:
package com.android.utm.todosqlite.util;
import java.io.InputStream;
import java.util.ArrayList;

139

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import
import
import
import
import
import
import
import
import

org.apache.http.HttpResponse;
org.apache.http.client.HttpClient;
org.apache.http.client.methods.HttpPost;
org.apache.http.impl.client.DefaultHttpClient;
org.apache.http.protocol.BasicHttpContext;
org.apache.http.protocol.HttpContext;
org.w3c.dom.Document;
org.w3c.dom.Node;
org.w3c.dom.NodeList;

import android.app.ProgressDialog;
import android.os.AsyncTask;
import com.android.utm.todosqlite.TrazarRutaInternaFragment;
import com.google.android.gms.maps.model.LatLng;
public class GMapsDirection {
public final static String MODE_DRIVING = "driving";
public final static String MODE_WALKING = "walking";
private TrazarRutaInternaFragment fragment;
public ProgressDialog progress;
/**
* El constructor recibe como parmetro
* el fragment sobre el cual se est ejecutando
* o mostrando el mapa y sobre el cual se va a
* pintar la ruta de nuestro punto de origen a
* nuestro punto de destino
* */
public GMapsDirection(TrazarRutaInternaFragment fragment) {
this.fragment = fragment;
}
public void getDocument(LatLng start, LatLng end, String mode) {
/**
* Armamos la url de peticin a Google
* donde le pedimos que nos de las indicaciones
* de cmo llegar desde nuestro punto de origen
* hasta nuestro punto de destino, para lo cual
* necesitamos las coordenadas de inicio y de
* destino
* */
String url =
"http://maps.googleapis.com/maps/api/directions/xml?"
+ "origin=" + start.latitude + "," +
start.longitude
+ "&destination=" + end.latitude + "," +
end.longitude

140

+
"&sensor=false&units=metric&mode="+MODE_DRIVING;
// Usamos nuestra clase ConnectionDetector para verificar la
conectividad a internet
ConnectionDetector connectionDetector = new
ConnectionDetector(fragment.getActivity());
if(connectionDetector.isConnectedToInternet()){
new RetrieveData().execute(url);
}
}
/**
* Clase interna que hereda de AsyncTask la cual recibe
* la url de peticin para Google y entrega un objeto del
* tipo Document el cual contiene los pasos y coordenadas
* de los puntos para llegar al destino especificado
* */
class RetrieveData extends AsyncTask<String, Void, Document> {
/**
* En este mtodo lo nico que haremos ser iniciar
* un PogressDialog, este estar visible mientras
* se ejecuta el proceso de preguntar a Google y de
* que de su respuesta y as mismo de trazar la ruta
* sobre el mapa
* */
@Override
protected void onPreExecute() {
progress = new ProgressDialog(fragment.getActivity());
progress.setTitle("Cargando");
progress.setMessage("Por favor, espera...");
progress.setCanceledOnTouchOutside(false);
progress.show();
}
/**
* Este mtodo recibe como parmetro la url para realizar
* la consulta a Google, y como resultado de su ejecucin
* dar un objeto del tipo Document el cual contendr la
* estructura del documento XML que responde Google y que
* contiene la informacin de cmo llegar
* */
protected Document doInBackground(String... urls) {
try {
// Interfaz para un cliente HTTP.
HttpClient httpClient = new DefaultHttpClient();

141

// Un contexto para la ejecucin de una


solicitud.
HttpContext localContext = new
BasicHttpContext();
// El mtodo POST se utiliza para solicitar que
el servidor de origen acepte la entidad incluida en la solicitud
HttpPost httpPost = new HttpPost(urls[0]);
/**
* Los clientes HTTP encapsulan una mezcla
heterognea de objetos
* necesarios para ejecutar solicitudes HTTP al
manipular las cookies,
* autenticacin, gestin de la conexin, y otras
caractersticas.
* */
HttpResponse response =
httpClient.execute(httpPost, localContext);
// Se genera un objeto InputStream donde se
almacena la respuesta de Google
InputStream in =
response.getEntity().getContent();
//Instanciamos la fbrica para DOM y creamos el
nuevo parser DOM
DocumentBuilder builder =
DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
// Realizamos la lectura completa del XML
Document doc = builder.parse(in);
return doc;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Este mtodo recibe el objeto Document con la informacin
* del XML de respuesta de Google
* */
protected void onPostExecute(Document document) {
if(document != null){
/**
* Ejecutamos el mtodo de traceRoute
* que pertenece a la clase TrazarRutaInternaFragment
* y se pasa de parmetro el objeto Document*/
fragment.traceRoute(document);
}

142

// Ocultamos el ProgressDialog
progress.hide();
}
}
/**
* Este mtodo recibe el obejto Document con toda
* la informacin del XML de Google
* y lo que hace es obtener la informacin contenida
* en l para obtener nicamente los puntos con sus
* coordenadas y que sern puestos en el mapa para
* representar la ruta
* */
public ArrayList<LatLng> getDirection(Document doc) {
NodeList nl1, nl2, nl3;
ArrayList<LatLng> listGeopoints = new ArrayList<LatLng>();
nl1 = doc.getElementsByTagName("step");
if (nl1.getLength() > 0) {
for (int i = 0; i < nl1.getLength(); i++) {
Node node1 = nl1.item(i);
nl2 = node1.getChildNodes();
Node locationNode = nl2
.item(getNodeIndex(nl2,
"start_location"));
nl3 = locationNode.getChildNodes();
Node latNode = nl3.item(getNodeIndex(nl3,
"lat"));
double lat =
Double.parseDouble(latNode.getTextContent());
Node lngNode = nl3.item(getNodeIndex(nl3,
"lng"));
double lng =
Double.parseDouble(lngNode.getTextContent());
listGeopoints.add(new LatLng(lat, lng));
locationNode = nl2.item(getNodeIndex(nl2,
"polyline"));
nl3 = locationNode.getChildNodes();
latNode = nl3.item(getNodeIndex(nl3, "points"));
ArrayList<LatLng> arr =
decodePoly(latNode.getTextContent());
for (int j = 0; j < arr.size(); j++) {
listGeopoints.add(new
LatLng(arr.get(j).latitude, arr
.get(j).longitude));
}
locationNode = nl2.item(getNodeIndex(nl2,
"end_location"));
nl3 = locationNode.getChildNodes();

143

latNode = nl3.item(getNodeIndex(nl3, "lat"));


lat =
Double.parseDouble(latNode.getTextContent());
lngNode = nl3.item(getNodeIndex(nl3, "lng"));
lng =
Double.parseDouble(lngNode.getTextContent());
listGeopoints.add(new LatLng(lat, lng));
}
}
return listGeopoints;
}
private int getNodeIndex(NodeList nl, String nodename) {
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i).getNodeName().equals(nodename))
return i;
}
return -1;
}
private ArrayList<LatLng> decodePoly(String encoded) {
ArrayList<LatLng> poly = new ArrayList<LatLng>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) :
(result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) :
(result >> 1));
lng += dlng;
LatLng position = new LatLng((double) lat / 1E5,
(double) lng / 1E5);
poly.add(position);
}
return poly;

144

}
}

Ahora es momento ya de empezar a trabajar la parte que ser visible en nuestra aplicacin,
empezaremos con el diseo de los layouts de las interfaces de cada uno de los fragments que
aparecern en nuestras pestaas, a continuacin muestro una captura de pantalla de cmo se vera
nuestra aplicacin al terminar:


Lo que vemos es una pantalla que tiene dos tabs, en una tenemos un mapa con una ruta marcada sobre
de l, y en la otra pestaa es un pequeo formulario en el cual vemos unos parametros con las
posiciones actuales y la de destino y un botn, la pantalla se ve as por que en el momento de tomar la
captura de pantalla se est haciendo un swipe entre las pestaas, es decir esta aplicacin tiene un
ViewPager.
Creacin de elementos visuales
En esta seccin nos dedicaremos a slo crear todo los layouts y/o archivos de configuracin que
necesitemos para la creacin de nuestra aplicacin
Procederemos ahora a crear los diferentes layouts, el primero que crearemos se llamar
como_llegar_interna_fragment.xml, dicho layout pertenece al fragment que nos mostrar la
ruta de cmo llegar entre dos puntos directamente en el mapa, es muy simple, se ocupa un view o
elemento en el cual se muestra un mapa (con los datos obtenidos del servicio de Google Maps). Una
vez enfocado, capturar las pulsaciones de teclas y gestos tctiles para mover el mapa. Tambin

145

contiene un ImageView que tiene el atributo visibility en invisible esto es un truco que se necesita para
poder hacer swipe entre las pestaas, de no ser as en algunas versiones nuevas de Android mostrar
unas secciones en negro al momento de cambiar las pestaas, si su aplicacin no ocupa hacer swipe con
el mapa, entonces no es necesario que tenga el ImageView. Este es el cdigo:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Un view que muestra un mapa
(con los datos obtenidos del servicio de Google Maps).
Una vez enfocado, capturar las pulsaciones de teclas
y gestos tctiles para mover el mapa. -->
<com.google.android.gms.maps.MapView
android:id="@+id/mapa"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:uiZoomControls="true" />
<!-- Este ImageView tiene el atributo visibility
en invisible esto es un truco que se necesita
para poder hacer swipe entre las pestaas, de no
ser as en algunas versiones nuevas de Android
mostrar unas secciones en negro al momento de
cambiar las pestaas-->
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="invisible" />
</RelativeLayout>
Para el layout de la otra pestaa que lo que hace es pedir a una aplicacin externa que muestre el trazo
de la ruta que se desea, para este caso se desea sea mostrada por a aplicacin Maps de Google, pero en
muchos casos podra pasar que existan varias aplicaciones que puedan abrir la ruta solicitida (es algo
complicado especificar una aplicacin en especial), en ese caso lo que hace android de forma
automtica es algo como lo que se muestra en la imagen de siguiente:

146


En este caso ya es decisin personal que opcin tomar, pero yo aconsejo hacerlo con la aplicacin de
Maps, ya que nos dar como resultado lo que vemos en las siguientes imgenes:

147

El segundo layout ser demasiado simple pues los elementos que utilizaremos son varios que ya hemos
usado varias veces en otros ejemplos, pero aqu dejo el cdigo como ejemplo, el layout se llamar
como_llegar_externa_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:background="#CECECE" >
<TextView
android:id="@+id/latitud_origen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/longitud_origen"
android:layout_below="@+id/longitud_origen"
android:layout_marginTop="28dp"
android:text="Latitud Origen" />
<TextView
android:id="@+id/longitud_origen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="18dp"
android:layout_marginTop="16dp"
android:text="Longitud Origen" />
<!-- Aqu se va a mostrar la longitud de origen obtenida del GPS
del mvil -->
<TextView
android:id="@+id/longitud_origen_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/latitud_origen"
android:layout_centerHorizontal="true"
android:text="TextView" />
<!-- Aqu se va a mostrar la latitud de origen obtenida del GPS
del mvil -->
<TextView
android:id="@+id/latitud_origen_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/latitud_origen"
android:layout_alignLeft="@+id/longitud_origen_txt"
android:text="TextView" />

148

<TextView
android:id="@+id/longitud_destino"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/latitud_origen"
android:layout_below="@+id/latitud_origen"
android:layout_marginTop="27dp"
android:text="Longitud Destino" />
<!-- Aqu se muestra la longitud de destino -->
<TextView
android:id="@+id/longitud_destino_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/longitud_destino"
android:layout_alignBottom="@+id/longitud_destino"
android:layout_alignLeft="@+id/latitud_origen_txt"
android:text="-99.131111" />
<TextView
android:id="@+id/latitud_destino"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/longitud_destino"
android:layout_below="@+id/longitud_destino"
android:layout_marginTop="24dp"
android:text="Latitud Destino" />
<!-- Aqu se muestra la latitud de destino -->
<TextView
android:id="@+id/latitud_destino_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/latitud_destino"
android:layout_alignBottom="@+id/latitud_destino"
android:layout_alignLeft="@+id/longitud_destino_txt"
android:text="19.4325" />
<!-- Botn que realizar el proceso de armar la URL para
solicitar el trazado de la ruta de un punto de origen a uno
de destino -->
<Button
android:id="@+id/btn_trazar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/latitud_destino_txt"
android:layout_centerHorizontal="true"
android:layout_marginTop="86dp"
android:text="Trazar Ruta" />
</RelativeLayout>

149

En nuestro ejemplo las pestaas tendrn dos colores, una para cuando estn seleccionados (#558e33), y
otro para cuando no lo estn (#adab21), es por esta razn que registraremos dos colores en el archivo
colors.xml, adems tambin registraremos un color para la lnea a trazar de la ruta en el mapa, por
lo que nuestro archivo de configuracin de colores quedar cmo se muestra en el listado siguiente:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="list_color">#94A65D</color>
<color name="negro">#000000</color>
<!-- Estos son las tres nuevas definiciones de colores -->
<color name="tab_trazar_on">#558e33</color>
<color name="tab_trazar_off">#adab21</color>
<color name="route">#65b4f1</color>
</resources>
Android tiene una forma muy fcil para controlar el estilo de los elementos que deben de mostrar
cuando sean tocados, seleccionados o enfocados entre otros. Para lograr que de forma automtica se
cambin los colores de las pestaas ser necesario crear un nuevo archivo xml pero este estar en la
carpeta drawable y llevar por nombre tab_selector_trazar.xml, en este archivo se declararn
las reglas que se deben de cumplir cada vez que una de las pestaas es tocada o cada vez que su estado
cambie ha seleccionado, a continuacin se muestra el cdigo de este archivo (en lugar de colores
pueden ser definidas imgenes):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Active tab -->
<!-- Lo que se dice aqu es que cuando el estado de seleccionado
de una tab sea verdadero
se deber de aplicar a la pestaa el color definido con el nombre
tab_trazar_on -->
<item android:drawable="@color/tab_trazar_on"
android:state_selected="true"/>
<!-- Inactive tab -->
<!-- Lo que se dice aqu es que cuando una tab no est
seleccionado
se deber de aplicar a la pestaa el color definido con el nombre
tab_trazar_off -->
<item android:drawable="@color/tab_trazar_off"/>
</selector>

Si no queremos que las pestaas de nuestra aplicacin luzcan de la forma por default como en el estilo
de Android ser necesario que sea creado un layout nuevo en donde se especifique el nuevo estilo o
apariencia, como ese es el caso del proyecto que estamos desarrollando entonces ser necesario que
sea creado un nuevo layout de nombre tab_layout_trazar.xml, este nuevo diseo es muy
simple consta de un RelativeLayout al cual le aplicaremos como valor del atributo background el archivo

150

previamente creado, esto har que si la pestaa est seleccionada tenga un color y si no lo est tenga
otro color, el otro elemento que aparecer es un TextView en el cual aparecer el texto que deseemos
en cada pestaa. Este layout ser aplicado a cada una de las pestaas que tengamos en pantalla al
momento, este es el cdigo del layout:
<?xml version="1.0" encoding="utf-8"?>
<!-- Lo interesante en este caso es la aplicacin en el atributo
background del archivo tab_selector_trazar.xml para cambiarle
los colores segn el status de la pestaa -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_selector_trazar" >
<TextView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFF"
android:gravity="center"
android:layout_centerInParent="true" />
</RelativeLayout>
Ya definimos como se debe de ver cada una de las pestaas que deber de tener nuestra aplicacin,
ahora vamos a definir la estructura completa, esto qu significa?, pues definir mediante un layout la
ubicacin de donde deben de aparecer las pestaas (tabs), la cantidad de pestaas a mostrar, definir un
espacio para que sean mostrados los contenidos de cada pestaa, y en el caso de este ejemplo agregar
el elemento de ViewPager para poder hacer el movimiento de swipe entre pestaas.
En Android, el elemento principal de un conjunto de pestaas ser el control TabHost. ste va a ser el
contenedor principal de nuestro conjunto de pestaas y deber tener obligatoriamente como id el valor
@android:id/tabhost. Dentro de ste vamos a incluir un LinearLayout que nos servir para
distribuir verticalmente las secciones principales del layout: la seccin de pestaas en la parte superior y
la seccin de contenido en la parte inferior. La seccin de pestaas se representar mediante un
elemento TabWidget, que deber tener como id el valor @android:id/tabs, y como
contenedor para el contenido de las pestaas aadiremos un FrameLayout con el id obligatorio
@android:id/tabcontent. Por ltimo, dentro del FrameLayout incluiremos el contenido de
cada pestaa, normalmente cada uno dentro de su propio layout principal (en mi caso he utilizado
FrameLayout) y con un id nico que nos permita posteriormente hacer referencia a ellos fcilmente
(en mi caso he utilizado por ejemplo los ids tab_1_interna , tab_2_externa , ). En nuestro caso es
necesario agregar el controlador que permite al usuario mover de un tirn a la izquierda y derecha a
travs de diferentes ventanas dicho control es android.support.v4.view.ViewPager,el
nombre de este layout ser view_tabs_layout_trazar.xm.

151



<?xml version="1.0" encoding="utf-8"?>
<!-- Contenedor para las pestaas en una ventana, este contiene dos
hijos, uno es el
un conjunto de etiquetas para las pestaas que el usuario hace
clic para seleccionar
una pestaa especfica, el otro hijo es un objeto FrameLayout el
cual muestra el
contenido de la pgina -->
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id=" @android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@null" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- Aqu ser la seccin de las pestaas y siempre el id
deber de tener el valor
de android:id="@android:id/tabs" -->
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:tabStripEnabled="false" >
</TabWidget>
<!-- contenedor para el contenido de las pestaas con el id
obligatorio "@android:id/tabcontent" -->
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:background="@null" >
<!-- Por cada pestaa que contenga la vista se deber
de incluir un FrameLayout -->
<FrameLayout
android:id="@+id/tab_1_interna"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<FrameLayout
android:id="@+id/tab_2_externa"

152

android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
<!-- Controlador que permite al usuario mover de un tirn a la
izquierda y derecha a travs de
diferentes ventanas -->
<android.support.v4.view.ViewPager
android:id="@+id/pager_trazar_ruta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null" />
</LinearLayout>
</TabHost>
Para terminar con la fase de diseo de interfaz ser necesario tener un layout en el cual tengamos un
concentrador de todos los dems layouts hechos pues son esos layouts una parte del diseo general
dicho layout se llamar fragment_trazar.xml que en verdad es demasiado sencillo su diseo
pues solo tiene un LinearLayout como contenedor principal pero es aqu en donde se usa un nuevo
elemento, se llama include y de lo que se encarga o para lo que sirve es para incluir un layout dentro de
otro slo es necesario usar el atributo layout y especificarle el nombre del layout a incluir. Para caso de
nuestro ejemplo mostramos el siguiente cdigo que ilustrar de mejor manera lo que se dice:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#12ac56"
android:orientation="vertical"
android:baselineAligned="false" >
<!-- El elemento include nos sirve para incluir otros layouts
dentro de este
slo basta con indicar el nombre del layout a incluir -->
<include
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
layout="@layout/view_tabs_layout_trazar" />
</LinearLayout>
Por fin se ha terminado la fase de diseo de la interfaz es necesario ahora entrar al cdigo en java para
poder agregar la funcionalidad necesaria para que nuestra aplicacin funcione de la mejor manera
posible.

153

Agregar funcionalidad a las pantallas, creacin de clases.


Lo primero que haremos ser crear una clase que herede de la clase Fragment, pues esta ser la que
controle la vista o la interfaz de la pestaa que se encargar de mostrar una ruta entre dos puntos en un
mapa de Google Maps, pero todo esto ser dentro de nuestra aplicacin que venimos desarrollando.
Dicha clase le pondremos por nombre TrazarRutaInternaFragment.java que adems de
extender de Fragment vamos a implementar los mtodos de la interfaz de LocationListener, en esta
clase vamos a necesitar de dos clases con sus mtodos que previamente creamos en el paquete
com.android.utm.todosqlite.util,
las
cuales
son
ConnectionDetector,
GMapsDirection.
Lo primero ser verificar la conexin a internet esto lo hacemos en el mtodo onCreate() en esta
parte lo que hacemos es instanciar un objeto de la clase ConnectionDetector, para usar uno de
sus mtodos y comprobar si nuestro dispositivo mvil tiene acceso a interntet, en caso de no tenerlo
muestra un AlertDialog con un mensaje
A grandes rasgos lo que se hace es que en el momento que se ejecuta el mtodo onCreateView se hace
referencia al elemento com.google.android.gms.maps.MapView del layout, es aqu en donde
se mostrar el mapa, posteriormente se inicializa la API de Google Maps Android y as obtener las
caractersticas necesarias para poder usar en el mapa que se obtenga, ahora se procede a obtener los
proveedores para la localizacin, pueden ser varios pero en nuestro caso deseamos que sea mediante el
GPS el proveedor principal, tambin podra ser por medio de WIFI. Instanciamos un objeto de la clase
GMapsDirection de esta clase usaremos el mtodo getDocument(), dicho mtodo empezar el
proceso de armar la url de consulta a Google Maps y de interpretacin de la respuesta del WebService,
este mtodo recibe como parmetros dos objetos del tipo LatLng, el primero es con la posicin actual, el
segundo es la posicin del punto de destino y el tercer parmetro que recibe es el modo de transporte
que utilizaremos para llegar.
Ya casi terminamos ahora falta un mtodo que sea el que trace la ruta (o que la pinte en el mapa), por lo
que crearemos un mtodo que se llame traceRoute(), y que recibe como parmetro un objeto del
tipo Document, en este objeto se encuentran todos los puntos de los que est compuestos la ruta a ser
trazada sobre el MapView, cada punto es un objeto LatLng, pero lo que haremos ser usar el mtodo
getDirection() de la clase GMapsDirection, con este mtodo obtenemos un ArrayList que
contiene objetos LatLng con las coordenas de todos los puntos que responde Google Maps, ahora
craremos un objeto PolylineOptions este objeto es una serie de segmentos de lnea conectados que
pueden formar cualquier forma que desee y se puede utilizar para marcar caminos y rutas en el mapa.
Adems se especifican algunas opciones como el ancho y color de la lnea. Es necesario agregar los
puntos al objeto PolyLine para lo cual empleamos un for para recorrer el arraylist, y con el mtodo add()
del objeto PolyLine se agregan cada uno de los elementos del arreglo, en este punto es necesario
agregar el objeto PolyLine al mapa, y listo hemos terminado pero para mayor claridad veremos un
ejemplo de esta clase con todo el cdigo necesario para un correcto funcionamiento:
package com.android.utm.todosqlite;

154

import java.util.ArrayList;
import org.w3c.dom.Document;
import
import
import
import
import
import
import
import
import
import
import

android.app.AlertDialog;
android.content.Context;
android.location.Criteria;
android.location.Location;
android.location.LocationManager;
android.os.Bundle;
android.support.v4.app.Fragment;
android.view.LayoutInflater;
android.view.View;
android.view.ViewGroup;
android.widget.Toast;

import com.android.utm.todosqlite.util.ConnectionDetector;
import com.android.utm.todosqlite.util.GMapsDirection;
import
com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
/*
* En esta clase heredamos de la clase Fragment de android y vamos
* a implementar la interfaz publica LocationListener
* */
public class TrazarRutaInternaFragment extends Fragment implements
LocationListener{
private
private
private
private
private
private
private
private
private
private
private
private

MapView mMapView;
GoogleMap map;
final double latitude = 19.4325;
final double longitude = -99.131111;
Context context;
LocationManager locationManager;
String provider;
Location location;
GMapsDirection md;
LatLng currentLocation;
double currentLatitude;
double currentLongitude;

155

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container,
Bundle savedInstanceState) {
// Cargar el layout en el fragment
View rootView =
inflater.inflate(R.layout.como_llegar_interna_fragment,
container, false);
/**
* Hacer referencia al elemento
com.google.android.gms.maps.MapView
* del layout aqu ser donde se mostrar el mapa
* */
mMapView = (MapView) rootView.findViewById(R.id.mapa);
// inflar y regresar el layout
mMapView.onCreate(savedInstanceState);
// Necesario para desplegar el mapa obtenido inmediatamente
mMapView.onResume();
try {
/**
* Inicializa la API de Google Maps Android y as
* obtener las caractersticas necesarias para poder
* usar en el mapa ya obtenido
* */
MapsInitializer. initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
map = mMapView.getMap();
map.setMyLocationEnabled(true);
CameraUpdate center = CameraUpdateFactory.newLatLng(new
LatLng(latitude, longitude));
CameraUpdate zoom = CameraUpdateFactory.zoomTo(12);
map.moveCamera(center);
map.animateCamera(zoom);
context = getActivity();
// Obtener los proveedores de localizacin que existane en
nuestro dispositivo mvil
locationManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
// Una clase indicando los criterios de aplicacin para la
seleccin de un proveedor de ubicacin.
Criteria criteria = new Criteria();

156

// Aqu escogemos el mejor proveedor de acuerdo a los


criterios
provider = locationManager.getBestProvider(criteria, true);
/**
* Devuelve un objeto Location indicando los datos
* de la ltima ubicacin conocida obtenida del
* proveedor determinado.
* */
location = locationManager.getLastKnownLocation(provider);
if (location != null) {
System.out.println("Provider " + provider + " has been
selected.");
onLocationChanged(location);
} else {
Toast.makeText(context, "Localizacin no disponible",
Toast.LENGTH_LONG).show();
}
/**
* De esta manera es la forma en la que se agrega
* un marcador al mapa as como sus diferentes opciones
* que tendr el marcador, este marcador nos indicar el
* punto de destino
*/
Marker marker = map.addMarker(new MarkerOptions()
.position(new LatLng(latitude,
longitude)).title("Este es el destino")
.snippet("Hasta aqu debemos de llegar")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_action_p
lace)));
/**
* Se agrega un listener al marker, de esta
* manera se puede controlar si se desea que
* haga alguna accin
* */
map.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
Toast.makeText(
context,
"Marcador pulsado:\n" +
marker.getTitle(),
Toast.LENGTH_SHORT).show();
return false;
}
});

157

/**
* Se agrega un listener al snipet (la informacin
* que aparece al tocar el marker), de esta
* manera se puede controlar si se desea que
* haga alguna accin, como por ejemplo mostrar
* otra vista
* */
map.setOnInfoWindowClickListener(new
OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
Toast.makeText(
context,
"Snipet pulsado:\n" +
marker.getTitle(),
Toast.LENGTH_SHORT).show();
}
});
/**
* Instanciamos un objeto de la clase
* GMapsDirection
* */
md = new GMapsDirection(this);
// Crear un nuevo objeto LatLng con la longitud y latitud
destino
LatLng location = new LatLng(latitude, longitude);
/**
* Ejecutamos el mtodo getDocument, dicho mtodo
* empezar el proceso de armar la url de consulta
* a Google Maps y de interpretacin de la respuesta
* */
md.getDocument(currentLocation, location,
GMapsDirection.MODE_DRIVING);
return rootView;
}
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setRetainInstance(true);
/**
* En esta parte lo que hacemos es instanciar un
* objeto de la clase ConnectionDetector, para
* usar uno de sus mtodos y comprobar si mi
* dispositivo mvil tiene acceso a interntet, en

158

* caso de no tenerlo muestra un AlertDialog con


* un mensaje
* */
ConnectionDetector connectionDetector = new
ConnectionDetector(getActivity());
if(!connectionDetector.isConnectedToInternet()){
AlertDialog.Builder builder = new
AlertDialog.Builder(getActivity());
builder.setMessage("Se requiere conexin a Internet
para visualizar el mapa.")
.setTitle("Error");
AlertDialog dialog = builder.create();
dialog.show();
}
}
/**
* Mtodo que se encarga de trazar la ruta
* o mostrarla en el mapa
* */
public void traceRoute(Document doc) {
// Detectar si hay conexin a internet
ConnectionDetector connectionDetector = new
ConnectionDetector(getActivity());
if(!connectionDetector.isConnectedToInternet()){
AlertDialog.Builder builder = new
AlertDialog.Builder(getActivity());
builder.setMessage("Se requiere conexin a Internet")
.setTitle("Error");
AlertDialog dialog = builder.create();
dialog.show();
}
/**
* Aqu lo que sucede es que con el mtodo getDirection
obtenemos
* un ArrayList que contiene objetos LatLng con las
coordenas de
* todos los puntos que responde Google Maps
* */
ArrayList<LatLng> directionPoint = md.getDirection(doc);
/**
* Creamos un objeto PolylineOptions este objeto
* es una serie de segmentos de lnea conectados
* que pueden formar cualquier forma que desee y
* se puede utilizar para marcar caminos y rutas
* en el mapa. Adems se especifican algunas
* opciones como el ancho y color de la lnea.
* */
PolylineOptions rectLine = new

159

PolylineOptions().width(8).color(getResources().getColor(R.color.route
));
/*
* En este for agregamos los puntos con sus
* coordenadas a la Polyline
* */
for(int i = 0 ; i < directionPoint.size() ; i++) {
rectLine.add(directionPoint.get(i));
}
// Agregar la Polyline al mapa para su visualizacin
map.addPolyline(rectLine);
}
@Override
public void onResume() {
super.onResume();
if (null != mMapView)
mMapView.onResume();
}
@Override
public void onPause() {
super.onPause();
if (null != mMapView)
mMapView.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
if (null != mMapView)
mMapView.onDestroy();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (null != mMapView)
mMapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
if (null != mMapView)
mMapView.onLowMemory();
}
/*

160

* Este mtodo se estar ejecutando cada vez que el GPS detecte


* que la posicin actual cambia y es aqu en donde actualizaremos
* la variable currentLocation que es un objeto LatLng con
posicin actual
* */
@Override
public void onLocationChanged(Location location) {
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
currentLocation = new LatLng(currentLatitude,
currentLongitude);
}
}

Nuestro proyecto de ejemplo tiene dos pestaas y estas dos pestaas son para mostrar dos formas de
trazar una ruta, la forma anterior que acabamos de ver muestra la forma en la que podemos insertar un
mapa dentro de la aplicacin, obtenemos nuestra posicin actual mediante el GPS del mvil, hacemos
una consulta a Google Maps e interpretamos esa informacin para poder mostrarla en el mapa, tambin
vimos como podemos agregarle objetos a el mapa (la ruta, y el marker que indica la posicin destino). La
segunda opcin trazar tambin una ruta entre un punto actual y un punto de destino que es fijo, pero
ahora utilizaremos una aplicacin externa en este caso la aplicacin de Maps (en caso de tenerla
instalada).

161

Es muy simple el cdigo de esta nueva clase que se llamar TrazarRutaExternaFragment.java, aqu
muestro todo el cdigo de esta clase:
package com.android.utm.todosqlite;
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.content.Context;
android.content.Intent;
android.location.Location;
android.location.LocationManager;
android.net.Uri;
android.os.Bundle;
android.support.v4.app.Fragment;
android.view.LayoutInflater;
android.view.View;
android.view.View.OnClickListener;
android.view.ViewGroup;
android.widget.Button;
android.widget.TextView;
android.widget.Toast;

public class TrazarRutaExternaFragment extends Fragment {


private
private
private
private
private
private
private
private
private

TextView latitudDestino;
TextView longitudDestino;
TextView latitudOrigen;
TextView longitudOrigen;
Button btnTrazar;
Context context;
LocationManager locManager;
Location loc;
android.location.LocationListener locListener;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container,
Bundle savedInstanceState) {
View rootView =
inflater.inflate(R.layout.como_llegar_externa_fragment, container,
false);
/*
* Instanciar los elementos del layout
* con objetos para poder interactuar
* con ellos desde el cdigo
* */
latitudDestino = (TextView)
rootView.findViewById(R.id.latitud_destino_txt);
longitudDestino = (TextView)
rootView.findViewById(R.id.longitud_destino_txt);
latitudOrigen = (TextView)
rootView.findViewById(R.id.latitud_origen_txt);

162

longitudOrigen = (TextView)
rootView.findViewById(R.id.longitud_origen_txt);
btnTrazar = (Button) rootView.findViewById(R.id.btn_trazar);
context = getActivity();
// Manda llamar el mtodo para obtener la posicin actual
comenzarLocalizacion();
// Se agrega una accin al botn para llamar el mtodo
trazarRuta()
btnTrazar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
trazarRuta();
}
});
return rootView;
}
/*
* En este mtodo se crea la URL para
* solicitar la ruta, esto se hace
* mediante un Intent*/
protected void trazarRuta() {
Intent intentMap = new
Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://maps.google.com/maps?addr="+loc.getLatitude()+"
, "+loc.getLongitude() +
"&daddr=" + latitudDestino.getText()
+", " + longitudDestino.getText()));
startActivity(intentMap);
}
/*
* Mtodo para obtener la posicin actual
* mediante el GPS del dispositivo mvil
* */
private void comenzarLocalizacion() {
// Obtenemos una referencia al LocationManager
locManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
//Si el GPS no est activado
if(!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){

163

mostrarAvisoGpsDesahibilitado();
}
// Obtenemos la ltima posicin conocida
loc =
locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
// Nos registramos para recibir actualizaciones de la
posicin
locListener = new android.location.LocationListener() {
@Override
public void onLocationChanged(Location location) {
loc = location;
latitudOrigen.setText(loc.getLatitude()+"");
longitudOrigen.setText(loc.getLongitude()+"");
}
@Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1,
Bundle arg2) {
// TODO Auto-generated method stub
}
};
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10000, 0, locListener);
}
// Mtodo que se usa para mostrar un mensaje de que el GPS est
deshabilitado
private void mostrarAvisoGpsDesahibilitado() {
Toast.makeText(getActivity().getApplicationContext(), "El
GPS se encuentra deshabilitado, por favor habilitar",
Toast.LENGTH_LONG).show();
}

164

}

Las clases anteriores fueron creadas para dar control a los fragments que tendramos en cada una de las
pestaas, ahora es necesario agregar las clases que se encargaran de controlar el funcionamiento de las
tabs y del ViewPager.
Para implementar ViewPager ser necesario un adaptador, el cual se encargara de administrar todas las
vistas. Lo ideal ser implementar una clase que se extienda de FragmentPagerAdapter la cual lanzar los
Fragments (Vistas) necesarios. Hablemos un poco de FragmnetPagerAdapter y de Fragments para
entenderlos mejor y as saber de que estamos haciendo uso. FragmenPagerAdapter es una
implementacin de PagerAdapter que facilita el uso de Fragments dentro de un ViewPager. Esta versin
de pager es comnmente usada en el manejo de fragments estticos parecido al manejo de Tabs.
FragmentPagerAdapter mantiene los fragments visitados en memoria por lo cual es til para cuando se
manejan un nmero reducido de Fragments. La clase creada se llama
TrazarRutaPagerAdapter.java, y a continuacin veremos el cdigo:
package com.android.utm.todosqlite;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class TrazarRutaFragmentPagerAdapter extends


FragmentPagerAdapter{
/** Este valor debe estar adecuado segn la cantidad de Fragments
que existan o se vayan a mostrar */
final int PAGE_COUNT = 2;
/** Constructor de la clase */
public TrazarRutaFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
/** Este mtodo ser invocado cuando una pgina es solicitada para
crearse */
@Override
public Fragment getItem(int arg0) {
Bundle data = new Bundle();
Fragment fragment = null;
/** Deber de existir una opcin (case) por cada uno de los
fragments a ser visibles en pantalla */
switch(arg0){
/** Pestaa para TrazarRutaInternaFragment es seleccionada
*/

165

case 0:
TrazarRutaInternaFragment trazarInternaFragment = new
TrazarRutaInternaFragment();
data.putInt("current_page", arg0+1);
trazarInternaFragment.setArguments(data);
fragment = trazarInternaFragment;
break;
/** Pestaa para TrazarRutaExternaFragment es seleccionada
*/
case 1:
TrazarRutaExternaFragment trazarExternaFragment = new
TrazarRutaExternaFragment();
data.putInt("current_page", arg0+1);
trazarExternaFragment.setArguments(data);
fragment = trazarExternaFragment;
break;
}
return fragment;
}
/** Retorna el nmero de pginas */
@Override
public int getCount() {
return PAGE_COUNT;
}
}
Con esto ya tendramos montada toda la estructura de controles necesaria para nuestra interfaz de
pestaas. Sin embargo, con esto no es suficiente. Necesitamos asociar de alguna forma cada pestaa
con su contenido, de forma que el control se comporte correctamente cuando cambiamos de pestaa. Y
esto tendremos que hacerlo mediante cdigo.
package com.android.utm.todosqlite;
import com.android.utm.todosqlite.util.Utils;
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.app.ActionBar;
android.content.Intent;
android.os.Bundle;
android.support.v4.app.FragmentActivity;
android.support.v4.app.FragmentManager;
android.support.v4.view.ViewPager;
android.util.DisplayMetrics;
android.view.LayoutInflater;
android.view.Menu;
android.view.MenuItem;
android.view.View;
android.view.ViewGroup;
android.widget.TabHost;
android.widget.TabHost.TabSpec;

166

import android.widget.TextView;
/**
* @author NelsonPadilla
*
*/
public class TrazarRutaFragment extends FragmentActivity implements
TabHost.OnTabChangeListener{
private
private
private
private
private
private
private
private
private
private

static final String TAB_TRAZAR_INTERNA = "INTERNA";


static final String TAB_TRAZAR_EXTERNA = "EXTERNA";
ViewPager mPager;
FragmentManager supportFragmentManager;
TabHost mTabHost;
int mCurrentTab = 0;
View indicator;
TextView textTab;
int DeviceWidth;
int DeviceHeight;

public TrazarRutaFragment() {
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_trazar);
// Calcular la resolucin del dispositivo
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

DeviceWidth = metrics.widthPixels;
DeviceHeight = metrics.heightPixels;
// Obtener el ActionBar
ActionBar actionBar = getActionBar();
// Establecer si queremos que la accin del icono sea
habilitado como ir a Home
actionBar.setDisplayHomeAsUpEnabled(true);
/**
* Obtener una referencia al ViewPager en el layout
* con esto lograremos hacer el swipe
* */
mPager = (ViewPager) findViewById(R.id.pager_trazar_ruta);
/**
* Cuando se usa un FragmetnActivity es necesario

167

* ejecutar este mtodo para obtener el FragmentManager


* para interactuar con los frgments asociados
* con esta activity
* */
supportFragmentManager = getSupportFragmentManager();
/**
* Definiendo un listener para el cambio de pginas
* */
ViewPager.SimpleOnPageChangeListener pageChangeListener =
new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
/**
* Al ocurrir el evento de un cambio de pgina
* lo que hacemos es seleccionar o establecemos
* cul es la tab actual
* */
mTabHost.setCurrentTab(position);
}
};
/** Estableciendo el pageChange listner para el viewPager */
mPager.setOnPageChangeListener(pageChangeListener);
/** Creando una instancia de FragmentPagerAdapter */
TrazarRutaFragmentPagerAdapter planningFragmentPagerAdapter
= new TrazarRutaFragmentPagerAdapter(supportFragmentManager);
/** Estableciendo el objeto FragmentPagerAdapter al objeto
viewPager */
mPager.setAdapter(planningFragmentPagerAdapter);
/*
* Establecemos un enlace entre el objeto TabHost
* con el elemento contenedor de las tabs en el layout
* */
mTabHost = (TabHost) findViewById(android.R.id.tabhost);
setupTabs();
// Se agrega un listener, para detectar el momento en que
una tab es cambiada
mTabHost.setOnTabChangedListener(this);
// Se establece cual es la pestaa seleccionada de origen
mTabHost.setCurrentTab(mCurrentTab );
// manualmente iniciando la carga en la primera tab
updateTab(TAB_TRAZAR_INTERNA, R.id.tab_1_interna);
}

168

/*
* Mtodo en el que se establece
* la accin a realizar al momento
* de seleccionar algn elemento de
* la ActionBar
* */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
/*
* En caso de haber seleccionado el botn
* habilitado como Home cargar la clase
* MainActivity
* */
case android.R.id.home:
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
// Something else
}
return super.onOptionsItemSelected(item);
}
/*
* Mtodo que se encargar de actualizar la vista,
* esto es que cambiar de fragment segn sea la
* tab seleccionada
* */
private void updateTab(String arg0, int placeholder) {
if (supportFragmentManager.findFragmentByTag(arg0) == null)
{
if (arg0.equals(TAB_TRAZAR_INTERNA)) {
new TrazarRutaInternaFragment();
}
if (arg0.equals(TAB_TRAZAR_EXTERNA)) {
new TrazarRutaExternaFragment();
}
}
}
/*
* Mtodo encargado de */
private void setupTabs() {
/*
* Llamar setup() antes de aadir pestaas si se carga
TabHost usando findViewById ().
* */
mTabHost.setup(); // Importante!!!

169

// Se agrega cada una de las tabs, en nuestro ejemplo slo


son 2
mTabHost.addTab(newTab(TAB_TRAZAR_INTERNA,
R.id.tab_1_interna));
mTabHost.addTab(newTab(TAB_TRAZAR_EXTERNA,
R.id.tab_2_externa));
}
/*
* Este mtodo de lo que se encarga es de crear un objeto
TabSpec.
* Los objetos TabSpec contienen toda la informacin de cada Tab
*
* */
private TabSpec newTab(String tag, int tabContentId) {
indicator =
LayoutInflater.from(this).inflate(R.layout.tab_layout_trazar,(ViewGrou
p) findViewById(android.R.id.tabs), false);
textTab = (TextView) indicator.findViewById(R.id.icon);
textTab.setTextSize(20);
if(tag.equals(TAB_TRAZAR_INTERNA)){
textTab.setText(getString(R.string.title_section1));
}
if(tag.equals(TAB_TRAZAR_EXTERNA)){
textTab.setText(getString(R.string.title_section2));
}
TabSpec tabSpec = mTabHost.newTabSpec(tag);
tabSpec.setIndicator(indicator);
tabSpec.setContent(tabContentId);
Utils util = new Utils();
// Configuramos el ancho del textView al 50% de la pantalla
del mvil
util.AdjustWidthScreen(DeviceWidth,DeviceHeight,50,textTab);
// Configuramos el alto del textView al 8% de la pantalla
del mvil
util.AdjustHeightScreen(DeviceWidth,DeviceHeight,8,textTab);
return tabSpec;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflar el men; esto agrega items a la barra de accin si
es que est presente.
getMenuInflater().inflate(R.menu.tareas, menu);
return true;
}
/*

170

* Mtood que se encarga de establecer las


* acciones a realizar cuando se hace un
* cambio de Tabs
* */
@Override
public void onTabChanged(String arg0) {
if (TAB_TRAZAR_INTERNA.equals(arg0)) {
// Se establece el nuevo fragment en la vista
updateTab(arg0, R.id.tab_1_interna);
mCurrentTab = 0;
// Se establece en el ViewPager cual debe de ser el
fragment visible
this.mPager.setCurrentItem(mCurrentTab);
return;
}
if (TAB_TRAZAR_EXTERNA.equals(arg0)) {
// Se establece el nuevo fragment en la vista
updateTab(arg0, R.id.tab_2_externa);
mCurrentTab = 1;
// Se establece en el ViewPager cual debe de ser el
fragment visible
this.mPager.setCurrentItem(mCurrentTab);
return;
}
}
}

Crear un lector QR
La inclusin de software que lee cdigos QR en telfonos mviles, ha permitido nuevos usos orientados
al consumidor, que se manifiestan en comodidades como el dejar de tener que introducir datos de
forma manual en los telfonos. Las direcciones y los URLs se estn volviendo cada vez ms comunes en
revistas y anuncios . El agregado de cdigos QR en tarjetas de presentacin tambin se est haciendo
comn, simplificando en gran medida la tarea de introducir detalles individuales de un nuevo cliente en
la agenda de un telfono mvil.
Es por esto que he decidido hacer un ejemplo simple y bsico de cmo crear uno. Este ejemplo estar
incluido dentro de la aplicacin que hemos venido desarrollando a lo largo del curso, es por eso que en
nuestro men (NavigationDrawer), agregaremos una nueva opcin para desde ah mandar ejecutar el
lector. El ejemplo consistira en que el lector creado podr leer cdigos QR, estos cdigos sern los ids de
los registros que tenemos en la base de datos de nuestro ejemplo, por lo que al leer el cdigo (que ser
un id), podremos hacer una consulta a la base de datos, obtener los datos y presentarlos en pantalla, un
ejemplo muy simple pero muy ilustrativo de todo lo que se podra hacer al leer uno de estos cdigos.

171

Android por default no integra en su api un lector de cdigos QR, para lo cul ser necesario agregar una
librera que nos ayudar y facilitar el trabajo de lectura e interpretacin del cdigo.
Es as que antes de empezar tendremos que aclarar dos cosas: Qu son los cdigos QR?, y segundo
dnde obtenemos la librera, y cmo la instalamos en nuestro proyecto?.

Qu son los cdigos QR?


respondiendo a la primera pregunta podemos decir que un cdigo QR (quick response code, cdigo de
respuesta rpida) es un mdulo til para almacenar informacin en una matriz de puntos o un cdigo
de barras bidimensional creado por la compaa japonesa Denso Wave, subsidiaria de Toyota, en 1994.
Se caracteriza por los tres cuadrados que se encuentran en las esquinas y que permiten detectar la
posicin del cdigo al lector. La sigla QR se deriva de la frase inglesa Quick Response (Respuesta
Rpida en espaol), pues los creadores (un equipo de dos personas en Denso Wave, dirigido por
Masahiro Hara) tenan como objetivo que el cdigo permitiera que su contenido se leyera a alta
velocidad. Los cdigos QR son muy comunes en Japn y de hecho son el cdigo bidimensional ms
popular en ese pas.

Librera ZXing
El proyecto ZXing es una librera de procesamiento de imagen que es de cdigo abierto, y procesa
cdigos de barra en 1D/2D en mltiples formatos. Para descargarlo lo haremos de la siguiente URL
http://repo1.maven.org/maven2/com/google/zxing/core/3.0.0/core-3.0.0.jar, y la instalacin ser muy
simple ya descargado, habr que copiar el archivo descargado (core-3.0.0.jar) en la carpeta
/ruta/workspace/ToDoSQLite/libs/ ya con esto podemos usar la librera en nuestro proyecto.
Permisos en el AndroidManifest
Cmo lo hemos visto y hecho en secciones anteriores empezaremos nuestro ejemplo con la declaracin
de permisos en el archivo AndroidManifest.xml de nuestro proyecto, por qu es necesario ahora
declarar permisos?, en nuestro caso como vamos a usar hardware de nuestro dispositivo mvil (la
cmara), es necesario hacerlo, y as va a pasar para cualquier otro proyecto que hagamos en el futuro,
hay que definir los permisos para poder hacer uso del hardware o servicios que tenga nuestro mvil,
tambin nuestro proyecto har una pequea vibracin en el momento de detectar un cdigo para
avisarle al usuario, bueno tambin tenemos que declarar permisos para poder usar la vibracin, e
incluso el permiso para solicitar el autofocus de la cmara, y he aqu lo que habra que colocar en
nuestro AndroidManifest para este ejemplo:
<!-- Permisos para utilizar la cmara, para que vibre y para que la
cmara haga autofocus -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature
android:name="android.hardware.camera.autofocus"

172

android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
Y para nuestro proyecto vamos a dar permisos a nuestras actividades que usaremos, que slo sern dos:
<activity
android:name="com.android.utm.todosqlite.QRDetailActivity"
android:screenOrientation="portrait" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.android.utm.todosqlite.MainActivity" />
</activity>
<activity
android:name="com.android.utm.todosqlite.ZXingActivity"
android:configChanges="keyboard|keyboardHidden|orientation"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

Creacin de interfaces grficas


Primero empezaremos con el layout de la actividad encargada de usar la cmara para leer y decodificar
el cdigo QR, la verdad no nos meteremos a fondo de explicar esto, slo hablaremos algo de lo que es o
para lo que sirve un nuevo elemento que veremos en este layout y que se llama SurfaceView,
segn la documentacin oficial disponible aqu , Proporciona una superficie de dibujo dedicado
incrustado dentro de una jerarqua de vistas. Puedes controlar el formato de esta superficie y si se
quiere, su tamao, SurfaceView se encargara de colocar la superficie en el lugar correcto en la
pantalla. La superficie esta ordenada respecto del eje Z de modo que se encuentra detrs de la ventana
que contendr al SurfaceView, esta crea un agujero en la ventana para poder mostrar su superficie.
La jerarqua de vistas se va a encargar de manejar la superficie con los dems componentes que hay en
la ventana por lo que se puede combinar SurfaceView con cualquier otro elemento como botones
en la parte superior de la superficie aunque esto puede afectar el rendimiento.
En pocas palabras lo que pasa aqu es que en el SurfaceView es en donde se mostrar lo que se ve
en la cmara. El layout que vamos a ocupara para nuestro proyecto se llamar
activity_capture.xml y esto es lo que contendr:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout

173

xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/preview_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<View
android:id="@+id/center_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:background="#00000000" />
</RelativeLayout>
</FrameLayout>
En el momento en que ya se est ejecutando la aplicacin y estemos leyendo algn cdigo QR veremos
algo como lo siguiente:

174

Ya terminada la creacin del layout de la cmara para el lector es momento de proceder a la creacin
del layout que mostrar la vista de resultado, en este layout lo que veremos ser el resultado de una
consulta a la base de datos y en la cual utilizaremos lo que lemos del cdigo QR, pues en el cdigo
tendremos el id del registro que queremos leer. El diseo de la interfz es demasiado simple pues no es
el caso de este ejemplo ver como disear o construir las interfaces, y bueno he aqu el cdigo del layout
que llevar por nombre activity_qr_detail.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/darker_gray"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Categora" />
<TextView
android:id="@+id/category_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Categora" />
</LinearLayout>
<LinearLayout
android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Resumen" />
<TextView

175

android:id="@+id/summary_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<TextView
android:id="@+id/description_result"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="top" />
</LinearLayout>
La interfaz que acabamos de crear al momento de ya haber ledo un cdigo vlido veremos algo como lo
que se muestra a continuacin (la verdad una interfaz muy simple):


Clases para el lector de QR
En este ejemplo se tiene una nueva clase en el paquete com.android.utm.todosqlite.util
(recordemos que estos paquetes son los de mi proyecto, aqu deberan de tener de acuerdo a los suyos)
esta clase, de qu se encargar o para qu nos servir?, pues para algo muy simple como hacer que el
mvil vibre y produzca un beep, en el momento que decodifique un cdigo QR. Primero para esto ya
tenemos los permisos en establecidos en el AndroidManifes.xml de nuestro proyecto, segundo lo que
hace falta antes de continuar ser poner un archivo de audio en nuestro proyecto que ser el que haga
el beep. Es necesario crear una nueva carpeta dentro de la carpeta res de nuestro proyecto a la que

176

llamaremos raw, quedando de esta manera /res/raw/beep.ogg, y como vemos el archivo se llamar
beep.ogg, en caso de no contar con ninguno se puede descargar desde esta direccin
http://soundbible.com/1251-Beep.html, esta pgina es una biblioteca de sonidos, si no les agrada ese
pueden colocar el que deseen slo que deben de recordar de cambiar el nombre del archivo en el
cdigo por el del nuevo archivo de audio seleccionado para que funcione de la manera adecuada, estos
son todos los preparativos que habra que hacer respecto a esta clase cuyo nombre ser
BeepManager.java
(recuerda
de
poner
la
clase
en
el
paquete
com.android.utm.todosqlite.util), esta clase la podemos utilizar as como est en cualquier
otro proyecto as sin modificaciones, salvo el nombre del archivo de audio que usemos, si es otro al que
se especifica en el cdigo ser necesario cambiarlo. Este es el cdigo:

package com.android.utm.todosqlite.util;
import
import
import
import
import
import
import
import
import

android.app.Activity;
android.content.Context;
android.content.SharedPreferences;
android.content.res.AssetFileDescriptor;
android.media.AudioManager;
android.media.MediaPlayer;
android.os.Vibrator;
android.preference.PreferenceManager;
android.util.Log;

import java.io.IOException;
import com.android.utm.todosqlite.R;
import com.android.utm.todosqlite.ZXingActivity;
/**
* Manages beeps and vibrations for {@link ZXingActivity}.
*/
public final class BeepManager {
private static final String TAG =
BeepManager.class.getSimpleName();
private static final float BEEP_VOLUME = 0.10f;
private static final long VIBRATE_DURATION = 200L;
private
private
private
private

final Activity activity;


MediaPlayer mediaPlayer;
boolean playBeep;
boolean vibrate;

/*
* Constructor de la clase que inicia
* variables y pone las condiciones de

177

* inicio para el audio y para la vibracion


* */
public BeepManager(Activity activity) {
this.activity = activity;
this.mediaPlayer = null;
updatePrefs();
}
void updatePrefs() {
/*
* Obtiene las preferencias compartidas del contexto
* relacionado con este contexto
* */
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(activity);
playBeep = shouldBeep(prefs, activity);
vibrate = true;//
prefs.getBoolean(PreferencesActivity.KEY_VIBRATE,
// false);
if (playBeep && mediaPlayer == null) {
// The volume on STREAM_SYSTEM is not adjustable, and
users found it
// too loud,
// so we now play on the music stream.
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer = buildMediaPlayer(activity);
}
}
/*
* Con este mtodo se inicia el reproductor e iniciar
* la reproduccin del archivo de audio, as como inicia
* la vibracin del mvil
* */
public void playBeepSoundAndVibrate() {
if (playBeep && mediaPlayer != null) {
mediaPlayer.start();
}
if (vibrate) {
Vibrator vibrator = (Vibrator)
activity.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
/*
* Mtodo que determina si el sonido del beep
* se podr reproducir, esto se debe a las
* condiciones en las que se tengan del volumen

178

* del audio de todo el sistema. Si est en modo


* silencio el beep no se reproduce
* */
private static boolean shouldBeep(SharedPreferences prefs,
Context activity) {
boolean shouldPlayBeep = true;//
prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP,
// true);
if (shouldPlayBeep) {
// See if sound settings overrides this
AudioManager audioService = (AudioManager) activity
.getSystemService(Context.AUDIO_SERVICE);
if (audioService.getRingerMode() !=
AudioManager.RINGER_MODE_NORMAL) {
shouldPlayBeep = false;
}
}
return shouldPlayBeep;
}
/*
* En este mtodo se construye el reproductor de audio
* se establecen todas las condiciones que deber de
* tener el MediaPlayer
* */
private static MediaPlayer buildMediaPlayer(Context activity) {
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// When the beep has finished playing, rewind to queue up
another one.
mediaPlayer.setOnCompletionListener(new
MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer player)
{
player.seekTo(0);
}
});
AssetFileDescriptor file =
activity.getResources().openRawResourceFd(
R.raw.beep);
try {
mediaPlayer.setDataSource(file.getFileDescriptor(),file.getStartO
ffset(), file.getLength());
file.close();
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
} catch (IOException ioe) {
Log.w(TAG, ioe);

179

mediaPlayer = null;
}
return mediaPlayer;
}
}
Ahora es el turno para la clase de la activity que mostrar el resultado y llamar a la consulta dicha clase
la llamaremos QRDetailActivity.java, esta clase tiene una funcionalidad muy similar a la de
DetailsActivity.java, salvo que en esta solo tiene la funcionalidad de mostrar resultados no
hace modificaciones de datos. Algo en lo que me detendr a explicar es la forma en la que recuperamos
el dato del id que es envado desde la clase ZxingActivity.java (en este punto an no la hemos
hecho), dicho parmetro se manda en un objeto Bundle, y es de esta manera en la que se mandan
parmetros entre actividades, el cdigo que se encarga de hacer esto es colocado dentro de mtodo
onCreate(), y es el siguiente:
/*
* Recuperamos los parmetros que enviamos a esta
* activity
* */
mRowId = null;
Bundle extras = getIntent().getExtras();
mRowId = (bundle == null) ? null : (Long)
bundle.getSerializable(DBAdapter.KEY_ROWID);
if (extras != null) {
mRowId = extras.getLong(DBAdapter.KEY_ROWID);
}
Todo el dems cdigo est comentado para su comprensin por esto es que a continuacin se los
muestro:
package com.android.utm.todosqlite;
import
import
import
import
import
import
import
import
import
import

android.app.ActionBar;
android.content.Intent;
android.database.Cursor;
android.os.Bundle;
android.support.v4.app.FragmentActivity;
android.view.Menu;
android.view.MenuItem;
android.view.View;
android.view.View.OnClickListener;
android.widget.TextView;

import com.android.utm.todosqlite.database.DBAdapter;
public class QRDetailActivity extends FragmentActivity implements
OnClickListener {

180

private
private
private
private
private

DBAdapter mDbHelper;
TextView categoryResult;
TextView summaryResult;
TextView descriptionResult;
Long mRowId;

@Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
/**
* Se crea una instancia de la clase DBAdapter,
* el constructor de la clase mandar a crear la BD si no
existe,
* en caso de ya existir solo crear la conexin a la BD
* */
mDbHelper = new DBAdapter(this);
// Abre la conexin a la BD
mDbHelper.open();
// Cargamos el layout de nuestro fragment
setContentView(R.layout.activity_qr_detail);
/*
* Inicializamos los objetos y los enlazamos con
* los elementos (views) del layout
* */
categoryResult = (TextView)
findViewById(R.id.category_result);
summaryResult = (TextView)
findViewById(R.id.summary_result);
descriptionResult = (TextView)
findViewById(R.id.description_result);
/*
* Recuperamos los parmetros que enviamos a esta
* activity
* */
mRowId = null;
Bundle extras = getIntent().getExtras();
mRowId = (bundle == null) ? null : (Long)
bundle.getSerializable(DBAdapter.KEY_ROWID);
if (extras != null) {
mRowId = extras.getLong(DBAdapter.KEY_ROWID);
}

181

// Mandamos llamar al mtodo que se encargar de llenar los


campos en caso de ser una edicin
populateFields();
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
/*
* Mtodo que permite llenar los campos del formulario
* en el caso de que sea una edicin, si no es una
* edicin los campos ser dejados vacos
* */
private void populateFields() {
/*
* Confirmamos que la variable mRowId no est nula,
* esto confirma que se trata de una edicin
* */
if (mRowId != null) {
/*Recuperamos los datos de la tarea que coincide con
la variable mRowId*/
Cursor todo = mDbHelper.recuperaTarea(mRowId);
/*
* El mtodo startManagingCursor que se hereda de la
clase Activity
* nos sirve o nos ayuda para tener un mejor control
del cursor, pues
* este se adaptar al ciclo de vida de la activity,
esto es que si
* la activity es detenida el cursor automticamente
llamar al mtodo
* deactivate(), y cuando la activity se reinicie se
llamr al mtodo
* requery() para reiniciar el cursor. Tambin nos
ayudar al momento
* en que la activity sea destruida el Cursor ser
cerrado automticamente
*/
startManagingCursor(todo);
categoryResult.setText(todo.getString(todo.getColumnIndexOrThrow(
DBAdapter.KEY_CATEGORY)));
// Rellenamos los otros valores con lo que tengamos en
la BD
summaryResult.setText(todo.getString(todo.getColumnIndexOrThrow(D
BAdapter.KEY_SUMMARY)));

182

descriptionResult.setText(todo.getString(todo.getColumnIndexOrThr
ow(DBAdapter.KEY_DESCRIPTION)));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
return super.onCreateOptionsMenu(menu);
}
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
/*
* Reacciona al evento del botn
* Up/Home y nos regresa a la
* activity indicada
* */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
// Something else
}
return super.onOptionsItemSelected(item);
}
}
Por ltmo es turno de la creacin de la clase que se encargar de leer e interpretar el cdigo QR dicha
clase llevar por nombre ZxingActivity.java en esta clase no explicar todo lo que hace, pero son
mtodos que deben de ir y a los cuales no sera conveniente modificarles o moverles algo, pero si
debemos de poner atencin al mtodo onPreviewFram(), aqu muestro el cdigo de este mtodo:
/** Camera.PreviewCallback */
/*
* En este motodo se hace la captura de la imagen
* del cdigo QR y la decodifica, a su vez manda
* llamar a la activity QRDetailActivity para que
* se muestre el detalle de la consulta
* */

183

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
View centerView = (View)findViewById(R.id.center_view);
int left = centerView.getLeft() * previewPoint.x /
screenPoint.x;
int top = centerView.getTop() * previewPoint.y /
screenPoint.y;
int width = centerView.getWidth() * previewPoint.x /
screenPoint.x;
int height = centerView.getHeight() * previewPoint.y /
screenPoint.y;
PlanarYUVLuminanceSource source
PlanarYUVLuminanceSource(

= new
data,
previewPoint.x,
previewPoint.y,
left,
top,
width,
height,
false);

/*
* Se crea un objeto BinaryBitmap que contiene la imagen del
cdigo QR
* que se acaba de leer
* */
BinaryBitmap bitmap = new BinaryBitmap(new
HybridBinarizer(source));
/*
* Creamos el objeto que se encarga de leer el cdigo QR
* */
MultiFormatReader reader = new MultiFormatReader();
try {
/*
* Se decodifica la imagen que capt el lector
* con la cmara y se guarda en un objeto Result
* */
Result result = reader.decode(bitmap);
// Ejecutamos el mtodo que ejecuta el beep y hace vibrar
el telfono
beepManager.playBeepSoundAndVibrate();
/*
* Si el objeto Result no est vaco creamos un
* intent y mandamos ejecutar la activity
QRDetailActivity*/
if(result.getText()!=null){
/*

184

* Creacin del intent


* */
final Intent i = new Intent(this,
QRDetailActivity.class);
/*
* Declaramos los parametros que van a ser
enviados a
* la otra activity
* */
i.putExtra("_id",
Long.parseLong(result.getText()));
// iniciamos la ejecucin de la acivity
startActivity(i);
continua=false;
//ejecutamos este mtodo para que si damos al botn
back en la siguiente activity ya no podamos entrar a esta
finish();
} else {
continua=false;
}
} catch (Exception e) {

} finally {
if(continua){
Camera.Parameters parameters =
myCamera.getParameters();
if
(!parameters.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_FIXED)
) {
myCamera.autoFocus(this);
}
}
}
}
Pues es aqu donde se lee el cdigo QR y tambin en donde se descifra, es por eso que aqu si pueden
existir modificaciones al cdigo, esto va de la mano de lo que quieren que haga si aplicacin, en el caso
de este ejemplo slo leemos el QR y lo interpretamos para luego mandar el dato ledo como un
parmetro a la siguiente actividad, a continuacin viene el cdigo de esta clase completo:
package com.android.utm.todosqlite;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

185

import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.annotation.TargetApi;
android.app.Activity;
android.app.AlertDialog;
android.content.Context;
android.content.DialogInterface;
android.content.Intent;
android.content.res.Configuration;
android.graphics.Point;
android.hardware.Camera;
android.os.Build;
android.os.Bundle;
android.util.Log;
android.view.Display;
android.view.MotionEvent;
android.view.SurfaceHolder;
android.view.SurfaceView;
android.view.View;
android.view.Window;
android.view.WindowManager;

import
import
import
import
import
import

com.android.utm.todosqlite.util.BeepManager;
com.google.zxing.BinaryBitmap;
com.google.zxing.MultiFormatReader;
com.google.zxing.PlanarYUVLuminanceSource;
com.google.zxing.Result;
com.google.zxing.common.HybridBinarizer;

@TargetApi(Build.VERSION_CODES.ECLAIR) public class ZXingActivity


extends Activity
implements SurfaceHolder.Callback, Camera.PreviewCallback,
Camera.AutoFocusCallback {
private static final String TAG = "ZXingTest";
private static final int MIN_PREVIEW_PIXCELS = 640 * 480;
private static final int MAX_PREVIEW_PIXCELS = 800 * 480;
private Camera myCamera;
private SurfaceView surfaceView;
private Boolean hasSurface;
private Boolean initialized;
private Point screenPoint;
private Point previewPoint;
BeepManager beepManager;
private ArrayList<String> codigos;
private boolean continua=true;
/** lifecycle */
@Override

186

public void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
//setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR |
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
beepManager=new BeepManager(this);
// Con estos mtodos nos ayuda a dejar la pantalla en modo
completo
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE );
hasSurface = false;
initialized = false;
setContentView(R.layout.activity_capture);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
protected void onResume() {
super.onResume();
surfaceView = (SurfaceView)findViewById(R.id.preview_view);
SurfaceHolder holder = surfaceView.getHolder();
if (hasSurface) {
initCamera(holder);
} else {
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}

@Override
protected void onPause() {
closeCamera();
if (!hasSurface) {
SurfaceHolder holder = surfaceView.getHolder();
holder.removeCallback(this);
}
super.onPause();
}
/** SurfaceHolder.Callback */
@Override
public void surfaceCreated(SurfaceHolder holder) {

187

if (!hasSurface) {
hasSurface = true;
initCamera(holder);
Camera.Parameters parameters = myCamera.getParameters();
if(parameters.getFocusMode()!=null)
if
(!parameters.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_FIXED)
) {
myCamera.autoFocus(this);
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int
width, int height) {
}
/** Camera.AutoFocusCallback */
@Override
public void onAutoFocus(boolean success, Camera camera) {
//if (success)
try {
camera.setOneShotPreviewCallback(this);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
/** devices */
@Override
public boolean onTouchEvent(MotionEvent event) {
if (myCamera != null) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Camera.Parameters parameters =
myCamera.getParameters();
if(parameters.getFocusMode()!=null)
if
(!parameters.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_FIXED)
) {
myCamera.autoFocus(this);
}
}
}

188

return true;
}
/** Camera.PreviewCallback */
/*
* En este motodo se hace la captura de la imagen
* del cdigo QR y la decodifica, a su vez manda
* llamar a la activity QRDetailActivity para que
* se muestre el detalle de la consulta
* */
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
View centerView = (View)findViewById(R.id.center_view);
int left = centerView.getLeft() * previewPoint.x /
screenPoint.x;
int top = centerView.getTop() * previewPoint.y /
screenPoint.y;
int width = centerView.getWidth() * previewPoint.x /
screenPoint.x;
int height = centerView.getHeight() * previewPoint.y /
screenPoint.y;
PlanarYUVLuminanceSource source
PlanarYUVLuminanceSource(

= new
data,
previewPoint.x,
previewPoint.y,
left,
top,
width,
height,
false);

/*
* Se crea un objeto BinaryBitmap que contiene la imagen del
cdigo QR
* que se acaba de leer
* */
BinaryBitmap bitmap = new BinaryBitmap(new
HybridBinarizer(source));
/*
* Creamos el objeto que se encarga de leer el cdigo QR
* */
MultiFormatReader reader = new MultiFormatReader();
try {
/*
* Se decodifica la imagen que capt el lector
* con la cmara y se guarda en un objeto Result
* */
Result result = reader.decode(bitmap);

189

// Ejecutamos el mtodo que ejecuta el beep y hace vibrar


el telfono
beepManager.playBeepSoundAndVibrate();
/*
* Si el objeto Result no est vaco creamos un
* intent y mandamos ejecutar la activity
QRDetailActivity*/
if(result.getText()!=null){
/*
* Creacin del intent
* */
final Intent i = new Intent(this,
QRDetailActivity.class);
/*
* Declaramos los parametros que van a ser
enviados a
* la otra activity
* */
i.putExtra("_id",
Long.parseLong(result.getText()));
// iniciamos la ejecucin de la acivity
startActivity(i);
continua=false;
//ejecutamos este mtodo para que si damos al botn
back en la siguiente activity ya no podamos entrar a esta
finish();
} else {
continua=false;
}
} catch (Exception e) {

} finally {
if(continua){
Camera.Parameters parameters =
myCamera.getParameters();
if
(!parameters.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_FIXED)
) {
myCamera.autoFocus(this);
}
}
}
}
public boolean checkCode(String str_codigo){

190

return true;
}
public AlertDialog crearDialogo(String mensaje) {
AlertDialog.Builder builder = new AlertDialog.Builder(
ZXingActivity.this);
builder.setMessage(mensaje).setCancelable(false)
.setNeutralButton("OK", new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
continua=true;
Camera.Parameters parameters =
myCamera.getParameters();
if(!parameters.getFocusMode().equals(Camera.Parameters.FOCUS_MODE
_FIXED)) {
myCamera.autoFocus(ZXingActivity.this);
}
dialog.cancel();
}
});
return builder.create();
}
/**
*
* @param holder
*/
private void initCamera(SurfaceHolder holder) {
try {
openCamera(holder);
} catch (Exception e) {
Log.w(TAG, e);
}
}
private void openCamera(SurfaceHolder holder) throws IOException {
if (myCamera == null) {
myCamera = Camera.open();
if (myCamera == null) {
throw new IOException();
}
}
myCamera.setPreviewDisplay(holder);
if (!initialized) {
initialized = true;

191

initFromCameraParameters(myCamera);
}
setCameraParameters(myCamera);
//myCamera.setDisplayOrientation(90);
myCamera.startPreview();
}
/**
* ????????????????????????
*/
private void closeCamera() {
if (myCamera != null) {
myCamera.stopPreview();
myCamera.release();
myCamera = null;
}
}
/**
* ????????????????????????
* @param camera
*/
private void setCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(previewPoint.x, previewPoint.y);
List<String> focusModes = parameters.getSupportedFocusModes();
if(parameters.getFocusMode()!=null)
if
(focusModes.contains(Camera.Parameters.FOCUS_MODE_MACRO)){
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
} else if
(focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
camera.setParameters(parameters);
}
/**
*
* @param camera
*/
private void initFromCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
WindowManager manager =
(WindowManager)getApplication().getSystemService(Context.WINDOW_SERVIC
E);
Display display = manager.getDefaultDisplay();
int width = display.getWidth();

192

int height = display.getHeight();


if (width < height) {
int tmp = width;
width = height;
height = tmp;
}
screenPoint = new Point(width, height);
Log.d(TAG, "screenPoint = " + screenPoint);
previewPoint = findPreviewPoint(parameters, screenPoint,
false);
Log.d(TAG, "previewPoint = " + previewPoint);
}
/**
*
* @param parameters
* @param screenPoint
* @param portrait
* @return
*/
private Point findPreviewPoint(Camera.Parameters parameters, Point
screenPoint, boolean portrait) {
Point previewPoint = null;
int diff = Integer.MAX_VALUE;
for (Camera.Size supportPreviewSize :
parameters.getSupportedPreviewSizes()) {
int pixels = supportPreviewSize.width *
supportPreviewSize.height;
if (pixels < MIN_PREVIEW_PIXCELS || pixels >
MAX_PREVIEW_PIXCELS) {
continue;
}
int supportedWidth = portrait ? supportPreviewSize.height
: supportPreviewSize.width;
int supportedHeight = portrait ? supportPreviewSize.width
: supportPreviewSize.height;
int newDiff = Math.abs(screenPoint.x * supportedHeight supportedWidth * screenPoint.y);
if (newDiff == 0) {
previewPoint = new Point(supportedWidth,
supportedHeight);
break;
}
if (newDiff < diff) {
previewPoint = new Point(supportedWidth,

193

supportedHeight);
diff = newDiff;
}
}
if (previewPoint == null) {
Camera.Size defaultPreviewSize =
parameters.getPreviewSize();
previewPoint = new Point(defaultPreviewSize.width,
defaultPreviewSize.height);
}
return previewPoint;
}
}
Por ltimo es necesario tener una forma de donde mandar ejecutar todo el proceso para abrir el lector
esto lo haremos desde el men del MainActivity.java (NavigationDrawer), para lo cual habr que
agregar unas lneas de cdigo en el switch del mtodo MostrarFragment(), dicho cdigo extra es el
siguiente:
case 4:
startActivity(new Intent(this, ZXingActivity.class));
break;
Con esto damos por terminado el ejemplo de lectura de cdigos QR

Adapters
Los Adapters de Android son un puente entre el Adapter View (por ejemplo ListView) y los datos
subyacentes para esa vista. Imagnese lo que hubiera sido el mundo sin necesidad de adaptadores!
Sin Adapters, para implementar la funcionalidad del ListView, se habra necesitado de:

Crear un TextView dentro de un ScrollView.


Tendriamos que poner en prctica el concepto de paginacin de los contenidos del TextView.
Tendramos que escribir cdigo adicional para identificar el evento del click en una fila en
particular el TextView

A continuacin se muestra un diagrama conceptual de alto nivel que muestra el trabajo del adaptador
de Android:

194

Entender el comportamiento interno de un Android Adapter


Los Adapters llaman al mtodo getView() que devuelve una vista para cada elemento dentro de la
vista del adaptador. El mtodo de formato del layout y los datos correspondientes a un elemento dentro
de la vista del adaptador se encuentra en el getView(). Ahora, esto sera una pesadillacon el
rendimiento si getView() devuelve una nueva vista cada vez que se le llama. Crear una nueva vista
sera muy caro en Android, ya que se necesitara para recorrer la jerarqua de vistas (usando el mtodo
ViewbyID() para encontrar) y luego inflar la vista para finalmente mostrarlo en la pantalla. Esto pone
mucha presin sobre el recolector de basura. As que lo que Android hace es que recicla y reutiliza las
vistas que estn fuera de foco. Abajo se muestra un representacin visual de lo que es el proceso de
reciclado:


En la figura anterior, asumimos que estamos viendo los meses en un ao en un ListView. Para empezar,
los meses de enero a mayo se muestran en la pantalla. Al desplazarse por la vista, el mes de enero se
sale de la zona de visualizacin de la pantalla del mvil. Tan pronto como la vista de enero sale de la
pantalla, el Adapter View (ListView en este caso) enva la vista a algo que se llama un reciclador. As
que cuando se desplaza hacia arriba, el mtodo getView() se llama para obtener el siguiente punto
de vista (que es de junio). Este mtodo getView() tiene un parmetro llamado convertview que
apunta a la vista sin utilizar en el reciclador. A travs del convertview, el adaptador intenta controlar
la vista sin usar y reutilizarla para mostrar la nueva vista (que es de junio, en este caso).

195

Mapas en Android (Google Maps Android


API v2)
Esta versin presenta muchas novedades interesantes, de las que cabe destacar las siguientes:

Integracin con los Servicios de Google Play (Google Play Services) y la Consola de APIs.
Utilizacin a travs de un nuevo tipo especfico de fragment (MapFragment), una mejora muy
esperada por muchos.
Utilizacin de mapas vectoriales, lo que repercute en una mayor velocidad de carga y una mayor
eficiencia en cuanto a uso de ancho de banda.
Mejoras en el sistema de cach, lo que reducir en gran medida las famosas reas en blanco que
tardan en cargar.
Los mapas son ahora 3D, es decir, podremos mover nuestro punto de vista de forma que lo
veamos en perspectiva.

Pasos para instalar y/o configurar la API de Google Maps Android.


1. En primer lugar, dado que la API v2 se proporciona como parte del SDK de Google Play Services,
ser necesario incorporar previamente a nuestro entorno de desarrollo dicho paquete. Haremos
esto accediendo desde Eclipse al Android SDK Manager y descargando del apartado de extras el
paquete llamado Google Play Services.


Imagen 33

196

Tras pulsar el botn de Install y aceptar la licencia correspondiente el paquete quedar instalado en
nuestro
sistema,
concretamente
en
la
ruta:
<carpeta-sdkandroid>/extras/google/google_play_services/. Recordemos esto porque nos har
falta ms adelante.
2. El siguiente paso ser obtener una API Key para poder utilizar el servicio de mapas de Google en
nuestra aplicacin.
3. La nueva API de mapas de Android se ha integrado por fin en la Consola de APIs de Google, por
lo que el primer paso ser acceder a ella.
4. Es probable que si nunca hemos entrado a la consola de APIS de Google nos pida que una
pantalla como la que se muestra a continuacin, por lo que hacemos click en el botn Create
Proyect, en caso de no ser as continuamos con el punto 5 directamente.


Imagen 34

5. Una vez hemos accedido, tendremos que crear un nuevo proyecto desplegando el men
superior izquierdo y seleccionando la opcin Create.


Imagen 35

197

6. Aparecer entonces una ventana que nos solicitar el nombre del proyecto. Introducimos algn
nombre descriptivo y aceptamos sin ms.


Imagen 36

7. Una vez creado el proyecto, accederemos a la opcin Services del men izquierdo. Desde esta
ventana podemos activar o desactivar cada uno de los servicios de Google que queremos
utilizar. En este caso slo activaremos el servicio llamado Google Maps Android API v2
pulsando sobre el botn ON/OFF situado justo a su derecha.


Imagen 37

8. Ahora aceptamos los trminos de uso de Google.


Imagen 38

9. Una vez activado aparecer una nueva opcin en el men izquierdo llamada API Access.
Accediendo a dicha opcin tendremos la posibilidad de obtener nuestra nueva API Key que nos
permita utilizar el servicio de mapas desde nuestra aplicacin particular.

198


Imagen 39


10. Para ello, pulsaremos el botn Create new Android key. Esto nos llevar a un cuadro de
dilogo donde tendremos que introducir algunos datos identificativos de nuestra aplicacin. En
concreto necesitaremos dos: la huella digital (SHA1) del certificado con el que firmamos la
aplicacin, y el paquete java utilizado. El segundo no tiene misterio, pero el primero requiere
alguna explicacin.
Toda aplicacin Android debe ir firmada para poder ejecutarse en un dispositivo, tanto fsico
como emulado. Este proceso de firma es uno de los pasos que tenemos que hacer siempre
antes de distribuir pblicamente una aplicacin.
Adicionalmente, durante el desarrollo de la misma, para realizar pruebas y la depuracin del
cdigo, aunque no seamos conscientes de ello tambin estamos firmado la aplicacin con un
certificado de pruebas. Podemos saber en qu carpeta de nuestro sistema est almacenado
este certificado accediendo desde Eclipse al men Window/Preferences y accediendo
a la seccin Android/Build.

199


Imagen 40

11. Como se puede observar, en mi caso el certificado de pruebas est en la ruta


C:\Users\NELSONCROZBY\.android\debug.keystore. Pues bien, para obtener
nuestra huella digital SHA1 deberemos acceder a dicha ruta desde la consola de comando de
Windows y ejecutar los siguientes comandos:
C:\>cd C:\Users\NELSONCROZBY\.android\
C:\Users\NELSONCROZBY\.android>"C:\Program Files (x86) \Java \jdk1.7.0_07
\bin\keytool.exe" -list -v -keystore debug.keystore -alias androiddebugkey storepass android -keypass android

12. Suponiendo

que

tu

instalacin de Java est en la ruta C:\Program


Files\Java\jdk1.7.0_07. Si no es as slo debes sustituir sta por la correcta. Esto nos
deber devolver varios datos del certificado, entre ellos la huella SHA1.

200


Imagen 41

13. Pues bien, nos copiamos este dato y lo aadimos a la ventana de obtencin de la API Key donde
nos habamos quedado antes, y a continuacin separado por un punto y coma aadimos el
paquete java que vayamos a utilizar en nuestra aplicacin, que en mi caso ser
com.demo.proyectodemo.


Imagen 42

14. Pulsamos el botn Create y ya deberamos tener nuestra API Key generada, podremos verla
en la pantalla siguiente dentro del apartado Key for Android Apps (with certificates).
Apuntaremos tambin este dato para utilizarlo ms tarde.

201


Imagen 43

15. Con esto ya habramos concluido los preparativos iniciales necesarios para utilizar el servicio de
mapas de Android en nuestras propias aplicaciones, por lo que modificaremos nuestro proyecto
de ejemplo en Eclipse.
16. lo primero que haremos ser aadir al fichero AndroidManifest.xml la API Key que acabamos de
generar. Para ello aadiremos al fichero, dentro de la etiqueta <application>, un nuevo
elemento <meta-data> con los siguientes datos:


Imagen 44

17. Como valor del parmetro android:value tendremos que poner nuestra API Key recin
generada.
En
mi
caso
mi
API
Key
generada
es:
AIzaSyDmw0rDncgMS1TbUkaXavswHdZRdMbyw6w (recuerda este valor es para el caso
mo, aqu debe de ir valor que a ustedes les genera).
18. Siguiendo con el AndroidManifest, tambin tendremos que incluir una serie de permisos que
nos permitan hacer uso de los mapas. En primer lugar tendremos que definir y utilizar un
permiso llamado tu.paquete.java.permission.MAPS_RECEIVE, estas etiquetas
deben de ser colocadas antes de la etiqueta <application, en mi caso quedara de la
siguiente forma (recordemos y tengamos mucho cuidado de usar el nombre del paquete
principal de su proyect:
<permission
android:name="com.android.utm.todosqlite.java.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-permission
android:name="com.android.utm.todosqlite.java.permission.MAPS_RECEIVE"
/>

202


Imagen 45

19. Adems, tendremos que aadir permisos adicionales que nos permitan acceder a los servicios
web de Google, a Internet, y al almacenamiento externo del dispositivo (utilizado para la cach
de los mapas), estos permisos son colocados inmediatamente despus de los anteriores:
<uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GSERVIC
ES" />
<!-- permitimos abrir conexiones de red. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Imagen 46

20. Por ltimo, dado que la API v2 de Google Maps Android utiliza OpenGL ES versin 2, deberemos
especificar tambin dicho requisito en nuestro AndroidManifest aadiendo un nuevo elemento
<uses-feature> inmediatamente despus de los permisos anteriores:


Imagen 47

21. Una vez hemos configurado todo lo necesario en el AndroidManifest, y antes de escribir nuestro
cdigo, tenemos que seguir aadiendo elementos externos a nuestro proyecto. El primero de
ellos ser referenciar desde nuestro proyecto la librera con el SDK de Google Play Services que
nos descargamos al principio de este tutorial. Para ello, desde Eclipse podemos importar la
librera a nuestro conjunto de proyectos mediante la opcin de men File / Import /
Existing Android Code Into Workspace. Como ya dijimos este paquete se localiza
en
la
ruta
<carpeta-sdkandroid>/extras/google/google_play_services/libproject/googleplay-services_lib.

203


Imagen 48

22. Tras seleccionar la ruta correcta dejaremos el resto de opciones con sus valores por defecto y
pulsaremos Finish para que Eclipse importe esta librera a nuestro conjunto de proyectos.
23. El siguiente paso ser referenciar esta librera desde nuestro proyecto de ejemplo. Para ello
iremos a sus propiedades pulsando botn derecho / Properties sobre nuestro proyecto y
accediendo a la seccin Android de las preferencias. En dicha ventana podemos aadir una
nueva librera en la seccin inferior llamada Library. Cuando pulsamos el botn Add nos
aparecer la librera recin importada y podremos seleccionarla directamente, aadindose a
nuestra lista de libreras referenciadas por nuestro proyecto.

204


Imagen 49

24. Como ltimo paso de configuracin de nuestro proyecto, si queremos que nuestra aplicacin se
pueda ejecutar desde versiones antiguas de Android (concretamente desde la versin de
Android 2.2) deberemos asegurarnos de que nuestro proyecto incluye la librera android-
support-v4.jar, que debera aparecer si desplegamos las seccin Android Dependencies o la
carpeta lib de nuestro proyecto.


Imagen 50

25. Las versiones ms recientes de ADT incluyen por defecto esta librera en nuestros proyectos,
pero si no est incluida podramos hacerlo mediante la opcin del men contextual Android
Tools / Add Support Library sobre el proyecto, o bien de forma manual.

205

Pasos para construir una aplicacin bsica usando la API de Google Maps
Y con esto hemos terminado de configurar todo lo necesario. Ya podemos escribir nuestro cdigo. Y
para este primer ejemplo sobre el tema nos vamos a limitar a mostrar un mapa en la pantalla principal
de la aplicacin. Posteriormente veremos cmo aadir otras opciones o elementos al mapa.
1. Para esto tendremos simplemente que aadir el control correspondiente al layout de nuestra
actividad en este caso es activity_mapa.xml. En el caso de la nueva API v2 este control se
aadir en forma de fragment (de ah que hayamos tenido que incluir la librera android-
support para poder utilizarlos en versiones de Android anteriores a la 3.0) de un determinado
tipo
(concretamente
de
la
nueva
clase
com.google.android.gms.maps.SupportMapFragment), quedando por ejemplo de
la siguiente forma (ver Imagen 132):


Imagen 51


Grficamente el diseo de la interfaz se vera como se muestra en la Imagen 53.


Imagen 52

206

2. Por supuesto, dado que estamos utilizando fragments, la actividad MapasActivity.java tambin
tendr que extender a FragmentActivity (en vez de simplemente Activity como es lo normal).
Usaremos tambin la versin de FragmentActivity incluida en la librera android-support para
ser compatibles con la mayora de las versiones Android actuales. Veamos la Imagen 54 para ver
cmo queda el cdigo de nuestra activity.


Imagen 53

Con esto, ya podramos ejecutar y probar nuestra aplicacin. En mi caso las pruebas las he realizado
sobre un dispositivo fsico con Android 2.3.5 ya que por el momento parece haber algunos problemas
para hacerlo sobre el emulador. Por tanto tendremos que conectar nuestro dispositivo a la PC mediante
el cable de datos e indicar a Eclipse que lo utilice para la ejecucin de la aplicacin.
En la Imagen 55 podemos ver una captura en pantalla de la ejecucin del cdigo que previamente
hemos creado.

207


Imagen 54

Interactuando con el Mapa (pasar coordenadas)

En el ejemplo anterior todo lo que hicimos fue lo necesario para configurar la API de Google y poder
cargar un mapa en nuestra pantalla, pero ahora lo que se pretende hacer es ya interactuar con el mapa,
en qu consistir esta interaccin, pues lo primero ser lograr que el mapa se posicione sobre un punto
en especfico y a este punto le colocaremos unos markers personalizado junto a algn tipo de
mensaje.
1. Bueno lo primero que haremos ser abrir el archivo MapasActivity.java para modificarlo, de
ahora en adelante en este ejemplo todo lo que hagamos ser en esta clase.
2. Como en este ejemplo ser algo demostrativa y simple pondremos las coordenadas de dos
puntos de forma manual en unas variables globales del tipo LatLng, en posteriores ejemplos
veremos cmo recuperar la posicin actual a travs del GPS del celular por lo pronto veremos la
Imagen 56 y observamos la forma de declarar las coordenadas.


Imagen 55

3. Ahora pasaremos a inicializar la variable del tipo GoogleMap declarada y el elemento respectivo
del layout. En la siguiente Imagen podemos ver cmo se hace (recuerda que esto se hace en el
mtodo onCreate):

208


Imagen 56

4. Posteriormente agregaremos los markers para cada uno de los puntos que crearemos en el
mapa y tambin pondremos el zoom de inicio sobre el mapa y declararemos un efecto al
momento de hacer zoom sobre el mapa, ver Imagen 58 para el cdigo.


Imagen 57

Localizacin geogrfica en Android


La localizacin geogrfica en Android es uno de esos servicios que, a pesar de requerir poco cdigo para
ponerlos en marcha, no son para nada intuitivos ni fciles de llegar a comprender por completo. Y esto
no es debido al diseo de la plataforma Android en s, sino a la propia naturaleza de este tipo de
servicios. Por un lado, existen multitud de formas de obtener la localizacin de un dispositivo mvil,
aunque la ms conocida y popular es la localizacin por GPS, tambin es posible obtener la posicin de
un dispositivo por ejemplo a travs de las antenas de telefona mvil o mediante puntos de acceso Wi-Fi
cercanos, y cada uno de estos mecanismos tiene una precisin, velocidad y consumo de recursos
distinto. Por otro lado, el modo de funcionamiento de cada uno de estos mecanismos hace que su
utilizacin desde nuestro cdigo no sea todo lo directa e intuitiva que se deseara. Iremos comentando
todo esto a lo largo del documento, pero vayamos paso a paso.

Qu mecanismos de localizacin tenemos disponibles?


Lo primero que debe conocer una aplicacin que necesite obtener la localizacin geogrfica es qu
mecanismos de localizacin (proveedores de localizacin, o location providers) tiene disponibles en el
dispositivo. Como ya hemos comentado, los ms comunes sern el GPS y la localizacin mediante la red
de telefona, pero podran existir otros segn el tipo de dispositivo.
La forma ms sencilla de saber los proveedores disponibles en el dispositivo es mediante una llamada al
mtodo getAllProviders() de la clase LocationManager, clase principal en la que nos
basaremos siempre a la hora de utilizar la API de localizacin de Android. Para ello, obtendremos una
referencia al location manager llamando a getSystemService(LOCATION_SERVICE), y

209

posteriormente obtendremos la lista de proveedores mediante el mtodo citado para obtener la lista de
nombres de los proveedores:


Imagen 58

Una vez obtenida la lista completa de proveedores disponibles podramos acceder a las propiedades de
cualquiera de ellos (precisin, coste, consumo de recursos, o si es capaz de obtener la altitud, la
velocidad, etc). As, podemos obtener una referencia al provider mediante su nombre llamando al
mtodo getProvider(nombre) y posteriormente utilizar los mtodos disponibles para conocer sus
propiedades, por ejemplo getAccuracy() para saber su precisin (tenemos disponibles las
constantes Criteria.ACCURACY_FINE para precisin alta, y Criteria.ACCURACY_COARSE
para precisin media), supportsAltitude() para saber si obtiene la altitud, o
getPowerRequirement() para obtener el nivel de consumo de recursos del proveedor. La lista
completa de mtodos para obtener las caractersticas de un proveedor se puede consultar en la
documentacin oficial de la clase LocationProvider.


Imagen 59

Al margen de esto, hay que tener en cuenta que la lista de proveedores devuelta por el mtodo
getAllProviders() contendr todos los proveedores de localizacin conocidos por el dispositivo,
incluso si stos no estn permitidos (segn los permisos de la aplicacin) o no estn activados, por lo
que esta informacin puede que no nos sea de mucha ayuda.

Qu proveedor de localizacin es mejor para mi aplicacin?


Android proporciona un mecanismo alternativo para obtener los proveedores que cumplen unos
determinados requisitos entre todos los disponibles. Para ello nos permite definir un criterio de
bsqueda, mediante un objeto de tipo Criteria, en el que podremos indicar las caractersticas
mnimas del proveedor que necesitamos utilizar (podis consultar la documentacin oficial de la clase
Criteria para saber todas las caractersticas que podemos definir). As, por ejemplo, para buscar uno con
precisin alta y que nos proporcione la altitud definiramos el siguiente criterio de bsqueda:


Imagen 60

210

Tras esto, podremos utilizar los mtodos getProviders() o getBestProvider() para obtener
la lista de proveedores que se ajustan mejor al criterio definido o el proveedor que mejor se ajusta a
dicho criterio, respectivamente. Adems, ambos mtodos reciben un segundo parmetro que indica si
queremos que slo nos devuelvan proveedores que estn activados actualmente. Veamos cmo se
utilizaran estos mtodos:


Imagen 61

Con esto, ya tenemos una forma de seleccionar en cada dispositivo aquel proveedor que mejor se ajusta
a nuestras necesidades.

Est disponible y activado un proveedor determinado?


Aunque, como ya hemos visto, tenemos la posibilidad de buscar dinmicamente proveedores de
localizacin segn un determinado criterio de bsqueda, es bastante comn que nuestra aplicacin est
diseada para utilizar uno en concreto, por ejemplo el GPS, y por tanto necesitaremos algn mecanismo
para saber si ste est activado o no en el dispositivo. Para esta tarea, la clase LocationManager nos
proporciona otro mtodo llamado isProviderEnabled() que nos permite hacer exactamente lo
que necesitamos. Para ello, debemos pasarle el nombre del provider que queremos consultar. Para los
ms comunes tenemos varias constantes ya definidas:

LocationManager.NETWORK_PROVIDER. Localizacin por la red de telefona.

LocationManager.GPS_PROVIDER. Localizacin por GPS.

De esta forma, si quisiramos saber si el GPS est habilitado o no en el dispositivo (y actuar en


consecuencia), haramos algo parecido a lo siguiente:


Imagen 62

En el cdigo anterior, verificamos si el GPS est activado y en caso negativo mostramos al usuario un
mensaje de advertencia. Este mensaje podramos mostrarlo sencillamente en forma de notificacin de
tipo toast,

El GPS ya est activado, y ahora qu?


Una vez que sabemos que nuestro proveedor de localizacin favorito est activado, ya estamos en
disposicin de intentar obtener nuestra localizacin actual. Y aqu es donde las cosas empiezan a ser

211

menos intuitivas. Para empezar, en Android no existe ningn mtodo del tipo obtenerPosicinActual().
Obtener la posicin a travs de un dispositivo de localizacin como por ejemplo el GPS no es una tarea
inmediata, sino que puede requerir de un cierto tiempo de procesamiento y de espera, por lo que no
tendra sentido proporcionar un mtodo de ese tipo.
Si buscamos entre los mtodos disponibles en la clase LocationManager, lo ms parecido que
encontramos es un mtodo llamado getLastKnownLocation(String provider), que como
se puede suponer por su nombre, nos devuelve la ltima posicin conocida del dispositivo devuelta por
un provider determinado. Es importante entender esto: este mtodo NO devuelve la posicin actual,
este mtodo NO solicita una nueva posicin al proveedor de localizacin, este mtodo se limita a
devolver la ltima posicin que se obtuvo a travs del proveedor que se le indique como parmetro. Y
esta posicin se pudo obtener hace pocos segundos, hace das, hace meses, o incluso nunca (si el
dispositivo ha estado apagado, si nunca se ha activado el GPS, etc.). Por tanto, cuidado cuando se haga
uso de la posicin devuelta por el mtodo getLastKnownLocation().
Entonces, de qu forma podemos obtener la posicin real actualizada? Pues la forma correcta de
proceder va a consistir en algo as como activar el proveedor de localizacin y suscribirnos a sus
notificaciones de cambio de posicin. O dicho de otra forma, vamos a suscribirnos al evento que se
lanza cada vez que un proveedor recibe nuevos datos sobre la localizacin actual. Y para ello, vamos a
darle previamente unas indicaciones (que no son ordenes) sobre cada cuanto tiempo o cada cuanta
distancia recorrida necesitaramos tener una actualizacin de la posicin.
Todo esto lo vamos a realizar mediante una llamada al mtodo requestLocationUpdates(), al
que deberemos pasar 4 parmetros distintos:

Nombre del proveedor de localizacin al que nos queremos suscribir.


Tiempo mnimo entre actualizaciones, en milisegundos.
Distancia mnima entre actualizaciones, en metros.
Instancia de un objeto LocationListener, que tendremos que implementar previamente
para definir las acciones a realizar al recibir cada nueva actualizacin de la posicin.

Tanto el tiempo como la distancia entre actualizaciones pueden pasarse con valor 0, lo que indicara que
ese criterio no se tendr en cuenta a la hora de decidir la frecuencia de actualizaciones. Si ambos valores
van a cero, las actualizaciones de posicin se recibirn tan pronto y tan frecuentemente como estn
disponibles. Adems, como ya hemos indicado, es importante comprender que tanto el tiempo como la
distancia especificadas se entendern como simples indicaciones o pistas para el proveedor, por lo
que puede que no se cumplan de forma estricta.
En cuanto al listener, ste ser del tipo LocationListener y contendr una serie de mtodos
asociados a los distintos eventos que podemos recibir del proveedor:

onLocationChanged(location). Lanzado cada vez que se recibe una actualizacin de la


posicin.
onProviderDisabled(provider). Lanzado cuando el proveedor se deshabilita.

212

onProviderEnabled(provider). Lanzado cuando el proveedor se habilita.

onStatusChanged(provider, status, extras). Lanzado cada vez que el


proveedor cambia su estado, que puede variar entre OUT_OF_SERVICE,
TEMPORARILY_UNAVAILABLE, AVAILABLE.

Por nuestra parte, tendremos que implementar cada uno de estos mtodos para responder a los
eventos del proveedor, sobre todo al ms interesante, onLocationChanged(), que se ejecutar
cada vez que se recibe una nueva localizacin desde el proveedor. Veamos un ejemplo de cmo
implementar un listener de este tipo:


Imagen 63

Como podemos ver, en nuestro caso de ejemplo nos limitamos a mostrar al usuario la informacin
recibida en el evento, bien sea un simple cambio de estado, o una nueva posicin, en cuyo caso
llamamos al mtodo auxiliar mostrarPosicion().
En el mtodo mostrarPosicion() nos vamos a limitar a mostrar los distintos datos de la posicin pasada
como parmetro en los controles correspondientes de la interfaz, utilizando para ello los mtodos
proporcionados por la clase Location. En nuestro caso utilizaremos getLatitude(),
getAltitude() y getAccuracy() para obtener la latitud, longitud y precisin respectivamente.
Por supuesto, hay otros mtodos disponibles en esta clase para obtener la altura, orientacin,
velocidad, etc que se pueden consultar en la documentacin oficial de la clase Location. Veamos el
cdigo:

213


Imagen 64

Por qu comprobamos si la localizacin recibida es null? Como ya hemos dicho anteriormente, no


tenemos mucho control sobre el momento ni la frecuencia con la que vamos a recibir las actualizaciones
de posicin desde un proveedor, por lo que tampoco estamos seguros de tenerlas disponibles desde un
primer momento. Por este motivo, una tcnica bastante comn es utilizar la posicin que devuelve el
mtodo getLastKnownLocation() como posicin provisional de partida y a partir de ah
esperar a recibir la primera actualizacin a travs del LocationListener. Y como tambin dijimos,
la ltima posicin conocida podra no existir en el dispositivo, de ah que comprobemos si el valor
recibido es null. Para entender mejor esto, a continuacin tenis la estructura completa del mtodo
que lanzamos al comenzar la recepcin de actualizaciones de posicin:

214


Imagen 65

Como se puede observar, al comenzar la recepcin de posiciones, mostramos en primer lugar la ltima
posicin conocida, y posteriormente solicitamos al GPS actualizaciones de posicin cada 30 segundos.
En las Imgenes 67 - 69 podemos ver la el diseo grfico y el archivo xml que utilizaremos para la
pantalla de la interfaz grfica.

215


Imagen 66


Imagen 67

216


Imagen 68

En las siguientes Imgenes 70 - 74 podemos ver el cdigo de los diferentes mtodos que conforman
nuestra activity TrazarActivity.java.


Imagen 69. Declaracin de variables globales.

217


Imagen 70. Mtodo onCreate()


Imagen 71. Mtodos trazarRuta() y mostrarDestino()

218


Imagen 72. Mtodo comenzarLocalizacion()


Imagen 73. Mtodos mostrarAvisoGpsDeshabilitado() y mostrarPosicion()

219

AsyncTask
La clase AsyncTask nos ayuda a los desarrolladores a darle un uso adecuado y ms fcil al UI thread de
nuestras aplicaciones. Permite ejecutar operaciones en segundo plano y definir los resultados en el UI
thread sin tener que quebrarnos la cabeza manipulando threads y handlers.
Para utilizar AsyncTask debemos:

Crear una subclase de AsyncTask, comnmente como una clase interna privada dentro de la
actividad en la que estemos trabajando.
Sobreescribir uno o ms mtodos de AsyncTask para poder realizar el trabajo en segundo plano,
adems de cualquier otra tarea asociada para poder mostrar alguna actualizacin en el UI
thread.
Cuando sea necesario, crear una instancia de AsyncTask y llamar al mtodo execute() para que
empiece a realizar su trabajo.

Tipos genricos
AsyncTask utiliza tipos genricos, por lo que resulta necesario definir tres tipos de datos cada vez que
necesitemos crear una instancia de esta clase:

Parmetros (Params). El tipo de informacin que se necesita para procesar la tarea.


Progreso (Progress). El tipo de informacin que se pasa dentro de la tarea para indicar su
progreso.
Resultado (Result). El tipo de informacin que se pasa cuando la tarea ha sido completada.

Hay que tener en cuenta que existen casos en los que algn tipo genrico no es utilizado por la
AsyncTask, para ello utilizamos el tipo Void como se muestra a continuacin:

Etapas del ASyncTask


Cada vez que una tarea asncrona se ejecuta, se pasa a travs de 4 etapas:
1. onPreExceute(). Se invoca en el UI thread inmediatamente despus de que la tarea es
ejecutada. Este paso se utiliza normalmente para configurar la tarea. El ejemplo bsico es
cuando se muestra una ProgressBar en la interfaz de usuario.
2. doInBackground(Params). Se invoca en el subproceso en segundo plano inmediatamente
despus de que onPreExecute() termina de ejecutarse. En esta etapa se calcula el tiempo
estimado que tomar la realizacin de la tarea, que deber pasarse a la ltima etapa de todo el
proceso. Los parmetros de la tarea asncrona tambin se pasan en esta etapa. Dentro de esta
etapa podemos utilizar el mtodo publishProgress(Progress) para publicar una o ms unidades

220

de progreso en el UI thread por la ayuda de la siguiente etapa que es


onProgressUpdate(Progress).
3. onProgressUpdate(Progress). Se invoca en el UI thread despus de una llamada a
publishProgress(Progress). El momento de la ejecucin es indefinido. Este mtodo es utilizado
para mostrar cualquier tipo de progreso en la interfaz de usuario mientras la tarea en segundo
plano sigue ejecutndose.
4. onPostExecute(Result). Se invoca en el UI thread despus de que el proceso en segundo plano
ha sido terminado. El resultado devuelto por todo el proceso se pasa a este mtodo como
parmetro.

Las reglas del juego


Para poder trabajar sin problemas con la clase AsyncTask, existen algunas reglas acerca de los threads
que debes tomar en cuenta:

La instancia de la tarea debe crearse en el UI thread.


El mtodo execute(Params) debe invocarse en el UI thread.
Los mtodos onPreExecute(), onPostExecute(Result), doInBackground(Params), on
ProgressUpdate(Progress) no deben llamarse de forma manual.
La tarea debe ser ejecutada slo una vez (con excepcin de que la ejecucin corresponda a un
segundo intento).

Consumir informacin con la creacin de


un Rest API con Google AppScript y uso
de Volley Framework en Android
Nuestra aplicacin ser una especie de hub de recibos de Nomina, sern creados y llenados por medio
de Google AppScript y nuestra App Android consumir dichos datos con la ayuda de Volley Framework.

221

Google AppScript es la propuesta de la empresa por hacer que las apps sean mas que una suite de
oficina, es un conjunto de cdigo que va por detrs de dichas apps escrito en Javascript (aunque la
interpretacin del mismo corre en los servidores de Google) que permite extender la funcionalidad de
aplicaciones como Google Docs o Google Spreadsheets a la vez que permite comunicarse con servicios
como Gmail o Google Calendar.
En este ejemplo vamos a realizar un rest API con Google Spreadsheets, si suena raro, pero nuestra Base
de datos por as decirlo, no sra mas que una hoja de SpreadSheet, vanlo como una posibilidad para
aplicaciones ligeras donde cualquier persona puede modificar La base de datos como una hoja de
Calculo normal y ver los cambios sin problemas en la aplicacin Android.
La siguiente liga contiene la hoja con la que estaremos trabajando, debemos crear una copia a nuestra
cuenta de Drive (es necesario tener cuenta de Google, y acceder a ella primeramente), eso se realiza de
la siguiente manera:


Concentremonos en la hoja, podemos observar que se conforma de 3 partes: Header, Data y Footer. El
motivo es resaltar los datos vamos a utilizar, como el app solo mostrara a cada persona en la nomina, el
header y el footer no nos sirven, as mismo nuestro script estar preparado para solo obtener los datos
importantes sin importar el tamao de cualquiera de las secciones.

222

El siguiente paso es trabajar con el script, cuando ustedes crearon una copia de la liga anterior, no solo
copiaron los datos de la hoja, si no que por detrs, copiamos el script que fue escrito previamente en
ella, para crear o modificar un script ingresamos al menu Herramientas y debemos acceder a la opcin
Editor de secuencias de comando.


Al hacer lo anterior lo que veremos ser algo muy similar a lo siguiente

223


Es importante que verifiquemos en dnde se declara la variable SPREADSHEET_ID cuyo valor no debe de
conterner la siguiente cadena &usp en caso de contenerla se deber de quitar
Podemos observar que el Script contiene 3 funciones:

myFunction
toObject
doGet

Al inicio tenemos 2 variables con el tamao del header y del footer, no olviden actualizar esos valores si
es que modificaron el numero de rows. myFunction es el encargado de obtener todos los datos del
SpreadSheet, toObject es una funcion que creamos para convertir los datos obtenidos como arreglo a
objeto, esto sera de gran utilidad ya que la respuesta JSON sera mas agradable de manejar y por ultimo
doGet es requerido para cuando publiquemos el script como WebApp, las partes mas importantes estan
comentadas. Para ver funcionar nuestro Script, debemos publicarlo como WebApp, esto es muy facil,
tan solo con acceder al menu Publicar -> Implementar como aplicacin web

224


En este caso es necesario establecer una versin del proyecto, ponemos 1 como la versin del proyecto
y hacemos click en Guardar nueva versin

225

Por ltimo hacemos click en el botn Implementar.


Cuando publiquemos como web app, se nos otorgara una URL y eso es todo, ya tenemos un REST API
hecho solamente con Google AppScript y los datos obtenidos desde una simple Hoja de Calculo.


Para comprobar que todo funciona correctametne haremos click en el enlace que dice ltimo cdigo
que aparece en la imagen anterior, con esto abrimos la URL generada y deber crear una respuesta
como la de la siguiente imagen:


Ahora toca el turno de manejar dicha informacin en nuestra app, para ello no utilizaremos la manera
tradicional (Usando Threads con AsyncTask), en su remplazo usaremos un Framework HTTP client
support llamado Volley, el uso de uno o de otro ya depende de gustos.
Nota
Es importante hacer notar que es necesario declarar el proyecto completamente pblico y abierto, pues
es necesario que desde la aplicacin Android pueda acceder a este.

Volley: un cliente HTTP para Android.


Como se menciono en el Google I/O de 2013: Volley is a library that makes networking for Android
apps easier and most importantly, faster. Por lo que ya no es tan doloroso el consumir web services.
Anteriormente este tipo de aplicaciones se solucionaban a la manera HTTP client Java tradicional (con
flujo de entrada, buffer, etc) pero con Volley, solo necesitamos saber que tipo de respuesta esperamos
(JSONObject, JSONArray, String etc) y eso es todo. La siguiente imagen representa el diagrama de
nuestra App:

226

Agregando la Librera
El primer paso necesario es conseguir la librera, esto lo lograremos clonando el proyecto Volley desde
un repositorio para lo cual seleccionamos File Import Git Projects from Git, como se muestra en
la siguiente imagen y pulsamos Next


Posteriormente seleccionamos la opcin URI y Next

227

En la siguiente ventana en la seccin URI debemos de escribir la siguiente direccin


https://android.googlesource.com/platform/frameworks/volley y dejar los
dems datos que aparecen tal cual como se muestran en la siguiente imagen


En la siguiente pantalla se deber de seleccionar el branche que se se desea, por default estn
seleccionados todos pero debemos de slo seleccionar la que se llama master y click en Next.

228

El repositorio comenzar a descargarse automticamente. Ya por ltimo tenemos que elegir la forma en
que queremos crear el proyecto, en la siguiente imagen se muestra la pantalla que aparece para este fin
la vamos a dejar como est o en caso de que no aparezca como se ve en la imagen se deber de
seleccionar las mismas opciones.


Y hacemos click en Next en todas las pantallas que aparezcan. Es as como se ha creado un proyecto
pero que en realidad ser una librera y nos auxiliar en el desarrollo y correcto funcionamiento de
nuestro proyecto, dicha librera contiene todas las clases que pertenecen al proyecto Volley. Ya
descargado el siguiente paso ser el de asignar como librera a nuestro proyecto: click derecho en
nuestro proyecto -> Android -> Library add -> volley, y ya con esto debe de quedar listo el entorno
para comenzar a desarrollar nuestro proyecto de android.

Preparando Volley
Para empezar a trabajar con Volley creamos una instancia del mismo (RequestQueue), solo
necesitamos crearla a partir del mtodo newRequestQueue de Volley que recibe nuestro contexto:
RequestQueue queue = Volley.newRequestQueue(this);
Como se menciona anteriormente, debemos saber que tipo de respuesta esperamos recibir, en nuestro
caso es un JSONArray. Construiremos una instancia de ese tipo la cual podremos usarla en cualquier
momento que lo necesitamos (es como un singleton, aqu preparamos el request, aun no es ejecutado).
Para construir el JsonArrayRequest su constructor recibe la URL a la que queremos acceder, la
clase anonima Response.Listener que sobrecarga el metodo: onResponse(), ademas de la
clase anonima Response.ErrorListener() que sobrecarga el metodo onErrorResponse().
Esto quiere decir que intuitivamente, dependiendo de si la respuesta fue exitosa o no, se mandan a
llamar uno u el otro:

229

String
URL="https://script.googleusercontent.com/macros/echo?user_content_key
=lFICbdS8JH7Qu5P8Zc-O8Obivcf58FTKcnLZcMCSlI2Nj6WhAZKVgz9Du2S6C5xmVaOSNBOdG5o85LRco60xiKXdElX244Rm5_BxDlH2jW0nuo2oDemN9CC
S2h10ox_1xSncGQajx_ryfhECjZEnEDsaoV-dQuTXwGeEegV2_Od5afzYas7yyPsvS7GrZOuKlOh3tRsmWDRy7wERKzg&lib=M5aD4PDtvLBAgJtbZlnaQMLGP5fZpIYsy";
JsonArrayRequest req = new JsonArrayRequest(URL, new
Response.Listener<JSONArray> () {
@Override
public void onResponse(JSONArray response) {
"Entraremos en este mtodo si el llamado fue exitoso"
"recibimos JSONArray response como respuesta"
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
"Entraremos en este mtodo si existi un error"
}
});
Ahora solo queda ejecutar nuestro request, recordamos que antes hemos creado una instancia
RequestQueue llamada queue, queue tiene un metodo llamado add que recibe como
parametro un request preparado de cualquier tipo (recordar el de nosotros es JsonArrayRequest
llamado req), entonces lo pasamos como parametro para que se pueda ejecutar:
queue.add(req);
En nuestro caso solo es uno, pero RequestQueue puede ejecutar n llamados como instancias de
respuesta hemos creado, cool no es cierto?.

Continuamos con el diseo


Como un ListView no es suficiente para mostrar los datos de manera atractiva, hemos creado uno a
la medida,con todas las buenas practicas que lo amerita, hemos creamos un modelo llamado Persona
que es construido con los datos que obtenemos del API (Nombre, Sueldo, SalarioDiario, DiasLaborados).
Modelo Persona
package com.android.nomina.models;
public class Persona {
private

String nombre;

230

private
private
private

String salarioDiario;
String diasLaborados;
String sueldo;

public String getNombre() {


return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getSalarioDiario() {
return salarioDiario;
}
public void setSalarioDiario(String salarioDiario) {
this.salarioDiario = "$"+salarioDiario+" por da";
}
public String getDiasLaborados() {
return diasLaborados;
}
public void setDiasLaborados(String diasLaborados) {
this.diasLaborados = diasLaborados+" das trabajados";
}
public String getSueldo() {
return sueldo;
}
public void setSueldo(String sueldo) {
this.sueldo = "Sueldo Total $"+sueldo;
}
}
CustomAdapter
public class CustomAdapter extends ArrayAdapter<Persona>{
ArrayList<Persona> data;
LayoutInflater inflater;
public CustomAdapter(Context context, ArrayList<Persona>
objects){
super(context, -1, objects);
this.data = objects;
this.inflater = LayoutInflater.from(context);
}
@Override

231

public View getView(int position, View convertView, ViewGroup


parent) {
ViewHolder holder;
Persona persona = data.get(position);
int layout = R.layout.list_row;
if (convertView == null) {
convertView = inflater.inflate(layout, null);
holder = new ViewHolder();
holder.nombre = (TextView)
convertView.findViewById(R.id.nombre);
holder.salarioDiario = (TextView)
convertView.findViewById(R.id.salario_diario);
holder.diasLaborados = (TextView)
convertView.findViewById(R.id.dias_laborados);
holder.sueldo = (TextView)
convertView.findViewById(R.id.sueldo);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
holder.nombre.setText(persona.getNombre());
holder.sueldo.setText(persona.getSueldo());
holder.salarioDiario.setText(persona.getSalarioDiario());
holder.diasLaborados.setText(persona.getDiasLaborados());
return convertView;
}
public static class
public TextView
public TextView
public TextView
public TextView
}

ViewHolder{
nombre;
salarioDiario;
diasLaborados;
sueldo;

Diseo de cada Row de la lista


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#90000000"
>

232

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Nombre"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:gravity="center_horizontal"
android:paddingTop="15dp"
android:paddingBottom="15dp"
android:id="@+id/nombre" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sueldo"
android:textColor="#89d8fa"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:id="@+id/sueldo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Salario diario"
android:textStyle="italic"
android:textColor="#ffb900"
android:layout_marginLeft="10dp"
android:id="@+id/salario_diario" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dias"
android:textStyle="italic"
android:layout_marginRight="10dp"
android:layout_marginBottom="15dp"
android:layout_gravity="right"
android:textColor="#00de72"
android:id="@+id/dias_laborados" />
</LinearLayout>
Finalmente
Nuestro MainActivity contiene el llamado a nuestro API (hecho con Volley), el cual si es un xito,
construira nuestro adapter para el ListView con todos los objetos recibidos, no es tan directo ya que
se necesita parsear la informacin, y de la cual creamos un metodo para dicho proposito, a
continuacion el codigo completo de nuestro MainActivity:
public class MainActivity extends ActionBarActivity {

233

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//ActionBar de Color Negro, solo por esttica
ColorDrawable colorDrawable = new
ColorDrawable(Color.parseColor("#000000"));
ActionBar actionbar = getSupportActionBar();
actionbar.setBackgroundDrawable(colorDrawable);
//Creamos una instancia de RequestQueue que slo recibe el
contexto
RequestQueue queue = Volley.newRequestQueue(this);
//URL del SpreadSheet
String URL =
"https://script.googleusercontent.com/macros/echo?user_content_key=lFI
CbdS8JH7Qu5P8Zc-O8Obivcf58FTKcnLZcMCSlI2Nj6WhAZKVgz9Du2S6C5xmVaOSNBOdG5o85LRco60xiKXdElX244Rm5_BxDlH2jW0nuo2oDemN9CC
S2h10ox_1xSncGQajx_ryfhECjZEnEDsaoV-dQuTXwGeEegV2_Od5afzYas7yyPsvS7GrZOuKlOh3tRsmWDRy7wERKzg&lib=M5aD4PDtvLBAgJtbZlnaQMLGP5fZpIYsy";
//Creamos una instancia de un ProgressDialog para que el
usuario observe que los datos se estan obteniendo
final ProgressDialog progressDialog =
ProgressDialog.show(this, "Por favor espere ...", "Descargando Datos
...", true);
//Configuramos nuestro request, al intanciar JsonArrayRequest
recibe la URL y un Listener de JSON Array, el cual
//contiene una serie de mtodos a implelentar, prcticamente
si resulto bien o existio un error, ademas
// sirve como un singleton para mandarlo a llamar cuando sea
necesario hacer de nuevo el request.
// Recordar que este solo construye el llamado HTTP, se ejecuta
mas adelante cuando lo agregamos como parametro del metodo add
//de RequestQueue
JsonArrayRequest req = new JsonArrayRequest(URL, new
Response.Listener<JSONArray> () {
@Override
public void onResponse(JSONArray response) {
//Un textview antes de la vista nos permite ver los
datos crudos dentro de la misma app
TextView textView = (TextView)
findViewById(R.id.datos_crudos);

234

textView.setText(response.toString());
//dejamos en el Log un pequeo mensaje con el response
como string para ver un preview de lo que recibimos
Log.e("respeusta", response.toString());
//buscamos el listview de main_activity
ListView list = (ListView)
findViewById(R.id.list_view);
//Si vemos el CustomAdapter debemos pasar un contexto
y un ArrayList de objetos Personas
//dicho ArrayList es parseao de la respuesta por medio
de la funcion parser
CustomAdapter adapter = new
CustomAdapter(getApplicationContext(), parser(response));
//pasamos el adapter para que la lista se muestre en
el UI
list.setAdapter(adapter);
progressDialog.dismiss();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
progressDialog.dismiss();
}
});
// Ejecutamos Volley, con el request preparado
queue.add(req);
}
// La funcin de abajo se encarga de parsear toda la informacin
public ArrayList<Persona> parser(JSONArray respuesta){
ArrayList<Persona> personasAux = new ArrayList<Persona>();
for(int i = 0; i < respuesta.length(); i++){
JSONObject jsonObject;
Persona persona = new Persona();
try {
jsonObject = (JSONObject) respuesta.get(i);
persona.setNombre(jsonObject.getString("nombre"));
persona.setSalarioDiario(jsonObject.getString("salario
Diario"));

235

persona.setDiasLaborados(jsonObject.getString("diasLab
orados"));
persona.setSueldo(jsonObject.getString("sueldo"));
personasAux.add(persona);
} catch (JSONException e) { Log.e("peticin", "Error al
parsear");}
}
return personasAux;
}
}
Layout de MainActivity
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.android.nomina.MainActivity">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="3" >
<TextView
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/datos_crudos"
android:layout_gravity="center_horizontal" />
</ScrollView>
<ListView
android:layout_weight="1"
android:headerDividersEnabled="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/list_view"
android:footerDividersEnabled="false" />
</LinearLayout>
El resultado de la ejecucin de todo esto que hemos realizado lo podemos ver en la siguiente imagen

236

Datos en crudo

Datos procesados


En el cual se puede apreciar en la parte superior la seccin en dnde se muestran los datos en crudo tal
como los obtenemos desde nuestro proyecto en Google Docs. Y la segunda parte muestra una lista con
la misma informacin pero ya con la informacin formateada de tal manera que sea entendible para el
usuario. Otra punto a destacar es que en cada ocasin en la que cambiemos la informacin en nuestra
hoja de Google los datos de que sean modificados se reflejaran en nuestra aplicacin mvil, pero para
poder ver esto es necesario cerrar la aplicacin y cargarla de nuevo para que se note el cambio.

Navegacin
Navegacin con Back y Up
La navegacin consistente es un componente esencial de la experiencia general del usuario. Hay pocas
cosas que frustran ms a los usuarios de navegacin bsica que se comporta de maneras contradictorias
e inesperadas. Android 3.0 introdujo cambios significativos en el comportamiento global de navegacin.
Cuidadosamente siguiendo las directrices para atrs (back) y hacia arriba (up) har que la navegacin de
sus aplicaciones sea previsible y fiable para los usuarios.
Android 2.3 y anteriores se bas en el sistema de botn Atrs para apoyar la navegacin dentro de una
aplicacin. Con la introduccin de las barras de accin en Android 3.0, un segundo mecanismo de

237

navegacin apareci: el botn de arriba, que consiste en el icono de la aplicacin y un smbolo de


intercalacin de punto a la izquierda.

Up vs. Back
El botn Arriba se utiliza para navegar dentro de una aplicacin basada en las relaciones jerrquicas
entre pantallas. Por ejemplo, si la pantalla A muestra una lista de elementos, y la seleccin de un
elemento conduce a la pantalla de B (que presenta ese tema con ms detalle), a continuacin, la
pantalla B debe ofrecer un botn Arriba que devuelve a la pantalla A.
Si una pantalla es la ms alta en una aplicacin (es decir, el hogar de la aplicacin), no debe presentar un
botn Arriba.
El sistema de botn Atrs se utiliza para navegar, en orden cronolgico inverso, a travs de la historia de
las pantallas que el usuario ha trabajado recientemente. Se basa generalmente en las relaciones
temporales entre las pantallas, en lugar de la jerarqua de la aplicacin.
Cuando la pantalla vista anteriormente es tambin el padre jerarquico de la pantalla actual, al pulsar el
botn Atrs tiene el mismo resultado que al pulsar un botn Up esto ocurre comunmente. Sin
embargo, al contrario el botn de arriba, lo que garantiza es que el usuario permanezca dentro de su
aplicacin, el botn Atrs puede devolver al usuario a la pantalla de inicio, o incluso a una aplicacin
diferente.

238

El botn Back tambin es compatible con algunos comportamientos que no estn directamente
vinculados a la navegacin de pantalla a la pantalla:

Desestima las ventanas flotantes (dilogos, popups)


Desestimar barras de accin contextual, y elimina el resaltado de los elementos seleccionados
Oculta el teclado en pantalla (IME)

Navegacin dentro de su aplicacin


1. Navegar a pantallas con mltiples puntos de entrada
A veces, una pantalla no tiene una posicin estricta dentro de la jerarqua de la aplicacin, y se puede
llegar desde mltiples puntos de entrada-tales como una pantalla de configuracin que se puede llegar
desde cualquier otra pantalla en su aplicacin. En este caso, el botn UP debera optar por regresar a la
pantalla de referencia, comportndose de forma idntica al fondo.
2. Cambio de vista en una pantalla
Cambiar las opciones de visualizacin para la pantalla no cambia el comportamiento de Up o posterior:
la pantalla sigue en el mismo lugar dentro de la jerarqua de la aplicacin, y no se crea un nuevo historial
de navegacin.

Ejemplos de tales cambios de vista son:

Vistas de conmutacin utilizando pestaas y / o swipes de izquierda y derecha


Cambiar vistas usando un men desplegable (tambin conocido como pestaas colapsadas)
Filtrando un a lista
Ordenando una lista
Cambio de caractersticas de visualizacin (como el zoom)


3. Navegar entre pantallas hermanas
Cuando la aplicacin soporta la navegacin entre una lista de elementos hacia una vista detallada de
uno de esos artculos, a menudo es conveniente que soporte la direccin de navegacin a partir de ese
punto a otro que le precede o le sigue en la lista. Por ejemplo, en Gmail, es fcil deslizar hacia la
izquierda o hacia la derecha a partir de una conversacin para ver una ms nueva o ms antigua en la
misma bandeja de entrada. Del mismo modo que al cambiar la vista en una pantalla, como la
navegacin no cambia el comportamiento de Up o Back.

239


Sin embargo, una notable excepcin a esto ocurre cuando se navega entre las vistas de detalle
relacionados no ligadas a a referida lista -por el ejemplo, cuando se navega en la Play Store entre
aplicaciones del mismo desarrollador, o lbumes del mismo artista. En estos casos, despus de cada
enlace crea la historia, haciendo que el botn Back se desplase por cada pantalla que visualizada
anteriormente. Up podra continuar para eludir esas pantallas relacionadas y vaya a la pantalla de
contenedores utilizada ms recientemente.

240


Tambin se tiene la capacidad de hacer el comportamiento Up an ms inteligente basado en el
conocimiento de la vista de detalle. Ampliando el ejemplo de arriba de Play Store, imagine que el
usuario ha navegado desde el ltimo libro a los detalles de la adaptacin de la pelcula. En ese caso, Up
puede volver a un contenedor (Pelculas), que el usuario no ha navegado travs de el.

241

Navegando dentro de la aplicacin va Widgets en la pantalla Home y las


Notificaciones.
Puede utilizar los widgets de la pantalla principal o notificaciones para ayudar a los usuarios a navegar
directamente a las pantallas mas profunds de la jerarqua de su aplicacin. Por ejemplo, la Bandeja de
entrada del widget de Gmail y la notificacin de nuevo mensaje pueden saltar la pantalla Bandeja de
entrada, llevando al usuario directamente a una vista de conversacin.
Para ambos de estos casos, manejar el botn UP de la siguiente manera:

Si la pantalla de destino suele ser accesible desde una pantalla en particular dentro de la
aplicacin, Up debera navegar a esa pantalla.
De lo contrario, Up debera ir a la pantalla superior ("Home") de su aplicacin.

En el caso del botn Back, se debe hacer la navegacin ms predecible mediante la insercin en la pila
de retroceso de la ruta completa de navegacin hacia arriba para la pantalla superior de la aplicacin.
Esto permite a los usuarios que han olvidado como ellos entraron en la aplicacin para navegar a la
pantalla superior de la aplicacin antes de salir.

242

A modo de ejemplo, el widget de Gmail en la pantalla Inicio tiene un botn para el salto directamente a
la ventana de redaccin. O la vuelta de la ventana de redaccin podra llevar al usuario a la Bandeja de
entrada, y desde all en el botn Back sigue Home.

Notificaciones Indirectas
Cuando una aplicacin necesita para presentar informacin sobre varios eventos a la vez, se puede
utilizar una sola notificacin que dirige al usuario a una pantalla intersticial. Esta pantalla resume estos
eventos, y ofrece caminos para que el usuario sumergirse profundamente en la aplicacin.
Notificaciones de este estilo se denominan notificaciones indirectas.
A diferencia de las notificaciones estndar (directas), al pulsar Back de la pantalla intersticial de una
notificacin indirecta devuelve al usuario al punto donde la notificacin se desencaden -no se insertan
pantallas adicionales en la pila de retroceso. Una vez que el usuario procede en la aplicacin desde la
pantalla intersticial, Up y Back se comportan como para las notificaciones estndar, tal como se describe
ms arriba: navegando dentro de la aplicacin en lugar de volver al intersticial.
Por ejemplo, supongamos que un usuario de Gmail recibe una notificacin indirecta desde Calendario.
Al tocar esta notificacin se abre la pantalla intersticial, que muestra recordatorios para diferentes
eventos. Tocando Back desde la intersticial devuelve al usuario a Gmail. Al tocar en un evento en
particular lleva al usuario lejos de la intersticial e ingresando por completo a la aplicacin Calendario
para mostrar los detalles del evento. A partir de los detalles del evento, arriba y atrs navegar a la vista
de nivel superior de Calendario.

243

Notificaciones pop-up
Las notificaciones pop-up evitan el buzn de notificaciones, en lugar de eso aparecen directamente en
frente del usuario. Rara vez se utilizan, y deben reservarse para ocasiones en que se requiere una
respuesta oportuna y la interrupcin del contexto del usuario si es necesario. Por ejemplo, Talk utiliza
este estilo para alertar al usuario de la invitacin de un amigo a unirse a un chat de vdeo, ya que esta
invitacin caducar automticamente despus de unos segundos.
En trminos de comportamiento de navegacin, las notificaciones emergentes siguen de cerca el
comportamiento de la pantalla intersticial de una notificacin indirecta. Back descarta la notificacin
emergente. Si el usuario se desplaza desde el pop-up en la aplicacin notifica, Up y Back siguen las
reglas para las notificaciones estndar, navegando dentro de la aplicacin.

244

Navegando entre aplicaciones


Una de las fortalezas fundamentales del sistema Android es la capacidad de las aplicaciones para
activarse entre s, dando al usuario la posibilidad de navegar directamente desde una aplicacin a otra.
Por ejemplo, una aplicacin que necesita capturar una foto puede activar la aplicacin de la cmara, que
devolver la foto a la aplicacin. Este es un gran beneficio tanto para el desarrollador, que puede
aprovechar fcilmente el cdigo de otras aplicaciones, y el usuario que disfruta de una experiencia
consistente para las acciones que se realizan normalmente.
Para entender la navegacin aplicacin a aplicacin, es importante para entender el marco de
comportamiento de Android que se discute a continuacin.

Actividades, tareas e intents

En Android, una actividad es un componente de aplicacin que define una pantalla de informacin y
todas las acciones asociadas que el usuario puede realizar. Las aplicaciones son una coleccin de
actividades, que constan tanto de las actividades que se crean y las que se reusan de otras aplicaciones.

245

Una tarea es la secuencia de actividades de un usuario sigue para lograr una meta. Una sola tarea puede
hacer uso de las actividades de una sola aplicacin, o puede basarse en las actividades de un nmero de
diferentes aplicaciones.
Un intent es un mecanismo para que una aplicacin indique que le gustara la ayuda de otra aplicacin
en la realizacin de una accin. Las actividades de una aplicacin pueden indicar a cuales intents pueda
responder. Para los intents comunes tales como "Compartir", el usuario puede tener muchas
aplicaciones instaladas que pueden cumplir esa peticin.

Ejemplo: navegacin entre aplicaciones para apoyar el intercambio

Para comprender cmo las actividades, tareas, y los intents trabajan juntos, considere cmo una
aplicacin permite a los usuarios compartir contenido utilizando otra aplicacin. Por ejemplo, el
lanzamiento de la aplicacin Play Store desde Home comienza nueva tarea A (ver figura siguiente).
Despus de navegar a travs de la Play Store y tocar un libro promovido para ver sus detalles, el usuario
permanece en la misma tarea, que se extiende mediante la adicin de actividades. Activando la accin
Compartir pide al usuario con un dilogo donde se enumeran cada una de las actividades (de diferentes
aplicaciones) que se han registrado para manejar el intent Compartir.

246

Cuando el usuario decide compartir a travs de Gmail, se aade la actividad de redaccin de Gmail como
una continuacin de la tarea A-ninguna nueva tarea se crea. Si Gmail tena su propia tarea en
funcionamiento en segundo plano, no se vera afectada.
Desde la actividad de redaccin, enviando el mensaje o tocando el botn Back, regresa al usuario a la
actividad de detalles del libro. Toques posteriores de Back continuan navegando a travs de la Play
Store, llegando hasta Home.


Sin embargo, al tocar Up en la actividad de redaccin, el usuario indica un deseo de permanecer dentro
de Gmail. Aparece la actividad lista de conversaciones de Gmail, y una nueva Tarea B se crea para ello.
Nuevas tareas siempre estn arraigadas a la portada, por lo que tocando Back desde la lista de
conversacin se vuelve all.

247


La tarea A persiste en el fondo, y el usuario puede volver a ella ms tarde (por ejemplo, a travs de la
pantalla Recientes). Si Gmail ya tena su propio tarea funcionando en segundo plano, sera sustituida por
la tarea B -el contexto previo se abandona en favor de la nueva meta del usuario.
Cuando la aplicacin registra manejar los intentos con una actividad profunda dentro de la jerarqua de
la aplicacin, consulte Navegacin en su aplicacin a travs de widgets de la pantalla principal y
Notificaciones para obtener orientacin sobre cmo especificar de navegacin hacia arriba.

248

Estilos en Android

Dispositivos y Pantallas
Android potencializa a millones de telfonos, tabletas y otros dispositivos en una amplia variedad de
tamaos de pantalla y factores de forma. Al tomar ventaja del sistema de diseo flexible de Android,
se pueden crear aplicaciones que se adapten a la escala de grandes tabletas as como tambin
de telfonos ms pequeos.


Sea flexible
Estirar y comprimir sus diseos para adaptarse a diferentes alturas y anchuras.
Optimice los diseos
En los dispositivos ms grandes, se debe aprovechar el espacio adicional en pantalla. Cree vistas
compuestas que combinan mltiples vistas para revelar ms contenido y facilidad de navegacin.


249

Activos para todos


Proporcionar recursos para diferentes densidades de pantalla (DPI) para garantizar que su aplicacin se
vea bien en cualquier dispositivo.






Estrategias
As que, por dnde empezar cuando se disea para mltiples pantallas? Un mtodo consiste en
trabajar en la norma base (tamao normal y MDPI) y escalar hacia arriba o hacia abajo para los otros
cubos. Otro mtodo consiste en comenzar con el dispositivo con el tamao de pantalla ms grande, y
despus escalar hacia abajo y averiguar el tipo interfaz de usuario que se necesitara hacer para
ajustarlo en las pantallas ms pequeas.


Temas
Los temas son el mecanismo de Android para aplicar un estilo coherente con una aplicacin o
actividad. El estilo especifica las propiedades visuales de los elementos que componen la interfaz de
usuario, como el color, la altura, el relleno y el tamao de la fuente. Para promover una mayor cohesin
entre todas las aplicaciones en la plataforma, Android proporciona dos temas del sistema que usted
puede elegir la hora de la creacin de aplicaciones:

Holo Light
Holo Black

La aplicacin de estos temas recorren un largo camino para ayudar a construir aplicaciones que se
adapten correctamente en el lenguaje visual general de Android.





250






Gmail en Holo Light.









Ajustes en Holo Black.


Elija el tema del sistema que mejor se adapte a las necesidades y la
esttica de diseo para su aplicacin. Si su deseo es tener una mirada
ms clara para su aplicacin, utilizando uno de los temas del sistema
como punto de partida para las personalizaciones es una buena
idea. Los temas del sistema proporcionan una base slida sobre la
que se puede implementar de forma selectiva sus propios estilismos
visuales.




251

Retroalimentacin al Toque
Utilizar iluminacin y oscurecimiento al responder a los toques, reforzar los comportamientos
resultantes de gestos, e indicar qu acciones estn activadas y desactivadas.
Sea sensible a toques de una manera suave. Cada vez que un usuario toca un rea procesable en su
aplicacin, hacerles saber que la aplicacin est "escuchando", proporcionando una respuesta visual.
Que sea sutil slo un poco ms claro o ms oscuro que el color intacto. Esto proporciona dos beneficios:

Chispazos son ms agradable que las sacudidas.


La incorporacin de su marcan es mucho ms fcil porque la retroalimentacin tctil de
regeneracin funciona con cualquier color que elija.

252

Estados


La mayor parte de los elementos de interfaz de usuario de Android tienen retroalimentacin tctil
incorporada, incluyendo estados que indican si tocar el elemento tendr ningn efecto.

Comunicacin
Cuando los objetos reaccionan a los gestos ms complejos, ayudan a los usuarios a entender cul ser el
resultado.

253

En Recientes, cuando un usuario inicia a deslizar la miniatura hacia la izquierda o la derecha, comienza
a oscurecerse. Esto ayuda al usuario a comprender que el deslizamiento har que el elemento ser
removido
Lmites
Cuando los usuarios intentan desplazarse ms all del principio o al final de un rea de desplazamiento,
se comunica el lmite con una seal visual. Muchos de los widgets de interfaz de usuario de Android
desplazables, como listas y listas de la red, tienen retroalimentacin de apoyo para el lmite integrado. Si
usted est construyendo widgets personalizados, tenga retroalimentacin del lmite en mente y
ofrezcala en su aplicacin.

Si un usuario intenta desplazarse ms all del ltimo panel de la


pantalla de inicio, el contenido de la pantalla se inclina hacia la
derecha para indicar que una mayor navegacin en este sentido
no es posible.

Mtricas y Rejillas
Los dispositivos varan no slo en tamao fsico, sino tambin en la densidad de la pantalla (DPI). Para
simplificar la forma de disear para mltiples pantallas, pensar en cada dispositivo como caer en un
cubo de tamao y densidad cubo especial:

Los cubos de tamao son el hanset (menor que 600 DP) y la tableta (mayor que o igual 600dp).

254

Los cubos de densidad son LDPI, MDPI, IPAP, XHDPI, XXHDPI, y XXXHDPI.

Optimizar la interfaz de usuario de la aplicacin mediante el diseo de esquemas alternativos para


algunos de los diferentes grupos de tamao, y proporcionar imgenes de mapa de bits alternativos para
diferentes cubos de densidad.
Porque es importante que al disear e implementar sus diseos para varias densidades, las siguientes
instrucciones se refieren a las dimensiones de diseo con mediciones dp en lugar de pxeles.

Consideraciones sobre
el espacio
Dispositivos varan en la
cantidad de pxeles
independientes de la
densidad (dp) que
se pueden mostrar.

48dp Rhythm
Los Componentes en la interfazque el usuario puede tocar o manejar son generalmente dispuestas a lo
largo de 48dp unidades.


Por qu 48dp?
En promedio, 48dp se traducen a un tamao fsico de aproximadamente de 9 mm (con cierta
variabilidad). Esto es cmodo en la gama de tamaos recomendados (7-10 mm) para los objetos de la
pantalla tctil y los usuarios sern capaces de forma fiable y precisa apuntarlos con sus dedos.
Si el diseo de los elementos son de al menos 48dp alto y ancho usted puede garantizar que:

sus objetivos nunca ser menor que el tamao mnimo recomendado de 7mm,
independientemente de lo que se muestre en la pantalla.

255

usted tiene un buena realcin entre la densidad de informacin general por un lado, y
la seleccin de elementos de la interfaz en el otro.


Cuidado con el hueco
El espacio entre cada elemento de la interfaz de usuario es 8dp.
Ejemplos:













256

Tipografa

El lenguaje de diseo de Android se basa en herramientas tipogrficas tradicionales como la escala, el


espacio, el ritmo y la alineacin con una cuadrcula subyacente. La implementacin exitosa de estas
herramientas es esencial para ayudar a los usuarios a comprender rpidamente una pantalla de
informacin. Para apoyar este uso de la tipografa, desde la versin Ice Cream Sandwich se introduce
una nueva familia tipogrfica con nombre Roboto, creada especficamente para los requisitos de la
interfaz de usuario y las pantallas de alta resolucin.

257

El actual marco TextView ofrece Roboto en variantes delgadas, ligeras, regular y negrita, junto con un
estilo de cursiva para cada variante. El marco tambin ofrece la variante Roboto Condensada en pesos
regulares y audaces , junto con un estilo de cursiva para cada variante.
Colores de tipo predeterminado
La interfaz de usuario de Android utiliza los siguientes estilos de color por defecto: textColorPrimary
y textColorSecondary. Para los temas ligeros utiliza textColorPrimaryInverse y
textColorSecondaryInverse. Los estilos de color de texto de framework tambin admiten variantes para
el tacto de retroalimentacin cuando se utiliza dentro de los elementos de interfaz de usuario.


Escala Tipogrfica
El contraste en tamaos de letra puede recorrer un largo camino para crear diseos comprensibles. Sin
embargo, tambin muchos tamaos diferentes en la misma interfaz de usuario puede ser un poco
incmodo. El framework de Android utiliza el siguiente conjunto limitado de tamaos de letra:

Los usuarios pueden seleccionar un factor de escala de todo el sistema para el texto en aplicacin
Ajustes. Para apoyar estas funciones de accesibilidad, la tipografa debe especificarse en pixeles de
escala independiente (sp) siempre que sea posible. Los diseos que soporten tipografas escalables
deben ser probados contra estos valores.

Color
Usar colores primarios para enfasis. Escoja los colores que vayan con su marca y proporcione un buen
contraste entre los componentes visuales. Note que el rojo y el verde pueden ser indistinguibles para los
daltonicos.

258


Paleta
El azul es el color de enfasis estandar en la paleta de colores de Android. Cada color tiene su tono ms
oscuro correspondiente que puede ser usado como un complemento cuando sea necesario.

Iconografa


Un icono es una grfica que ocupa una pequea parte del espacio de la pantalla y proporciona una
rpida representacin intuitiva de una accin, un estado o una aplicacin.
Al disear iconos para su aplicacin, es importante tener en cuenta que su aplicacin se puede instalar
en una variedad de dispositivos que ofrecen una amplia gama de densidades de pxeles, como se
menciona en la seccin Dispositivos y Pantallas. Pero usted puede hacer que sus iconos se vean muy
bien en todos los dispositivos, proporcionando a cada icono en varios tamaos. Cuando su aplicacin se
ejecuta, Android comprueba las caractersticas de la pantalla del dispositivo y carga los assets
apropiados para la densidad especifica para su aplicacin.

259

Dado que va a entregar cada icono en varios tamaos para soportar diferentes densidades, las
directrices de diseo que siguen se refieren a las dimensiones del icono en las unidades dp, que se
basan en las dimensiones en pxeles de una pantalla de densidad media (MDPI).


Por lo tanto, para crear un icono para diferentes densidades, debe seguir la relacin de escala
2:3:4:6:8 entre los cinco densidades primarios (medio, alto, x-alta, xx-alta y alta, respectivamente-
xxx). Por ejemplo, considere la posibilidad de que se especifica el tamao de un icono de lanzador para
ser 48x48 dp. Esto significa que la lnea de base (MDPI) de activos es de 48x48 pxeles, y el asset de alta
densidad (HDPI) debe ser de 1,5 x de la lnea base en 72x72 pxeles, y los assets de x-high densidad
(XHDPI) deben ser 2 veces la lnea de base a 96x96 pxeles, y as sucesivamente.
Nota: Android tambin es compatible con pantallas de baja densidad (LDPI), pero normalmente no es
necesario crear assets personalizados en este tamao porque Android efectivamente reduce sus assets
HDPI a la mitad para que coincida con el tamao esperado.
Lanzador
El icono de lanzador es la representacin visual de su aplicacin en la pantalla de inicio o la pantalla All
Apps. Dado que el usuario puede cambiar el papel tapiz de la pantalla de inicio, asegrese de que el
icono de lanzador es claramente visible en cualquier tipo de fondo.

Dimensiones y escala

Iconos del lanzador en un dispositivo mvil


deben ser 48x48 dp .
Iconos del lanzador para su visualizacin en
Google Play debe ser 512x512 pxeles .

260

Dimensiones
Activo completo, dp 48x48


Estilo

Utilice una silueta distinta.


Tridimensional, de frente, con un ligero
punto de vista como si se mira desde
arriba, de modo que los usuarios perciben
una cierta profundidad

261

Action Bar
Iconos de la barra de accin son los botones grficos que representan las acciones ms importantes que
las personas pueden tomar dentro de su aplicacin. Cada uno debe emplear una metfora simple que
representa un concepto nico que la mayora de la gente puede entender de un vistazo.
Glifos pre-definidos deberan ser utilizados para ciertas acciones comunes tales como "actualizar" y
"compartir".
Dimensiones y escala

Iconos de la barra de accin


para los telfonos deben ser
32x32 dp .



rea focal y proporciones
Activo completo, dp 32x32
Plaza ptico, dp 24x24

Estilo

Pictogrfico, plano, no muy detallada, con


suaves curvas o formas agudas. Si el grfico es
delgado, girarla 45 a la izquierda o la derecha
para llenar el espacio focal. El grosor de los
trazos y espacios negativos debe ser un mnimo
de 2 dp.


Colores

Colores: #
333333
Habilitado: el
60% de
opacidad
para minusvlidos: 30%de opacidad


Colores: #
FFFFFF
Habilitado: el
80% de
opacidad
para minusvlidos: 30%de opacidad

262



Iconos pequeos/contextuales
Dentro del cuerpo de su aplicacin, use pequeos iconos para acciones superficiales y/o proporcionar el
estado de elementos especficos. Por ejemplo, en la aplicacin de Gmail, cada mensaje tiene un icono de
estrella que marca el mensaje como importante.

Dimensiones y escala

Iconos pequeos deben


ser 16x16 dp .

rea focal y proporciones


Activo completo, dp 16x16
Cuadrado ptico, dp 12x12



Estilo
Neutro, plana, y simple. Formas rellenas son ms
fciles de ver que los trazos finos. Utilice una sola
metfora visual de manera que un usuario puede
reconocer fcilmente y entender su propsito.






263



Colores

Utilice los colores no neutros


con moderacin y con un
propsito.Por ejemplo, Gmail
utiliza amarillo en el icono de
estrella para indicar un mensaje
marcado como favorito. Si el
icono es recurrible, elegir un
color que contraste con el
fondo.

Iconos de notificacin
Si su aplicacin genera notificaciones, proporcionar un icono que el sistema puede mostrar en la barra
de estado cada vez que una nueva notificacin est disponible.

Dimensiones y escala
Iconos de notificacin deben
ser 24x24 dp .

rea focal y proporciones


Activo completo, dp 24x24
Cuadrado ptico, dp 22x22

264

Estilo
Mantener el estilo llano y simple, utilizando el mismo
single, metfora visual como su icono de lanzador.

Colores
Iconos de notificacin deben ser
totalmente blanco. Adems, el
sistema puede escalar hacia abajo
y / u oscurecer los iconos.


Consejos de Diseo
Estos son algunos consejos que pueden resultar tiles a medida que crea iconos u otros drawables
assets para su aplicacin. Estos consejos se presupone que est utilizando programa Adobe Photoshop
o algn similar de edicin de imgenes raster y vector.
Utilice formas vectoriales cuando sea posible
Muchos programas de edicin de imgenes como Adobe Photoshop le permiten utilizar una
combinacin de formas vectoriales y capas raster y efectos. Cuando sea posible, utilice formas
vectoriales para que en caso de necesidad, los activos pueden ser ampliadas sin prdida de detalle y
nitidez de borde.

265

El uso de vectores tambin hace que sea fcil para alinear los bordes y esquinas a pxel lmites a
resoluciones menores.
Comience con grandes mesas de trabajo
Debido a que usted tendr que crear assets para diferentes densidades de pantalla, lo mejor es empezar
sus diseos de iconos en grandes mesas de trabajo con dimensiones que son mltiplos de los tamaos
de los iconos objetivo. Por ejemplo, los iconos del lanzador son 48, 72, 96, o 144 pxeles de ancho,
dependiendo de la densidad de la pantalla (mdpi, hdpi, xhdpi y xxhdpi, respectivamente). Si dibuja
inicialmente iconos de lanzadores en una mesa de trabajo 864x864, ser ms fcil y ms limpio para
ajustar los iconos cuando se escala la mesa de trabajo hasta los tamaos de destino para la creacin de
activos final.
Al escalar, vuelva a dibujar las capas de mapa de bits, segn sea necesario
Si escalas una imagen a partir de una capa de mapa de bits, en lugar de partir de una capa vectorial,
tendrn que volver a dibujar manualmente a aparecer ntidas a mayores densidades esas capas. Por
ejemplo, si un crculo 60x60 fue pintado como un mapa de bits para MDPI que tendr que volver a
pintar como un crculo 90x90 para HDPI.
Use convenciones de nombres comunes para los activos icono
Trate de nombrar archivos para que los assets relacionados se agrupan dentro de un directorio al que
estn ordenados alfabticamente. En particular, ayuda a utilizar un prefijo comn para cada tipo de
icono. Por ejemplo:

Tipo de activo

Prefijo

Ejemplo

Iconos

ic_

ic_star.png

Iconos del Lanzador

ic_launcher

ic_launcher_calendar.png

Iconos de men y barra de accin iconos

ic_menu

ic_menu_archive.png

Iconos de la barra de estado

ic_stat_notify

ic_stat_notify_msg.png

Iconos Tab

ic_tab

ic_tab_recent.png

Iconos de dilogo

ic_dialog

ic_dialog_info.png


Tenga en cuenta que no est obligado a usar un prefijo comn de cualquier tipo-hacerlo es slo para su
conveniencia.


266

Crear un espacio de trabajo que organiza los archivos por la densidad


Para soportar multiples densidades de pantalla significa que se deben crear multiples versiones del
mismo icono. Para ayudar a mantener las mltiples copias de los archivos seguros y fciles de encontrar,
se recomienda crear una estructura de directorios en tu espacio de trabajo que organiza los archivos
assets basados en la densidad objetivo
ejemplo:
art/...
mdpi/...
_pre_production/...
working_file . psd
finished_asset . png
hdpi/...
_pre_production/...
working_file . psd
finished_asset . png
xhdpi/...
_pre_production/...
working_file . psd
finished_asset . png
xxhdpi/...
_pre_production/...
working_file.psd
finished_asset.png



Debido a que la estructura del espacio de trabajo es similar a la de la aplicacin, se puede determinar
rpidamente qu assets deben copiarse en el directorio cada recursos. La separacin de los activos por
la densidad tambin le ayuda a detectar cualquier variacin en los nombres de archivos a travs de las
densidades, lo cual es importante porque los activos correspondientes a diferentes densidades debe
compartir el mismo nombre de archivo.







267

Para comparar, aqu est la estructura de directorio de recursos de una aplicacin tpica:
res/...
drawable- ldpi/...
finished_asset .
drawable- mdpi/...
finished_asset .
drawable- hdpi/...
finished_asset .
drawable- xhdpi/...
finished_asset .

png
png
png
png

Su imagen de marca
Siguiendo el patrn de diseo en Android no significa que tu aplicacin tenga la misma apariencia que la
de las aplicaciones de los dems. En Android, tu aplicacin puede brillar como una extensin de tu
marca.
Color
Usa el color de tu marca para Acentuar, sobrescribiendo el marco azul por defecto de los elementos
de la Interfaz de Usuario (UI) como, barras de progreso, botones radio, diapositivas, pestaas e
indicadores de scroll.
Busca la oportunidad de usar colores de contraste-alto para enfatizar, por ejemplo, el color de fondo de
la barra de accin, o un botn primario. Pero no te excedas: no todas las acciones son las mismas, as
que salo solamente para una o dos cosas importantes.
Cuando se personalizan los colores, la retroalimentacin tctil debe de ser sutil- solo ligeramente mas
claro u obscuro que el color sin tocar.

Los cuatro colores del Logo de la Cartera


de Google, proporcionan una acentuacin
agradable, la cual consiste en cuatro
puntos que aparecen mientras el usuario
introduce un PIN.

268

La Aplicacin de Google Play Music, tiene


un tema naranja, el cual es utilizado para
enfatizar la barra de accin y para
acentuar la pestaa seleccionada, el
indicador scroll as como los hipervnculos.


Logo
El lanzador del icono de tu aplicacin es la llave para incorporar tu logo, por que es lo que los usuarios
buscaran y tocaran al empezar a utilizar tu aplicacin. Tu puedes mover tu icono a travs de todas las
pantallas en tu aplicacin, mostrando en la barra de accin el nombre de la aplicacin.
Otra consideracin a tomar en cuenta es colocar el logo en tu icono, as como el nombre de la aplicacin
en la barra de accin.
Google +, refuerza su marca colocando su
icono a travs de la barra de accin.

269

Ejemplo del logo en la barra de accin.


Esto funciona bien en los casos cuando el
logo corresponde con el nombre de la
aplicacin.

Iconos
Si cuentas con iconos que ya estas usando para tu aplicacin en otras plataformas y estos a su vez tienen
un look distintivo de acuerdo a tu marca, los puedes utilizar tambin en tu aplicacin Android. Si se
toma en cuenta esta consideracin, tiene uno que estar seguro que el estilo de tu marca es aplicado a
cada icono en tu aplicacin.


Excepcin: para cualquier icono en tu juego existente de iconos donde la simbologa es manejada
diferente a como se maneja en Android, usa los smbolos de Android para darle estilo a tu marca. De esa
forma, el usuario entender que propsito tiene el icono. Aun as, el icono se vera como si perteneciera
a tu conjunto de iconos como parte de tu marca.
Ejemplo:
El icono normal para compartir con otras plataformas es la flecha hacia la derecha


Pero, qu pasara si no tienes aun tus propios iconos- por ejemplo, si estas creando una nueva
aplicacin solo para Android?. En este caso, usa los iconos estndar de Android.


270

Estilos de Escritura.
La voz de Android.
Al escribir el texto que aparece en su aplicacin, que sea concisa, simple y amigable.
Conciso:

Describa slo lo que el usuario necesita saber.

Eliminar la redundancia, como los ttulos que reiteran el cuerpo de un cuadro de informacin.

Mantener texto tan corto como sea posible.

Evite muchas palabras, texto abultado:


No hacer:
Consulte la documentacin que viene
con su telfono para futuras
instrucciones.

Hacer:
Lea las instrucciones que vienen con el telfono.

No proporcione informacin innecesaria
Desde una pantalla de Asistente de configuracin

Accediendo ...

El telfono necesita comunicarse con


los servidores de Google para iniciar sesin en su
cuenta.
Esto puede tardar hasta cinco minutos.






271

Desde una pantalla de Asistente de configuracin


Accediendo ...

El telfono est en contacto con Google.


Esto puede tardar hasta 5 minutos.

Simple

Utilice palabras cortas, verbos activos, y los nombres comunes.

Poner primero lo ms importante. "Carga frontal" los primeros 11 caracteres con la informacin
ms relevante en la cadena.

No trate de explicar las diferencias sutiles. Se pierden en la mayora de los usuarios.

Centrarse en la preocupacin del usuario, no los detalles tcnicos


No hacer
Controlar manualmente el GPS para evitar que otras
aplicaciones lo usen
Hacer
Para ahorrar energa, apague el modo de ahorro de
batera Ubicacin
Coloque las principales noticias primero
No hacer
Otras 77 personas han hecho +1 en esto, incluyendo
Larry Page
Hacer
Larry Page y otros 76 han hecho +1 en esto
Ponga la meta del usuario primero



272

No hacer
Toque Siguiente para completar la configuracin
mediante una conexin Wi-Fi

Hacer
Para finalizar la configuracin a travs de Wi-Fi,
toque Siguiente

Amistoso

Utilice contracciones.

Hablar directamente con el lector. Utilice "usted" para referirse al lector.

Mantenga su tono informal y coloquial, pero evite el argot.

Evite ser confuso o molesto


No hacer
Lo siento!
La Actividad MyAppActivity (en la aplicacin
MyApp) no est respondiendo
Hacer
MyApp no responde
Desea cerrarla?

Palabras a evitar
No utilice
uno, dos, tres, cuatro, ...

Use
1, 2, 3, 4, ...

273

Aplicacin

app

okay, ok,

OK

por favor, lo siento, gracias

Los intentos de cortesa pueden molestar al usuario,


especialmente en los mensajes que dicen que algo ha
ido mal.
Excepcin: En japons, "por favor" es obligatorio y
verbos imperativos deben ser localizadas en
consecuencia (encender -> por favor encienda).

hay, es y otros temas "desaparecidos"


(improperios gramaticales)

Utilice un sustantivo como sujeto

abortar, eliminar, dar por terminado

detener, cancelar, finalizar, salir

fallar, fracasado, un lenguaje negativo

En general, usar una frase positiva


(por ejemplo, "hacer" en lugar de "no hacer", salvo en
casos tales como "No mostrar de nuevo", "No se puede
conectar", y as sucesivamente.)

yo, mi, mo

usted, su, el suyo

Est seguro? Advertencia!

En lugar de eso encomendar a los usuarios la


consecuencia, por ejemplo, "Perder todas sus fotos y
los medios"


De formato al texto
Capitalizacin

Utilice maysculas al estilo de oracin para todas las cadenas de la IU: "Palabras para vivir."

Utilizar maysculas en todas las palabras importantes en:

Nombres de la aplicacin (Calendar, Google Drive)

Caractersticas con nombre (Android Beam, Face Unlock)

Los nombres propios (Estatua de la Libertad, San Francisco Giants)

Sea conservador. No utilice maysculas en palabras que no son parte de un nombre rasgo
formal:

274

Bloqueo de tarjeta SIM, Pantalla de Inicio, no Sim Card Lock.

Puntuacin

Perodo. No utilice un perodo despus de una sola oracin o frase que se usa de manera
aislada, como en un brindis, una etiqueta o notificacin. Dondequiera que dos o ms oraciones
corren juntas, utilice un punto para cada frase.

. Elipsis Utilice el carcter de puntos suspensivos (...) (Opcin-; en MacOS y ... en HTML) para
indicar
o

Incompletitud, como una accin en curso ("Downloading...") o el texto truncado.

Que un elemento del men (como impresin... o Compartir...) conduce a una mayor UI implica
decisiones importantes. Excepcin: Los comandos cuya redaccin ya implica ms (pero limitado) interfaz
de usuario, tales como Buscar en la pgina o Elija una fecha, no requieren

275

Anda mungkin juga menyukai