Desarrollo de aplicaciones basadas en Android

  • Robert Ramírez Vique

     Robert Ramírez Vique

    Ingeniero informático por la Universidad Politécnica de Cataluña y máster por la Universidad Ramón Llull. Es profesor de la UOC desde hace más de seis años, donde trabaja como especialista en las asignaturas relacionadas con las tecnologías móviles.

    Es desarrollador de aplicaciones para diferentes arquitecturas y tiene experiencia en varios sectores (eCommerce, sector industrial, etc.) y tecnologías.

PID_00178748

Licencia Creative Commons, versión 3.0, modalidad BY-SA (attribution - share alike), que permite modificar la obra, reproducirla, distribuirla o comunicarla públicamente siempre que se reconozca su autoría y siempre que la obra derivada quede sujeta a la misma licencia que el material original.

Introducción

En este módulo os presentamos una introducción al desarrollo de aplicaciones móviles basadas en Android. Para estudiar la plataforma Android, nos centraremos en el tipo de aplicaciones nativas, de manera que podáis ver sus particularidades en detalle y tengáis una visión más clara del desarrollo de aplicaciones nativas.
Android nació como una novedad con mucho futuro, y ha pasado de ser una gran promesa a uno de los grandes de la industria. Con muchos dispositivos, y en constante crecimiento, es una tecnología que, sin duda, debéis tener en cuenta. Además, ha sido construida con unas bases muy sólidas y sin cerrar la puerta a ninguna opción de desarrollo ni arquitectura, lo cual os puede resultar muy útil para aprender los desarrollos móviles.
Haremos un recorrido por las diferentes fases de desarrollo de una aplicación móvil (para el caso de Android).
En primer lugar, veremos una pequeña introducción sobre la historia y las peculiaridades de la tecnología. Después expondremos las razones por las que Android es, actualmente, uno de los grandes candidatos a líder mundial.
También veremos en detalle las herramientas que conforman todo el ecosistema, la arquitectura de las aplicaciones y su ciclo de vida típico.
A continuación, nos centraremos en las diferentes funcionalidades que nos ofrece la tecnología para acceder al hardware de los dispositivos, en la construcción de interfaces de usuario y en el almacenamiento de datos o de las comunicaciones. Aprovecharemos este apartado para que veáis las opciones que nos ofrece la plataforma para probar y mejorar nuestra aplicación.
Finalmente, tocaremos todos los temas relacionados con las fases de distribución de la aplicación. Veréis cómo se puede llegar a publicar una aplicación para que los usuarios puedan comprarla y su seguimiento posterior, y también os explicaremos cómo podéis aprovechar las herramientas que ofrece Android para hacer negocio, las cuales no se reducen únicamente a la venta directa.
De esta manera, tendréis la suficiente visión global de la tecnología como para poder comenzar un nuevo proyecto Android, sabréis qué opciones hay en cada apartado o, en su defecto, dónde encontrar dicha información.
Hay algunos temas que no quedarán cubiertos en este módulo. Las razones son las siguientes:
  • No veremos ningún tutorial, por lo que no existirá la descripción sobre cómo hacer un desarrollo paso a paso. Para eso, os proporcionarán recursos existentes fuera del módulo y específicamente diseñados para ello.

  • No os presentaremos una guía de referencia exhaustiva del desarrollo en Android; para ello están las referencias oficiales, que son mucho más amplias y están actualizadas. Sin embargo, os expondremos casos concretos para ayudaros a comprender el desarrollo.

  • Presuponemos que, gracias a otras asignaturas, tenéis bases de programación y de patrones de diseño de software.

Objetivos

Mediante el estudio de este módulo pretendemos que consigáis los objetivos siguientes:
  1. Que sepáis qué es Android y cuáles son sus posibilidades.

  2. Que sepáis cómo funcionan la aplicaciones en Android y dominéis las bases para poder desarrollarlas haciendo uso de las principales herramientas que existen.

  3. Que tengáis una visión global de todas las posibilidades que ofrece la plataforma, tanto en lo que respecta a las arquitecturas como en lo referente a API.

  4. Que conozcáis el proceso de comercialización de una aplicación Android, de modo que podáis llevarlo a cabo si es necesario, y su posterior seguimiento.

1.Introducción a Android

1.1.Pasado, presente y futuro de Android

Android fue fundada en el año 2003 por la empresa Android Inc. En el año 2005, Google la compró, e incorporó en sus filas a algunos de los principales valores de esta empresa, entre los que se encuentran Andy Rubin, Rich Miner y Chris White.
En noviembre del 2007, se crea la Open Handset Alliance, cuyo objetivo consiste en desarrollar estándares para dispositivos móviles. En esa misma fecha presentan su nuevo producto: Android, una plataforma construida sobre el kernel de Linux.
En diciembre del 2008 se añaden a la Open Handset Alliance catorce nuevos miembros, entre los que se encuentran ARM Holdings, Atheros Communications, Asustek Computer Inc, Garmin Ltd, PacketVideo, Softbank, Sony Ericsson, Toshiba Corp y Vodafone Group Plc.
En mayo del 2008 conceden los premios del primer Android Developer Challange, un concurso para conseguir las mejores aplicaciones para Android. Gracias a este concurso y a sus siguientes ediciones, consiguen una gran repercusión, además de grandes aplicaciones.
En septiembre del 2008 lanzan la primera versión de la plataforma, la 1.0, pero aún no existía ningún dispositivo.
Finalmente, en octubre del 2008, aparece el primer dispositivo, llamado T-Mobile o HTC Dream, que se vendió inicialmente en Estados Unidos y, posteriormente, en el resto del mundo. Desde entonces, el número de dispositivos no ha dejado de crecer; actualmente ya hay centenares de dispositivos diferentes.
En febrero del 2011 se hace oficial la primera versión no orientada a smarphones, sino a tablets PC, con mejoras en la interfaz, soporte de videochat y capacidades para un hardware mucho más potente.
Actualmente se habla de más de cien mil activaciones de dispositivos diariamente con la plataforma Android y de casi doscientos mil desarrolladores, que ya han creado decenas de miles de aplicaciones; un número que no deja de crecer.
Esta gran cantidad de novedades y la velocidad a la que aparecen, provoca que existan muchas versiones disponibles en cada momento, y eso es algo que debéis tener en cuenta a la hora de desarrollar para Android.

1.2.¿Qué es Android?

Android es una solución completa de software para dispositivos móviles. Incluye toda una pila de aplicaciones, como el sistema operativo, el middleware y las aplicaciones clave. También incluye herramientas para desarrollar en la plataforma, principalmente con el lenguaje de programación Java. Todo ello bajo licencia de código libre Apache, lo cual abre muchas posibilidades.
Android nos proporciona una serie de funcionalidades organizadas, tal como podéis ver en el siguiente gráfico.
Arquitectura de componentes de Android
1.2.1.Kernel o núcleo
El núcleo de Android está basado en el kernel de Linux, en el que se han realizado algunas modificaciones para adaptarlo a las necesidades de Android.
Este sirve como capa de abstracción del hardware al que tienen que acceder las aplicaciones. De esta manera, si se necesita un elemento hardware, la aplicación simplemente pedirá el recurso en genérico, sin tener que conocer el modelo exacto de hardware. Por ejemplo, si queremos acceder a la cámara, no importará el tipo, la definición ni el fabricante, simplemente accederemos a la cámara mediante el driver correspondiente.
1.2.2.Bibliotecas
La capa que se sitúa justo sobre el kernel la componen las bibliotecas nativas de Android. Estas bibliotecas están escritas en C o C++ y compiladas para la arquitectura hardware específica del teléfono, tarea que realiza normalmente el fabricante, que también se encarga de instalarlas en el terminal antes de ponerlo a la venta. Su cometido es proporcionar funcionalidad a las aplicaciones (para tareas que se repiten con frecuencia), evitar tener que codificarlas cada vez y garantizar que se llevan a cabo de la forma más eficiente.
Estas son algunas de las bibliotecas que se incluyen habitualmente:
  • Gestor de superficies (1) : Se encarga de componer, a partir de capas gráficas 2D y 3D, las imágenes que se muestran en la pantalla. Cada vez que la aplicación pretende dibujar algo en la pantalla, la biblioteca no lo hace directamente sobre ella. En vez de eso, realiza los cambios en imágenes (mapas de bits) que almacena en memoria y que después combina para formar la imagen final que se envía a la pantalla. Esto permite realizar con facilidad diversos efectos gráficos.

  • Scalable Graphics Library (SGL): Desarrollada por Skia (empresa adquirida por Google en el 2005) y utilizada tanto en Android como en Chrome (navegador web de Google), se encarga de representar elementos en dos dimensiones.

  • OpenGL for Embedded Systems (OpenGL ES): Motor gráfico 3D basado en las API (2) de OpenGL ES 1.0, 1.1 y 2.0. Utiliza aceleración hardware (si el dispositivo la proporciona) o un motor software altamente optimizado cuando no la hay.

  • Bibliotecas multimedia: Basadas en OpenCORE, permiten visualizar, reproducir e incluso grabar numerosos formatos de imagen, vídeo y audio.

  • WebKit: Motor web utilizado por el navegador (tanto como aplicación independiente como embebido en otras aplicaciones). Es el mismo motor que utilizan Google Chrome y Safari (el navegador de Apple, tanto en Mac como en el iPhone).

  • Secure Sockets Layer (SSL): Proporciona seguridad al acceder a Internet por medio de criptografía.

  • FreeType: Permite mostrar fuentes tipográficas, tanto basadas en mapas de bits como vectoriales.

  • SQLite: Motor de bases de datos relacionales, disponible para todas las aplicaciones.

  • Biblioteca C de sistema (libc): Está basada en la implementación de Berkeley Software Distribution (BSD), pero optimizada para sistemas Linux embebidos. Proporciona funcionalidad básica para la ejecución de las aplicaciones.

1.2.3.Entorno de ejecución
El entorno de ejecución de Android, aunque se apoya en las bibliotecas enumeradas anteriormente, no se considera una capa en sí mismo, dado que también está formado por bibliotecas. En concreto, por las bibliotecas esenciales de Android, que incluyen la mayor parte de la funcionalidad de las bibliotecas habituales de Java, así como otras específicas de Android. Se basa en funcionalidades del kernel (como el threading o la gestión de memoria a bajo nivel).
El componente principal del entorno de ejecución de Android es la máquina virtual Dalvik, componente que ejecuta todas y cada una de las aplicaciones no nativas de Android. Las aplicaciones se codifican normalmente en Java y son compiladas, pero no para generar un ejecutable binario compatible con la arquitectura hardware específica del dispositivo Android. En lugar de eso, se compilan en un formato específico para la máquina virtual Dalvik, que es la que las ejecuta. Esto permite compilar una única vez las aplicaciones y distribuirlas ya compiladas con la total garantía de que podrán ejecutarse en cualquier dispositivo Android que disponga de la versión mínima del sistema operativo que requiera cada aplicación.
No se debe confundir Dalvik con la máquina virtual Java, pues son máquinas virtuales distintas. De hecho, Google creó esta máquina virtual, entre otras cosas, para evitar problemas de licencias. Java es únicamente el lenguaje de programación, y los programas generados no son compatibles en cuanto a bytecode Java.
Los archivos generados para esta máquina virtual, archivos .dex, son muchos más compactos (hasta un 50%) que los generados para la máquina virtual Java tradicional. Para conseguir esto, Dalvik se basa en registros, en lugar de una pila para almacenar los datos, lo que requiere menos instrucciones. Esto permite ejecuciones más rápidas en un entorno con menos recursos.
Las aplicaciones Android se ejecutan cada una en su propia instancia de la máquina virtual Dalvik, de manera que se evitan interferencias entre ellas, y tienen acceso a todas las bibliotecas mencionadas antes y, mediante estas bibliotecas, al hardware y al resto de recursos gestionados por el kernel.
1.2.4.Marco de aplicaciones
La siguiente capa la forman todas las clases y servicios que utilizan directamente las aplicaciones para realizar sus funciones y que, obviamente, se apoyan en las bibliotecas y en el entorno de ejecución que ya hemos detallado. La mayoría de los componentes de esta capa son bibliotecas Java que acceden a los recursos mediante la máquina virtual Dalvik. Entre las más importantes se encuentran las siguientes:
  • Administrador de actividades (activity manager): Se encarga de controlar el ciclo de vida de las actividades y la propia pila de actividades. Sobre estas se puede hacer una metáfora con las ventanas de las aplicaciones de escritorio.

  • Administrador de ventanas (windows manager): Se encarga de organizar lo que se muestra en pantalla y de crear, para ello, superficies que pueden ser "rellenadas" por las actividades.

  • Proveedor de contenidos (content provider): Permite encapsular un conjunto de datos que va a ser compartido entre aplicaciones y crear, de esa manera, una capa de abstracción que permita acceder a dichos datos sin perder el control sobre cómo se accede a la información. Por ejemplo, uno de los proveedores de contenido existentes permite a las aplicaciones acceder a los contactos almacenados en el teléfono. Esta biblioteca nos permite crear también nuestros propios proveedores para permitir que otras aplicaciones accedan a información que gestiona la nuestra.

  • Vistas (views): Si antes equiparábamos las actividades con las ventanas de un sistema operativo de PC, las vistas las podríamos equiparar con los controles que se suelen incluir dentro de esas ventanas. Android proporciona numerosas vistas con las que construir las interfaces de usuario: botones, cuadros de texto, listas, etc. También proporciona otras más sofisticadas, como un navegador web o un visor de Google Maps.

  • Administrador de notificaciones (notification manager): Proporciona servicios para notificar al usuario cuando algo requiera su atención. Normalmente, las notificaciones se realizan mostrando alerta en la barra de estado, pero esta biblioteca también permite emitir sonidos, activar el vibrador o hacer pardear los LED del teléfono (si los tiene).

  • Administrador de paquetes (package manager): Las aplicaciones Android se distribuyen en paquetes (archivos .apk) que contienen tanto los archivos .dex como todos los recursos y archivos adicionales que necesite la aplicación, para facilitar su descarga e instalación. Esta biblioteca permite obtener información sobre los paquetes actualmente instalados en el dispositivo Android, además de gestionar la instalación de nuevos paquetes.

  • Administrador de telefonía (telephony manager): Proporciona acceso a la pila hardware de telefonía del dispositivo Android, si la tiene. Permite realizar llamadas o enviar y recibir SMS y MMS, aunque no permite reemplazar o eliminar la actividad que se muestra cuando una llamada está en curso (por motivos de seguridad).

  • Administrador de recursos (resource manager): Proporciona acceso a todos los elementos propios de una aplicación que se incluyen directamente en el código: cadenas de texto traducidas a diferentes idiomas, imágenes, sonidos e, incluso, estructuraciones de las vistas dentro de una actividad (layouts). Permite gestionar esos elementos fuera del código de la aplicación y proporcionar diferentes versiones en función del idioma del dispositivo o la resolución de pantalla que tenga, para poder contrarrestar la fragmentación actual de dispositivos.

  • Administrador de ubicaciones (location manager): Permite determinar la posición geográfica del dispositivo Android (usando el GPS o las redes disponibles) y trabajar con mapas.

  • Administrador de sensores (sensor manager): Permite gestionar todos los sensores hardware disponibles en el dispositivo Android: acelerómetro, giroscopio, sensor de luminosidad, sensor de campo magnético, brújula, sensor de presión, sensor de proximidad, sensor de temperatura, etc.

  • Cámara: Proporciona acceso a las cámaras del dispositivo Android, tanto para tomar fotografías como para grabar vídeo.

  • Multimedia: Conjunto de bibliotecas que permiten reproducir y visualizar audio, vídeo e imágenes en el dispositivo.

1.2.5.Aplicaciones
La capa superior de esta pila software la forman, como no podría ser de otra forma, las aplicaciones. En este saco se incluyen todas las aplicaciones del dispositivo, tanto las que tienen interfaz de usuario como las que no, tanto las nativas (programadas en C++) como las administradas (programadas en Java (3) ), tanto las que vienen de serie con el dispositivo como las instaladas por el usuario.
Aquí está también la aplicación principal del sistema: inicio (home), también llamada a veces lanzador (launcher), porque es la que permite ejecutar otras aplicaciones proporcionando la lista de aplicaciones instaladas y mostrando diferentes escritorios donde se pueden colocar accesos directos a aplicaciones o, incluso, pequeñas aplicaciones incrustadas o widgets, que son también aplicaciones de esta capa.
El aspecto principal a tener en cuenta de esta arquitectura es que todas las aplicaciones (las nativas de Android, las que proporciona Google, las que incluye de serie el fabricante del teléfono o las que instala después el usuario) utilizan el mismo marco de aplicación para acceder a los servicios que proporciona el sistema operativo. Esto implica dos cosas: que podemos crear aplicaciones que usen los mismos recursos que usan las aplicaciones nativas (nada está reservado o inaccesible) y que podemos reemplazar cualquiera de las aplicaciones del teléfono por otra de nuestra elección.
Este es el verdadero potencial de Android y lo que lo diferencia de su competencia: el control total por parte del usuario del software que se ejecuta en su teléfono.

2.Fundamentos de las aplicaciones

Como hemos visto anteriormente, una aplicación Android suele ser una aplicación escrita en Java y compilada a un fichero de tipo .apk. Dicho fichero se considera una aplicación y es el elemento usado por los dispositivos Android para instalar la aplicación.
Una aplicación puede estar compuesta por uno o más componentes, los cuales realizan funciones diferentes para darle el comportamiento a la aplicación, y cada uno puede ser activado de manera individual.
Más adelante veréis por qué estados puede pasar nuestra aplicación, para qué sirve cada uno y cómo podéis prepararos para ello.
Es importante que tengáis presente que las aplicaciones Android se ejecutan sobre un único y separado proceso Linux que tiene su propia máquina virtual, de manera que tienen los recursos restringidos y controlados, cosa que es ideal para maximizar la seguridad. Siguiendo el principio de los mínimos privilegios, a cada proceso se le adjudican, por defecto, los permisos de acceso a los componentes que requiere y ninguno más.
Sin embargo, se pueden hacer excepciones:
  • Se pueden tener varias aplicaciones compartiendo un recurso (para ello deben tener el mismo user ID), para lo cual es necesario que estén firmadas con el mismo certificado.

  • Si una aplicación sabe de antemano que quiere acceder a recursos como, por ejemplo, la cámara, Bluetooth, etc., debe pedírselo al usuario de forma explícita en el momento de instalarla. Esto se lleva a cabo gracias al manifiesto.

2.1.Componentes de una aplicación

Para facilitar la reutilización de código y agilizar el proceso de desarrollo, las aplicaciones Android se basan en componentes. Los componentes pueden ser de cuatro tipos:
1) Actividades (activity): Como hemos visto, son interfaces visuales que esperan alguna acción del usuario. Una aplicación puede tener una actividad o más, y desde una actividad se puede invocar a otras y volver nuevamente a la original. Todas las actividades extienden la clase activity. El contenido visual de cada actividad lo proporciona una serie de objetos derivados de la clase view. Android proporciona muchos de estos objetos prediseñados (como botones, selectores, menús, etc.).
2) Servicios (services): Los servicios no tienen interfaz gráfica, son procesos que se ejecutan en segundo plano para realizar acciones de larga duración.
3) Proveedores de contenidos (content providers): Permiten que una aplicación ponga ciertos datos a disposición de otras aplicaciones. Estos datos pueden estar guardados en ficheros, en una base de datos SQLite, en la web o en cualquier otro sitio que sea accesible. Mediante ellos, otras aplicaciones pueden preguntar o incluso modificar estos datos.
4) Receptores de eventos (broadcast receivers): Estos componentes están simplemente esperando a que se produzcan determinados eventos (batería baja, cambio del idioma del dispositivo, la descarga de una imagen nueva...). Cualquier aplicación puede tener tantos receptores para tantos eventos como quiera. Cada uno de ellos debe extender la clase BroadCastReceiver.
Como podéis ver, hay varias maneras de acceder a una aplicación y de comunicación entre las aplicaciones. Este es, sin duda, un punto fuerte de las aplicaciones Android. La comunicación entre aplicaciones, dado que se ejecutan en procesos con permisos distintos, no se puede hacer directamente. Para ello se utilizan los intents.

2.2.Ciclo de vida

El ciclo de vida de una aplicación está íntimamente ligado al de una activity, y su ciclo de vida también. Para que conozcáis mejor cómo funcionan las aplicaciones vamos a mostraros cómo se organizan a nivel de usuario.
Unos elementos importantes en Android son las tasks. Una task contiene una o varias activities. De alguna manera, es la tarea del usuario para conseguir algo.
Podéis salir de una task pulsando el botón atrás (back) o bien con el botón inicio (Home). En el caso del botón atrás, se destruirán la task y todas las activities y, por tanto, si se vuelve a esa activity, se habrá perdido el estado (a no ser que haya sido guardado de forma explícita). En cambio, si se sale de la task mediante el botón inicio (home), el estado de la activity estará implícitamente guardado.
Por tanto, una task tiene varias activities, debido a que una activity puede invocar a otra activity, y todas ellas están en la misma task. Cuando una activity crea otra, lo hace mediante un Intent, y lo puede hacer de dos maneras: esperando resultados (startActivityForResult()) o no esperándolos (startActivity()). En ambos casos, una vez finalizada la activity creada, se vuelve a la activity creadora. Esto se puede producir muchas veces gracias a las pilas de actividades que hay dentro de una tarea. Estas tareas también tienen su pila para permitir interrupciones y, en cierto modo, permitir múltiples hilos de ejecución.
Ejemplo
Estamos trabajando con una aplicación de calendario y vemos en una cita que hay una dirección de correo electrónico. Vamos a enviar un correo electrónico a esta cuenta, pero en ese momento nos llaman por teléfono.
Como resultado, en la pila de tasks tendremos dos tasks, una correspondiente a la aplicación de calendario, y otra correspondiente a la aplicación de teléfono, debido a que la segunda ha interrumpido a la primera.
Además, la primera task tendrá varias activities, en concreto, en el listado de elementos del calendario, la activity para ver un elemento del calendario concreto, y finalmente la activity que corresponde a la otra aplicación, la del envío de correo electrónico.
Cuando finalice la task del teléfono, volveremos a la task anterior y con la activity de correo electrónico.
Por todo ello, las activities tienen que comunicarse entre ellas. Invocar una activity parece algo bastante habitual y un gran punto a favor de Android. Sin embargo, por otro lado se defiende hacer que las activities estén lo menos acopladas posible entre ellas. Esto se consigue con los intents.
Hay activities que pueden tener varios puntos de entrada, y para ello definen varios IntentFilters. Con estos IntentFilters se puede también hacer activities que esperen a intents conocidos, como puede ser enviar un correo electrónico o elegir una fotografía. Si hay más de una activity para un mismo intent, se nos preguntará qué activity iniciar al producirse este intent. La información sobre a qué intents va a reaccionar una activity está definida en el manifiesto.
m1308_m5_003.jpg
Como vemos, una activity puede estar en diferentes estados mientras está ejecutándose. Estos estados se pueden resumir básicamente en tres:
1) Resumida: La actividad está en primer plano y tiene el foco del usuario. También se conoce como estado de ejecución o running (en inglés).
2) Pausada: Hay otra actividad en primer plano que está resumida, pero la pausada es aún visible. Esto puede suceder cuando la actividad en primer plano no cubre todo la pantalla o es parcialmente transparente. La actividad mantiene toda la información de memoria y está completamente viva, aunque puede llegar a ser destruida en un caso extremo de falta de memoria.
3) Terminada: La actividad está totalmente ocultada por otra actividad, y está en segundo plano. La actividad está totalmente viva, pero no es visible y puede ser destruida cuando el sistema necesite más memoria.
A las actividades pausadas o terminadas las puede destruir el sistema avisando (llamando al método finish()) o, directamente, destruyendo el proceso de sistema. Cuando una actividad vuelve después de ser destruida, se construye nuevamente.
Para conseguir programar las transiciones de estados de manera flexible y sostenible, Android provee un sistema de callbacks o retrollamada, de manera que el desarrollador puede tomar las acciones apropiadas en cada momento. A continuación podéis ver en la figura siguiente cuáles son:
Hay algunos eventos que son especialmente importantes:
1) onCreate: Es el punto de inicio, donde tenemos que iniciar toda la interfaz gráfica, además de crear todos los elementos. Como se puede llegar después de haber sido destruida, es posible que tengáis que recuperar el estado de algún origen persistente.
2) onPause y onStop: Son los eventos correspondientes a las paradas de la aplicación, y se debe guardar el estado de la sesión correspondiente. Después de estos eventos, la aplicación pasa a estar pausada (onPause) o terminada (onStop).
3) onResume y onStart: La aplicación vuelve del estado pausada o terminada y debe recuperar la información de la sesión.
4) onDestroy: Es el punto en el que se deben liberar los recursos, justo antes de destruir definitivamente la aplicación.
En cuanto al ciclo de vida, es importante tener en cuenta que, una vez se ha pasado el estado onPause (siempre sucede antes de un onStop y un onDestroy), la aplicación puede ser destruida directamente por el sistema operativo. Por tanto, la manera segura de almacenar la información del estado de la sesión es en el método onPause, pero hay que hacerlo con cuidado, porque estamos bloqueando la siguiente actividad y podemos empeorar la experiencia de usuario.
Para facilitarle la vida al desarrollador, existe un método al que el sistema llama cuando cree que es necesario guardar el estado: onSaveInstanceState(). Todas las vistas lo implementan con una implementación por defecto (por ejemplo, un campo de texto guarda su valor). Consiste en guardar pares de clave y valor para su posterior recuperación. En el caso de las actividades, sucede lo mismo; se puede sobrescribir el comportamiento por defecto para guardar el estado, y el objeto donde se guardan las claves-valor se pasará al método onCreate cuando se recupere el estado después de ser destruido, pudiendo utilizar también el método onRestoreInstanceState.
Todo estos métodos utilizados para gestionar la destrucción y la creación de las actividades cobran especial interés, pues cuando hay cambios en la configuración (como la orientación de la pantalla, el idioma, la aparición del teclado virtual), el sistema reinicia la actividad (se llama al onDestroy y después al onCreate). Esto permite adaptar la aplicación a las nuevas configuraciones.

2.3.Intenciones (Intents)

Para que varias aplicaciones de una misma tarea puedan comunicarse entre ellas, se lanza una intención (en inglés, intent) o solicitud para que un componente lleve a cabo una tarea.
Los intents ofrecen un servicio de paso de mensajes que permite interconectar componentes de la misma o de distintas aplicaciones.
Los intents se utilizan para invocar una nueva actividad o para enviar eventos a múltiples actividades (llamados broadcast intents). Los intents son gestionados por los receptores de eventos o broadcast receivers, que pueden escuchar a cualquier intent.
Un intent se describe con los siguiente atributos:
  • El nombre del componente que queremos avisar. Por ejemplo, la aplicación de correo electrónico.

  • La acción que se quiere lanzar. Por ejemplo, editar, llamar, sincronizar, información de batería baja, etc.

  • Los datos sobre la acción. Por ejemplo, escribir un nuevo correo.

  • La información extra. La dirección de correo del destinatario y el título.

Estas intenciones se pueden invocar de dos maneras:
  • Explícita: Se especifica de forma explícita en el código que componente es el encargado de gestionar el intent.

  • Implícita: Es la plataforma la que determina, mediante el proceso de resolución de intenciones, qué componente es el más apropiado para manejar el intent.

Un componente declara su capacidad de atender a un intent mediante el manifiesto, añadiendo etiquetas <intent-filter>.

2.4.Content providers

La manera de acceder o compartir información con otras aplicaciones es mediante los content providers. No existe ninguna zona común, ya que cada aplicación tiene su propio espacio de ejecución y sus propios permisos.
Estos providers os pueden permitir acceder, modificar o incluso borrar sus datos, siempre dependiendo del sistema de permisos que implementa Android. Además podréis ofrecer vuestros datos a otras aplicaciones, bien mediante la inclusión de esta información en algún provider ya existente, bien mediante la implementación de uno propio, al que tendremos que darle visibilidad.
Realmente no trabajaréis nunca con un provider concreto, sino que utilizaréis clases intermedias (por ejemplo, la clase ContentResolver). Para conseguir la instancia que os interesa, simplemente llamaréis al método de vuestra activity getContentResolver(), con lo que tendréis acceso para poder realizar las acciones de inserción, modificación, borrado y consulta de la información proporcionada por los providers. Para el caso de consulta de datos, también podéis utilizar el método managedQuery, que es el equivalente al método del ContentResolver.query.
Los datos que vais a intercambiar estarán en una única tabla, independientemente de cuál sea su representación interna. Cada columna tendrá un nombre y un tipo conocidos para poder tratar con los datos (el nombre de la columna). Cada fila de la tabla tendrá un identificador único, cuyo nombre de columna será _ID. Además, existen unas URI que os servirán para identificar cada uno de los recursos o conjuntos de recursos del content provider. Estas URI tendrán la siguiente forma:
m1308_m5_005.gif
donde:
  • A es la parte fija para identificar que se trata de un provider.

  • B es el nombre de la clase provider. Es necesario que se declare en el manifiesto.

  • C es el path del content provider, que puede ser nulo (si solo se provee información de un tipo) o tan complejo como se desee si hay varios tipos (por ejemplo, trains/bcn, trains/mdm, etc.).

  • D identifica una fila de los datos de manera única.

Para poder hacer una consulta de datos, tanto el método managedQuery() como el query() reciben los siguientes parámetros:
  • La URI que hemos visto antes: Si la última parte (D) está presente, se consultará únicamente una fila.

  • El nombre de las columnas que queremos conseguir: Si este parámetro es nulo, significa que queremos todos los datos.

  • Un filtro al estilo SQL: Sería todo lo que puede venir en la sentencia WHERE, pero sin la palabra WHERE en concreto. Si es nulo se entregarán todas las filas.

  • Una serie de argumentos de selección: Al igual que en otros lenguajes de consulta SQL, dentro de vuestros filtros podéis añadir caracteres interrogantes (?), que solo serán conocidos en el tiempo de ejecución. Aquí pondréis los valores correspondientes a esos interrogantes (en caso de existir).

  • Un criterio de ordenación: Al igual que en SQL, podéis definir el orden ascendente o descendente.

Para modificar los datos, siempre tendréis que usar los métodos del ContentResolver. Así podréis pasarle una URI (general, si es inserción o modificación masiva, concreta de una fila si se trata de actualizaciones o borrado). Además, trabajaréis con objetos ContentValues para pasar los datos que queréis modificar.

2.5.Manifiesto

El manifiesto de Android es un fichero XML que contiene información sobre vuestra aplicación. Este fichero se encuentra en la raíz de vuestro proyecto Android, y es imprescindible el sistema operativo ejecute vuestra aplicación.
Sirve para declarar información sobre nuestra aplicación que el sistema debe conocer de antemano:
  • Permisos necesarios para poder funcionar, como acceso a la cámara.

  • El nivel de la API de Android necesario para trabajar.

  • Las características hardware y software necesarias para trabajar (como, por ejemplo, tener cámara o no).

  • Las API que necesita acceder, además de las que están incorporadas en la Android Framework API. Por ejemplo, la librería de Google Maps.

  • Los componentes que forman nuestra aplicación.

2.5.1.Definición de componentes
Una parte importante e imprescindible en cada uno de los manifiestos es la definición de los componentes que forman la aplicación (están dentro del elemento XML <application>). Estos componentes pueden ser:
  • <activity>, que corresponde a una actividad.

  • <service>, para definir un servicio en segundo plano.

  • <receiver>, para definir un receptor de eventos.

  • <provider>, para definir un proveedor de contenidos.

En cualquiera de los casos anteriores se debe definir el nombre (android:name) que define el nombre de la clase totalmente cualificada.
Esta es, prácticamente, la única manera de definir un componente de nuestra aplicación y, por tanto, de hacer que sea utilizable en el ciclo de vida. Existe un caso en que no es necesario hacerlo así, que es en la creación dinámica de receptores de eventos, donde simplemente se crean objetos BroadcastReceiver y se registran con el método registerReceiver().
Como habéis visto anteriormente con los intents, es posible invocar componentes de forma explícita (excepto los proveedores de contenidos) utilizando una instancia creada de la clase, o bien de forma implícita mediante el manifiesto. Esto se hace con los elementos <intent-filter> del manifiesto, donde se define lo siguiente:
  • La acción (o acciones) a la que está asociado el componente. Este campo es obligatorio y define la estructura del resto del filtro. Aquí se define la acción que se desea (por ejemplo, ACTION_VIEW, ACTION_EDIT, ACTION_MAIN, etc.).

  • La categoría. Sirve para definir información adicional sobre la acción a ejecutar.

  • El tipo. Define el tipo de los datos del intent.

  • Y algunos elementos más, que no son obligatorios.

En el caso de las activities, un filtro muy normal es el de lanzar la aplicación. Por ejemplo, podemos tener el siguiente código para definir que nuestra aplicación se pueda ejecutar mediante el launcher:
2.5.2.Definición de requisitos
Una función importante que hace el manifiesto de Android es definir los requisitos mínimos de hardware y software. Esto sirve para filtrar las aplicaciones que se muestran en las tiendas de aplicaciones, de manera que solo se muestran aquellas que están disponibles para el dispositivo actual. Si intentáis instalar las aplicaciones en un dispositivo que no cumpla con alguno de estos requisitos, no se os permitirá.
Estos requisitos se definen en algunos elementos del manifiesto Android, la mayoría del estilo <uses-*>. Algunos de los más importantes son los siguientes:
  • Tipos de pantallas, que se definen en el elemento <supports-screens> y especifican aspectos como el tamaño de la pantalla (con opciones como small, normal, large y extra large) o la densidad de píxeles (con las opciones de low density, medium density, high density y extra high density).

  • Configuraciones de elementos de entrada, definidas en el elemento <uses-configuration>. Si vuestra aplicación requiere algún elemento especial (como los teclados, el trackball, un elemento de navegación direccional, etc.), lo debe especificar en esta sección.

  • Características del dispositivo, definido en <uses-features>, determina si se necesita algún tipo de comunicación específica o algún sensor, o si se requiere cámara.

  • Nivel de la API, definido en el elemento <uses-sdk>. Puede definir un mínimo y un máximo de las versiones del SDK soportadas.

  • Permisos, definido en <permission>. Sirven para limitar el acceso a las partes sensibles del sistema, como android.permission.READ_OWNER_DATA. Estos permisos se deben definir para que la aplicación pueda acceder a esas partes sensibles. También se pueden definir, en el mismo manifiesto, nuevos permisos.

  • Librerías externas, definido en <uses-library>. Tendremos un elemento por cada librería externa.

No debéis asumir en vuestras aplicaciones nada más que las API estándares de Android. Cualquier otra cosa deberá ser mencionada en el manifiesto para asegurar su funcionamiento.

2.6.Recursos

Los recursos en Android son aquellos ficheros que pertenecen al proyecto. Pueden ser multimedia o estáticos. Según su organización en directorios y la información de contexto de la aplicación, se utilizarán para un tipo de dispositivo u otro. Dentro de los ficheros hay muchos ficheros XML que sirven para definir layouts, menús, cadenas de texto, estilos, etc.
Estos recursos constituyen una parte importante de la plataforma, ya que se usan en varias partes de la plataforma para objetivos distintos, pero tienen el mismo funcionamiento. Por tanto, si sabemos cómo funcionan para un caso, sabremos cómo funcionarán para el resto, ya que el comportamiento será idéntico.
El principal objetivo de estos recursos es ahorrarle al desarrollador su gestión y delegar la elección de qué fichero utilizar a la plataforma Android. Esta es una manera de atacar la fragmentación en Android.
Para que estos recursos puedan ser interpretados por Android, deben estar organizados de una manera especial, siempre dentro del directorio res de la raíz de nuestro proyecto. A partir de aquí, tenemos varios subdirectorios.
Vamos a ver alguno de ellos:
  • Drawable: Son, básicamente, ficheros de imágenes o animaciones en XML.

  • Layout: Son ficheros que definen el diseño o distribución de los elementos en la pantalla.

  • Values: Son valores de cadenas de caracteres, enteros, colores, etc. que, por ejemplo, son candidatos a ser internacionalizados.

  • Otros pueden ser anim (para ficheros XML de animaciones), raw (para ficheros arbitrario) o menu (para ficheros XML que definen un menú).

Para que estos recursos puedan ser utilizados desde el código Java, además de los usos implícitos (como algunos layouts), la plataforma los transforma automáticamente a un fichero llamado R.java. Esta clase Java se regenera en cada cambio de los ficheros de recursos, de manera que todas las propiedades son identificadas de forma unívoca por atributos de la clase R de Java (por ejemplo, R.layout.main).
2.6.1.Recursos alternativos
Como habéis visto, con los recursos se pretende aislar al desarrollador de la elección del recurso adecuado. Con estos recursos definidos fuera del código, se pretende diferenciar textos en diferentes idiomas o diferentes densidades de pantalla.
Los recursos alternativos al recurso por defecto se definen con nombres de directorios alternativos, que se forman con la siguiente fórmula:
<resources_name>(_<config_qualifier>)+
donde resources_name corresponde al tipo de recurso, que puede ser cualquiera de los vistos anteriormente, y config_qualifier sirve para determinar una configuración diferente. Se puede definir más de un config_qualifier (debéis usar, para separarlos, el guión bajo)
Android soporta varios calificadores de configuración. A continuación os mostramos algunas de las opciones más interesantes:
  • Operador y nación: Sirve para identificar el operador que nos da la cobertura. Se puede identificar solo al código de nación, o nación y operador. Por ejemplo, mcc310 o mcc310-mnc004.

  • Idioma y región: Lo idiomas con dos posibles componentes separados por un guión. Primero se define el idioma (según ISO639-1) y después se define la región (precedido de la letra r y, después, del código del ISO3166-1-alpha-2). Por ejemplo, fr-rFR, fr-rCA.

  • Tamaño de la pantalla: Hay cuatro tipos, small, normal, large y xlarge.

  • Orientación de la pantalla: Define la orientación actual. Existen dos opciones:

    • port, para orientación de retrato o vertical

    • land, para orientación de paisaje u horizontal

  • Modo noche: Indica si es de día o de noche. Es útil para colores, por ejemplo. Tenemos dos opciones: night y notnight.

  • Densidad de la pantalla (dpi): Define varias opciones en número de píxeles posibles según la densidad de la pantalla. Por ejemplo:

    • ldpi: 120 dpi

    • hpdi: 240 dpi

    • xhdpi: 320 dpi

  • Modo de entrada de texto primario: Indica el tipo de teclado del que se dispone. Así, podemos tener lo siguiente:

    • nokeys: No se dispone de teclado físico.

    • qwery: Se dispone de un teclado completo.

    • 12key: El dispositivo dispone de un teclado de doce teclas.

El orden de los calificadores es importante. Es el que aparece en lista anterior. Podéis verlo en detalle en la referencia oficial de Android.
Los nombres no son sensibles a las mayúsculas y minúsculas, y no se pueden repetir varios valores para un mismo cualificado.
Cada vez que se pide un nuevo recurso en tiempo de ejecución y mediante, por ejemplo, la clase R, Android realiza la búsqueda con los valores de las configuraciones actuales y las opciones disponibles en el directorio res.
Para que Android pueda escoger el recurso adecuado, utiliza un algoritmo de eliminación de opciones disponibles mediante el cual toma cada una de las configuraciones actuales y elimina las que contradicen la configuración hasta que solo quede una opción.
Para poder evitar problemas de recursos no encontrados, siempre es una buena práctica darle un valor al recurso en la carpeta y fichero por defecto, que es donde mirará Android en el caso de que no encuentre el recurso.

3.Interfaz gráfica

Una de las partes más importantes de cualquier aplicación es la interfaz gráfica con la que el usuario debe trabajar, también conocida como interfaz de usuario. Android, además, conociendo la situación de fragmentación de su interfaz, opta por una serie de soluciones para conseguir aplicaciones que se puedan mantener y adaptar de la manera más fácil posible.
Para ello, Android proporciona varias maneras de definir nuestra interfaz:
  • Mediante el fichero layout.xml.

  • Mediante la programación de los componentes visuales, como se hace en la mayoría de las aplicaciones de sobremesa.

  • Mediante otras técnicas, que suelen ser la combinaciones de las anteriores (como, por ejemplo, el uso de LayoutInflater).

Independientemente de como se construya la interfaz gráfica, esta misma se compone de los mismos elementos, que son básicamente o View o ViewGroup, o cualquier clase que herede de estas.
Como muchas otras interfaces de usuario, Android tiene un modelo basado en el patrón de diseño observador y, por tanto, trabaja con events y listeners, lo que hace mucho más sencilla su gestión y codificación.
Dentro del ecosistema de desarrollo, siempre suelen aparecer facilidades para desarrollar trabajos laboriosos, y este es uno de esos casos. Veréis también cómo hay herramientas para realizar el trabajo de diseñar la interfaz gráfica de manera más sencilla y con menor probabilidad de errores.

3.1.Elementos de la interfaz gráfica

Podemos distinguir dos elementos de la interfaz gráfica: los View y los ViewGroup. Los primeros corresponden a todos los elementos gráficos (como botones, cajas de texto, elementos de selección, elementos para dibujar, etc.), y los segundos son los que sirven para agrupar a los primeros. Por tanto, un ViewGroup puede contener otros ViewGroups o más Views.
Esta manera de definir las interfaces hace muy fácil su reutilización, así como tener componentes autónomos.
Ejemplo de posible herencia de Views y ViewGroups
3.1.1.ViewGroup
Los ViewGroup son contenedores para los que Android proporciona una serie de subclases, que podéis usar para construir vuestra interfaz. Entre ellas destacamos:
  • FrameLayout: Es el tipo más simple, con un espacio en blanco en el centro (que se puede rellenar con un objeto).

  • LinearLayout: Dispone a todos sus hijos en una sola dirección, horizontal o vertical, uno detrás de otro.

  • ListView: Muestra a todos los hijos en una columna vertical con barra de desplazamiento.

  • TableLayout: Muestra a sus hijos de manera tabular, por columnas o filas.

  • TabLayout: Sirve para dividir nuestra interfaz con pestañas, de manera que podamos tener, en una misma activity, vistas distintas organizadas por pestañas.

  • RelativeLayout: Muestra los elementos de manera relativa a otros elementos o al contenedor. Es uno de los contenedores más utilizados, debido a su versatilidad a la hora de añadir nuevos elementos y a su capacidad para adaptarse a cambios de la interfaz (por nuevos datos, por ejemplo).

  • AbsoluteLayout: Se definen los elementos en función de sus sus coordenadas x e y correspondientes a la esquina superior izquierda.

Es recomendable que intentéis usar contenedores relativos, en lugar de absolutos, para que os adaptéis mejor a todo tipo de pantallas y cambios.
En el caso de que ninguna de las subclases anteriores os interese, siempre podéis realizar vuestra propia subclase de ViewGroup o extender alguna ya existente.
3.1.2.View
Los View son los elementos que, finalmente, serán objetos visuales. Los objetos normales son conocidos como widgets. Aquí podemos ver los elementos de un formulario, como el botón, el campo de texto o elementos más sofisticados como, por ejemplo, un selector de fecha o de hora, o un elemento para votar (RatingBar).
También hay otros elementos más potentes, como los que exponemos a continuación:
  • WebView: Es un elemento visual que incluye el resultado de visualizar un sitio web. Podéis habilitar o inhabilitar el uso de Javascript para este elemento según os convenga.

  • Gallery: Sirve para mostrar elementos en una galería horizontal. Se selecciona un elemento central, y el siguiente y el anterior se suelen poder ver. Es, en realidad, un contenedor de elementos, pero se suele usar dentro de otros contenedores.

  • Autocomplete: Es una caja de texto, donde se le hacen sugerencias de texto al usuario mientras escribe.

  • Google Map View: Sirve para visualizar elementos objetos utilizando como contenedor un mapa de Google Maps.

Como ocurre con los contenedores, si no es suficiente con estos elementos, podéis realizar vuestras propias adaptaciones u objetos visuales totalmente personalizados.
3.1.3.Fragments
Los fragmentos (fragments, en inglés) representan un comportamiento de la interfaz gráfica (o solo una porción del mismo) incluido en una activity.
Los fragmentos aparecen en Android a partir de la versión 3.0, principalmente para soportar diseños flexibles y dinámicos en pantallas grandes (como, por ejemplo, las de los tablets). Se usan para evitar, de manera más sencilla, la fragmentación.
Siempre han de estar asociados a una activity, pero los fragments pueden estar definidos en un fichero XML diferente y tener un comportamiento específico, de manera que su reutilización puede ser muy sencilla. Es muy normal incluir varios fragments en la misma activity en pantallas grandes, y, en cambio, dividirlos en dos activities en pantallas más pequeñas.
Ejemplo de fragmentos
En la siguiente figura podéis ver un ejemplo de dos fragments divididos de diferente manera en función del tamaño de pantalla.
Fuente: http://developer.android.com/
El ciclo de vida de un fragment está íntimamente ligado al de la activity en la que está incluido, pero se pueden definir acciones diferentes para el fragment en los events del ciclo de vida, de manera que su funcionamiento sea más autónomo.
Una funcionalidad interesante de los fragments es la de realizar acciones a los fragments desde nuestra activity. Estas acciones pueden ser guardadas en la pila de activities, de manera que se pueda navegar hacia atrás en las acciones realizadas. Estas acciones se guardan como parte de la clase FragmentTransaction. A esta clase se le deben realizar las llamadas correspondientes a los métodos add, remove o replace para conseguir los cambios deseados. Para aplicar la transacción se debe llamar al método commit, pero si queréis que esta acción pueda ser desecha mediante la pila de activities, se debe llamar al método addToBackStack.
3.1.4.Otros elementos de la interfaz gráfica
Además de los elementos genéricos de la interfaz, existen algunos elementos o métodos de programación que se van añadiendo a Android para facilitar el desarrollo.
Menús
Los menús sirven para permitir al usuario realizar acciones especiales en función de a qué están asociados, si a una activity o a una view concreta. Pueden ser de tres tipos:
  • Menú de opciones: Aparece cuando se pulsa el botón menú desde una activity.

  • Menú contextual: Aparece después de pulsar de manera prolongada una view.

  • Submenú: Aparece en caso necesario, cuando se pulsa un elemento de otro menú.

Estos menús. como el resto de elemento gráficos. pueden ser definidos mediante los recursos XML o bien mediante programación. Además, tienen events para gestionar sus acciones.
Notificaciones y diálogos
También es importante tratar el tema de las notificaciones y diálogos que se pueden mostrar al usuario. En lo que respecta a los diálogos, podemos generarlos mediante la clase toast, que consiste en simples mensajes emergentes con textos únicamente informativos, o bien mediante la clase dialog y sus subclases.
En cuanto a los mensajes informativos mediante toast, básicamente se generan llamando a makeText e informando del contexto visual, para poder mostrar el mensaje donde corresponda, con el texto y la duración asignada.
En cuanto a los diálogos, vamos a ver algunas subclases destacadas:
  • AlertDialog: Sirve para mostrar información. Le damos de una a tres opciones al usuario y una lista de elementos entre los que elegir (con checkboxes o radiobuttons).

  • ProgressDialog: Muestra un dialogo que informa que la aplicación está trabajando, y puede determinar su evolución.

  • DatePickerDialog/TimePickerDialog: Sirve para escoger una fecha.

Algunos ejemplos de diálogos modales
Estos diálogos toman el foco de la aplicación y, hasta que no finalice la acción o se ignore el diálogo, no permiten continuar.
Las notificaciones, en cambio, son informaciones que no tienen que ser atendidas inmediatamente. Normalmente son informaciones generadas por servicios, que informan de events (como, por ejemplo, la llegada de un correo electrónico). Estas notificaciones se quedan en la barra superior de Android (o en la barra de estado). Para crear estas notificaciones, debemos utilizar las clases Notification y NotificationManager.
Estilos y temas
En Android se pueden definir estilos. Estas propiedades las pueden heredar los elementos hijos del objeto visual donde lo hemos definido.
Los estilos son una colección de propiedades que definen el formato y la visualización de una ventana u objeto view. Estas propiedades son, por ejemplo, el tamaño, el color de fondo, el espacio exterior, el espacio interior, etc. Todos los estilos están definidos en un fichero XML, que está separado del que sirve para definir el layout de nuestras actividades.
Estos estilos se podrían definir de manera explícita dentro de las propias definiciones de la interfaz (ficheros XML del directorio layout), pero separarlos mejora la separación de conceptos y la reutilización. Es algo parecido a los estilos CSS (4) (que sirven para definir el estilo de un sitio web).
Estos estilos se definen con la propiedad style de un elemento view. Se pueden definir en el fichero XML, dentro de la definición del objeto view, o también en los constructores de estos objetos view.
Un estilo puede heredar de otro. Si se trata de un estilo que habéis definido vosotros, simplemente debéis dar el nombre de vuestro estilo prefijado por el estilo que queréis heredar.
En el caso de heredar un estilo nativo de Android, debéis definir el atributo del fichero XML parent, por ejemplo, parent="@android:style/TextAppearance".
Un tema es un estilo aplicado a toda una actividad o aplicación, en lugar de a una vista en concreto. Por ejemplo, podéis definir un estilo de tamaño de letra para una activity, y todos los textos dentro de esa activity tendrán ese tamaño de letra.
La ventaja de los temas es que permiten ser cambiados fácilmente y cambiar la visualización de vuestra aplicación por completo. Estos temas se aplican mediante el atributo android:theme de una activity.
Objetos 3D y animaciones
Para darle mayor potencial a vuestra aplicación, podeis realizar animaciones y objetos con texturas de tres dimensiones (3D).
En el caso de 3D, podéis basaros en la librería OpenGL, en concreto, en la librería OpenGL ES API, que permite realizar renderizados con alto rendimiento de tres dimensiones. Para ello, se basa en librerías parecidas a las correspondientes de J2ME, y simplemente debéis realizar vuestro objeto view correspondiente e implementar el método onDraw para escribir el objeto 3D que deseéis.
También podéis tener objetos 3D mediante el sistema Renderscript, que maximiza el rendimiento, pues se trata de una librería de bajo nivel que ejecuta código nativo (en concreto, código C). Este sistema evita, además, que os tengáis que preocupar de las diferencias a bajo de nivel de los dispositivos. Eso lo consigue mediante la compilación en el momento (just in time) desde el bytecode hasta el código máquina. Este tipo de codificación maximiza el rendimiento, pero complica el desarrollo y la depuración del código.
Las animaciones sirven para definir las transiciones de nuestros objetos visuales. Estas animaciones pueden ser definidas dentro de nuestros ficheros XML, en el directorio anim o mediante el propio código.
Otras formas de definir la interfaz
Como habéis visto, una manera típica de definir vuestros elementos visuales es mediante los ficheros XML de recursos correspondientes al contenedor. Estos ficheros permiten "setear" la mayoría de los atributos, así como el acceso desde el propio código. Es bastante habitual tener la definición inicial de la interfaz gráfica en un fichero XML y después modificarla mediante el código (accediendo a los elementos mediante la clase R).
Sin embargo, no todos los elementos gráficos que existen en las definiciones de XML se acaban renderizando; solo lo hacen aquellos que están en la línea de herencia de algún elemento renderizado. Por eso, en vuestra activity se debe llamar al método setContentView para indicar cuál es el contenedor de vuestra activity. Esto permite, además, definir elementos como resources, pero no renderizarlos inmediatamente, aunque sí se pueden renderizar a posteriori. Este proceso se conoce como inflate. El proceso utiliza el objeto XML procesado y genera la clase visual correspondiente.

3.2.Events

Los events son muy parecidos a otros entornos de desarrollo de interfaz gráfica basada en events. Estos events reaccionan a cualquier acción del usuario, ya sea pulsar una tecla en el teclado físico o virtual, pulsar un botón físico desde el botón menú hasta el botón de la cámara, tocar un punto en la pantalla o realizar acciones más sofisticadas (acercar o alejar, mover objetos, etc.).
Estos events siempre se realizan, y el hilo de la interfaz los interpreta. En el caso de que queráis realizar una acción ante uno de estos events, deberéis registrar un listener o escuchador para este event en el objeto visual que os interese. Según el tipo de event provocado, dicho event os traerá más información, que llegará en forma de parámetros a listener.
Ejemplo de listeners
A continuación os mostramos el uso típico de los listeners para escuchar la acción de hacer clic en un botón.
public class HelloWorldActivity extends Activity {
   @Override
   public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
   Button btn = (Button) findViewById(R.id.button);
   btn.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        Toast.makeText(HelloWorldActivity.this,
        "Click", Toast.LENGTH_SHORT).show();
      }
   });
   
  }
}
Vuestro código no siempre será el único interesado en escuchar estos events y, por tanto, debéis realizar un código seguro para evitar problemas en otros componentes. Unos pocos events son de una sola consumición; es decir, que no se pueden tener varios listeners, sino que el primero que lo recibe hace que el resto no lo vea.
Ahora veréis unos casos de events más sofisticados y muy particulares de las plataformas de dispositivos móviles: events táctiles y events de gestos predefinidos.
En el caso de los events táctiles o touch events, existen dos grupos: los events de una única acción y los events multiacción o multi touch events.
De los events de una única acción podemos tener:
  • onClick: Es un clic básico sobre un objeto visual.

  • onLongClick: Es un event de clic sin movimiento de este, pero con una duración más elevada.

  • OnDown: Ocurre cuando un usuario pulsa la pantalla; es decir, en el momento de pulsar. Sería el equivalente al keyDown de una tecla o botón.

  • onScroll: Se trata del event de hacer scroll, tanto vertical como horizontal.

  • onSingleTapUp: Sucede cuando se libera la pantalla pulsada. Por ejemplo, si se realiza con un dedo, tiene lugar cuando se deja de tocar la pantalla (después de la acción táctil).

  • onFling: Es una sucesión de events (tocar la pantalla, mover, dejar de tocar la pantalla). Suele utilizarse para desplazar objetos visuales.

Para el caso de los multi-touch events, tenemos diferentes acciones para el event onTouchEvent (5) , que se pueden dividir en:
  • ACTION_DOWN: Pulsación de la primera acción de tocar la pantalla.

  • ACTION_POINTER_DOWN: Pulsación de la segunda acción de tocar la pantalla.

  • ACTION_MOVE: Acción de movimiento mientras se tienen los dos puntos pulsados.

  • ACTION_UP: Acción de liberar la pantalla correspondiente a la primera pulsación.

  • ACTION_POINTER_UP: Acción de liberar la pantalla correspondiente a la segunda pulsación.

Estas acciones pueden ser usadas para realizar un zoom, por ejemplo.
Además de estas acciones complejas y personalizadas, Android ofrece unas librerías con las que gestionar los gestos predefinidos. Es decir, estas librerías son útiles para asociar acciones a gestos definidos que tengan sentido para vuestra aplicación. Esto se usa mucho para tener atajos a acciones habituales (como, por ejemplo, en navegadores para acciones como abrir una nueva ventana o ir hacia atrás).
Para definir este tipo de acciones, Android tiene una herramienta que ayuda a construirlos, el Gestoure Builder, así como un event para escuchar cuándo se producen dichas acciones por el usuario.
La herramienta está como un programa de ejemplo de cada SDK (está en /samples/android-XX/GestoureBuilder/). Su función es la de registrar los gestoures y las traducciones que queréis que tengan estos gestos. Los gestos se van guardando en un directorio concreto de vuestro emulador para que podáis utilizarlos a posteriori.
Para utilizar los gestos creados, debéis colocarlos en vuestro proyecto, accesible desde vuestros recursos para ser referenciado desde el código. Para que vuestro código sea capaz de escuchar estos gestos, debéis comunicárselo a vuestra activity añadiendo una zona con una capa del tipo GestoureOverlayView, que será donde escucharéis este tipo de gestos. En el mismo código debéis añadir un listener, el cual estará escuchando sobre la capa antes definida y sobre el tipo de gestos que hemos construidos con el Gestoure Builder.
Ejemplo de preparación de los gestos
En este trozo de código podéis ver las partes más interesantes de la preparación de los gestos.
public class ListenGestouresActivity extends Activity implements 
OnGesturePerformedListener {
  private GestureLibrary mLibrary;

  ...
  public void onCreate(Bundle savedInstanceState) {
    ...
          mLibrary = GestureLibraries.fromRawResource(this,
          R.raw.numbers);
          
          if (!mLibrary.load()) {
          finish();
          }
          GestureOverlayView gestures =(GestureOverlayView)
          findViewById(R.id.gestures);
          gestures.addOnGesturePerformedListener(this);
          ...
  }
}
public void onGesturePerformed(GestureOverlayView overlay,
    Gesture gesture) {
    ArrayList<Prediction> predictions = mLibrary.recognize(gesture);
    ...
    Prediction p = predictions.get(i);
    String text = "got " + p.name + " with a precision of " +
    p.score;
    ...
}
Y su uso para predecir qué gesto se ha de realizar implementando el event gestourePerformed. Como podéis ver, os da una lista de posibles events, que llama predicciones. Esto os permite elegir en función de la precisión que queráis tener.
3.2.1.AsyncTask y loaders
Siempre que se realiza una acción que pueda bloquear la interfaz, se debe realizar en un hilo de ejecución diferente. Además, es preocupante en el caso de Androides, pues puede aparecer un diálogo modal que informe que la aplicación no está respondiendo, (si tarda más de cinco segundos en hacerlo). Esto se puede hacer como siempre en Java, utilizando las clases propias. Podría ser algo así:
Este código tiene un problema añadido, y es que se está manipulando la interfaz desde fuera del hilo de la interfaz (UI thread), que no está preparada para ser modificada por múltiples hilos, con los problemas que ello puede conllevar.
Para evitar este problema, Android ofrece varias formas de modificar la UI (6) , como Activity.runOnUiThread(Runnable), View.post(Runnable), View.postDelay(Runnable, long) y Handler. Sin embargo, estas clases hacen que el código sea poco elegante y difícil de mantener.
También se podría hacer utilizando una clase específicamente creada para las actualizaciones asíncronas de la interfaz llamada AsyncTask. En este caso, quedaría como sigue:
public void onClick(View v) {
  new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
      protected Bitmap doInBackground(String... urls) {
         return loadImageFromNetwork(urls[0]);
      }
      
      protected void onPostExecute(Bitmap result) {
         mImageView.setImageBitmap(result);
      }
}
Con esta clase se pueden hacer todas las modificaciones de la interfaz de manera segura para ella. Como vemos, la AsyncTask utiliza los generics de Java para tener un código más controlado y elegante y, además, le permite al programador añadir la lógica sobrescribiendo los siguientes métodos:
  • onPreExecute: Invocado dentro del hilo de la interfaz, justo antes de empezar la tarea. Es útil para actualizar la interfaz gráfica (por ejemplo, con una barra de progreso).

  • doInBackground(Params...): Invocado en un hilo distinto después del onPreExecute. Es donde se realiza el trabajo costoso. En esté método se pueden realizar publishProgress(Progress...) para informar a la interfaz del progreso.

  • onProgressUpdate(Progress...): Invocado en el hilo de la interfaz después de cada llamada al publishProgress(Progress...) (realizado en el paso anterior).

  • onPostExecute(Result): Se ejecuta en el hilo de ejecución de la interfaz al finalizar el trabajo.

Estas AsyncTask pueden ser canceladas en cualquier momento, lo cual supone llamar a otro método para poder cancelar correctamente nuestra AsyncTask y liberar los recursos.
Otros elementos importantes son los loaders, que sirven para cargar de manera asíncrona datos en nuestra aplicación.
Las características principales de los loaders son los siguientes:
  • Se pueden asociar a cada una de las activities o fragments.

  • Permiten recoger datos de manera asíncrona.

  • Monitorizan los recursos, de manera que, cuando hay cambios en los datos, entregan cichos datos automáticamente.

  • Después de un cambio de la configuración, se conectan automáticamente al cursor de los datos antes de dicho cambio, de manera que no es necesario volver a preguntar por dichos datos.

Es responsabilidad del desarrollador encargarse de conseguir los datos de manera correcta y mostrarla al usuario. Los loaders se encargarán de mantener los datos y la nueva información.

4.Otras partes del SDK

Android tiene muchas partes y cada una de esas partes es realmente grande, por lo que se hace difícil cubrirlo todo y, seguramente, muchas de estas partes no serán necesarias para el desarrollo de nuestra aplicación. Por eso, vamos a mostraros algunas de estas partes que son importantes, partes relacionadas con librerías que existen y que ofrecen almacenamiento de información, acceso a sensores o mejoras en el uso y en el desempeño de nuestra aplicación.

4.1.Almacenamiento de datos

Se pueden almacenar datos de diversas maneras:
  • mediante las preferencias de la aplicación

  • en ficheros en el almacenamiento interno

  • en ficheros en el almacenamiento externo

  • mediante bases de datos

  • mediante la red

Si se almacenan datos en las preferencias de la aplicación, se utiliza la clase SharedPreferences mediante los métodos de la actividad getSharedPreferences() o getPreferences(). Aquí podréis guardar pares de clave valor, donde los valores serán tipos primitivos. Estos datos serán automáticamente persistidos entre diferentes sesiones de usuario.
El almacenamiento interno y externo consiste en guardar ficheros, bien en la memoria interna del dispositivo, bien en la memoria externa, generalmente en una tarjeta de memoria. Existen métodos para cada caso, de manera que podéis abrir un fichero con el nombre concreto, leerlo, escribirlo y, finalmente, cerrarlo. También existe la posibilidad de trabajar con los ficheros de caché, cuyo propósito es mejorar la experiencia de usuario evitando realizar acciones innecesarias.
Es importante saber que hay algunos directorios en los que los ficheros guardados serán visibles para todas las aplicaciones y no se borraran aun cuando se desinstale la aplicación (por ejemplo, los directorios music, podcasts, ringtones, etc.)
En el caso del almacenamiento en base de datos, se utilizará SQLite. Las bases de datos que creéis serán accesibles por nombre desde cualquier clase de nuestra aplicación, pero no desde fuera de la misma. Os recomendamos que utilicéis la clase SQLiteOpenHelper para crear vuestras bases de datos y que trabajéis sobre ellas.
Sobre estas bases de datos podréis realizar todo tipo de sentencias SQL. También tendréis la opción de recuperar datos en un cursor y trabajar con ellos.
Finalmente, para guardar datos en la red, debéis acceder a la red y enviar la información mediante servicios "en línea".

4.2.Acceso nativo

Android Native Development Kit (Android NDK) es un conjunto de herramientas que permiten empotrar componentes que usan código nativo en las aplicaciones Android tradicionales.
Estas partes de las aplicaciones se escribirán en C y C++, y se beneficiarán del hecho de ser aplicaciones nativas para volver a aprovechar ciertas partes o conseguir un mejor rendimiento.
Estas aplicaciones son más complejas, y solo por su naturaleza no conseguirán mejoras, sino que deberéis saber exactamente qué hacer para aprovechar mejor los recursos de bajo nivel. Por ese motivo es importante que sepáis cuándo utilizarlo.
Una buena regla general es utilizar NDK solo cuando sea necesario, no sin haber examinado antes otras alternativas.
Las aplicaciones candidatas a utilizar NDK suelen tener un uso intensivo de CPU, pero no utilizan mucha memoria (por ejemplo, las aplicaciones de procesamiento de señales de radio, de simulaciones de físicas, etc.).
Hay dos maneras de añadir nuestros componentes NDK a una aplicación Android:
  • Implementando nuestra aplicación de manera tradicional, con las API del SDK de Android, y utilizando JNI para hacer llamadas a nuestros componentes NDK. Está disponible desde la versión 1.5 de Android.

  • Implementando las clases directamente nativas, utilizando la clase NativeActivity. Su definición cambia en el manifiesto, pero el ciclo de vida no. Está disponible desde la versión 2.3 de Android.

Dentro del NDK se encuentran una serie de herramientas, tales como compiladores, ensambladores, etc., para generar binarios para la arquitectura ARM en diferentes plataformas de desarrollo (como Linux, Windows o OS X).

4.3.Location based application

Location base applications o location based services (LBS) son aplicaciones o servicios basados en la posición geográfica del usuario.
Para determinar la posición geográfica de un dispositivo móvil en vuestra aplicación, podéis usar GPS, o bien la localización basada en las celdas de telefonía y las señales WiFi. A estas posibilidades se las conoce como LocationProvider. Las aplicaciones que quieren conocer la geoposición se pueden basar en una o en ambas alternativas.
El global positioning system (GPS) o sistema de posicionamiento global es un sistema que sirve para determinar la posición de un objeto, persona o vehículo en cualquier parte del mundo. Es un sistema de gran precisión, ya que su margen de error puede ser únicamente de centímetros, aunque normalmente hablamos de metros.
El GPS es más preciso, pero presenta algunos inconvenientes, precisamente donde la localización vía WiFi o las celda de telefonía presentan ventajas. Con GPS, el consumo de batería es mayor y el tiempo para conseguir la posición es mayor.
La precisión de las posiciones, así como el consumo de batería asociado, puede verse afectado por factores como el movimiento del usuario, el cambio de proveedor de localización, los cambios de la precisión de la señal, etc. Todo esto lo tiene que tener en cuenta vuestra aplicación, que tendrá que actuar en consecuencia para evitar al máximo el uso inapropiado del servicio.
La manera de conocer la localización en Android es mediante la suscripción a LocationListener, a los events relacionados con la localización. Los objetos que implementan la interfaz LocationListener deben implementar los siguientes métodos: onLocationChanged, onProviderDisabled, onProviderEnabled y onStatusChanged. Estos sirven para escuchar cambios en el estado y en la disponibilidad de los proveedores de localización que nos interesen.
Este objeto, que sirve para recibir las actualizaciones, se debe registrar en el sistema mediante el método requestLocationUpdates, donde debéis registrar el proveedor que os interesa (GPS_PROVIDER o NETWORK_PROVIDER para la localización basada en celdas y redes WiFi), así como el tiempo y la distancia entre actualizaciones. Finalmente, debéis añadir vuestro objeto para recibir dichas actualizaciones.
Un método interesante es el de poder conocer la última localización conocida: getLastKnownLocation, que evita que tengamos que esperar a los proveedores de localización y, además, nos ayuda a ahorrar batería, pero con la correspondiente pérdida de precisión.
En cuanto a todas estas localizaciones que estamos mencionando (que pertenecen a la clase location), podréis saber cuándo fueron capturadas y mediante qué proveedor. De esta manera, podréis decidir si es suficiente con esta localización o queréis una nueva.
Además de la posibilidad de interaccionar directamente con los proveedores de localización, existe la posibilidad de utilizar librerías más propietarias, como la API de Google Maps, proporcionada por Google. Esta librería proporciona un ViewGroup llamado MapView, que se muestra como los mapas propios de Google Maps y utiliza los datos de su servicio, así como su interfaz de usuario. Incluye la gestión de la posición y las capas propias de dicha aplicación. Podéis programar sobre eso para añadir nuevas capas con vuestra información, pero para poder hacerlo es imprescindible que obtengáis una clave válida.

4.4.Comunicaciones

Existen diferentes opciones en Android para realizar comunicaciones. Es posible realizar comunicaciones de red normales mediante la API de comunicación de red o controlar el estado de nuestros proveedores de red con el método Context.getSystemService(Contex.CONNECTIVITY_SERVICE). También existe la posibilidad de utilizar API para propósitos concretos. Podemos destacar NFC, Bluetooth y SIP.
Como siempre, para cada una de estas conexiones es necesario que especifiquéis en vuestro manifiesto los permisos adecuados, ya que de lo contrario vuestra aplicación no funcionará.
4.4.1.Bluetooth
En Android, programando para trabajar con Bluetooth, se puede:
  • Escanear para encontrar otros dispositivos.

  • Pedir al adaptador de Bluetooth local por dispositivos ya enlazados.

  • Establecer canales RFCOMM.

  • Conectar con otros dispositivos mediante el servicio de discovery.

  • Transferir datos a otros y desde otros dispositivos

  • Gestionar múltiples conexiones.

Para trabajar con Bluetooth y conseguir las acciones básicas (como activar Bluetooth, encontrar dispositivos ya enlazado o nuevos, y transferir datos), Android nos proporciona una serie de clases clave:
  • BluetoothAdapter: Es el principal punto de acceso en la interacción. Sirve para encontrar, por ejemplo, dispositivos ya enlazados o no, y para crear sockets para comunicaciones con otros dispositivos.

  • BluetoothDevice: Representa un dispositivo al que se puede interrogar sobre información o contra el que se pueden abrir conexiones.

  • BluetoothSocket: Es el canal de comunicaciones para intercambiar información.

  • BluetoothServerSocket: Sirve para recibir conexiones cuando nuestro dispositivo está en modo servidor.

En muchas de las interacciones de nuestra aplicación con Bluetooth, Android mostrará diálogos de información para confirmar las acciones.
4.4.2.NFC
NFC a diferencia de otras tecnologías de comunicación por radiofrecuencias, como Bluetooth o WiFi, permite realizar las conexiones entre dos dispositivos sin necesidad de descubrir estos dispositivos ni enlazarlos; las interacciones pueden iniciarse solo con una acción.
NFC sirve para que nuestro dispositivo sea capaz de interaccionar con Tags NFC. Nuestro dispositivo podrá leer la información de estos tags o, incluso, interaccionar. Estos tags tienen diferentes tecnologías y pueden ser desde muy sencillos, con información textual, hasta muy complejos, con capacidades de cálculos o encriptación. Incluso un dispositivo Android puede simular ser un tag.
Para poder trabajar con NFC, Android proporciona las siguientes clases:
  • NfcManger: Sirve para gestionar varios adaptadores físicos de nuestros dispositivo en NFC. Como normalmente solo se dispone de uno, se puede usar el método estático getDefaultAdapter.

  • NfcAdapter: Representa nuestro adaptador al dispositivo NFC. Sirve para registrar cambios de tag hacia activity, y para trabajar con mensajes NFED.

  • NfcMessage y NfcRecord: NfcMessage es un contenedor de cero o más NfcRecords. Cada NfcRecord tiene información NDEF.

  • Tag: Representa al objeto pasivo de NFC. Estos tags pueden tener diferentes tecnologías y se pueden preguntar mediante el método getTechList().

4.4.3.SIP
Session initiation protocol (SIP) es un protocolo que sirve para controlar las sesiones de comunicaciones multimedia, como por ejemplo las de llamadas de voz o de vídeo sobre IP. El protocolo se puede usar para crear, modificar y finalizar sesiones entre dos puntos (unicast) o entre múltiples puntos (multicast). En las modificaciones se puede cambiar el número de puntos implicados o los streamings.
En Android existen una serie de clases que ayudan a trabajar con este protocolo y, por tanto, facilitan su desarrollo. Esto os permitirá realizar videoconferencias en vuestras aplicaciones, así como usar mensajería instantánea.
Debéis tener en cuenta algunos requisitos y limitaciones que existen en el desarrollo de SIP para Android:
  • Solo está disponible para dispositivos 2.3 o superiores.

  • SIP funciona con una red de datos inalámbricos y, por tanto, no se puede probar en los emuladores, solo en dispositivos físicos.

  • Cada miembro de la comunicación necesita una cuenta SIP (identificada en un servidor SIP).

Hay una serie de clases clave, que son las principales encargadas de trabajar con el protocolo:
  • SipManager: Sirve para trabajar con las tareas SIP (como iniciar conexiones o dar acceso a servicios SIP).

  • SipProfile: Define un perfil SIP e incluye la información del servidor y de la cuenta.

  • SipAudioCall: Sirve para gestionar una llamada sobre IP mediante SIP.

4.4.4.Widgets
Los widgets son aplicaciones en miniatura que permiten mostrar partes de una aplicación dentro del escritorio o pantalla de inicio.
Ejemplo de widgets en la pantalla de inicio de una tableta PC y de un smartphone
Ejemplo de widgets en la pantalla de inicio de una tableta PC y de un smartphone
Se puede programar la búsqueda de actualizaciones de los widgets, que se lleva a cabo a través de un tipo especial de broadcast receiver, con la periodicidad que se crea conveniente.
Hay tres elementos básicos para la construcción de un widget:
  • AppWidgetProviderInfo. Sirve para definir, generalmente a través del Android Manifest, la información de configuración del widget. Entre esta información destaca el tamaño mínimo (alto y ancho), el periodo de actualización, el layout visual (definido de igual manera que en el caso de las Activity) y la opción de añadir una Activity sólo dedicada a configurarlo.

  • AppWidgetProvider. El encargado de actualizar el widget según los eventos que vayan llegando. Algunos de los eventos importantes que tiene que gestionar son los de actualización (onUpdate), activación (onEnabled), borrado (onDelete). El más importante es el de actualización, que normalmente se realiza desde un service para evitar bloqueos y el consiguiente mensaje de error de una aplicación que tarda mucho en ejecutarse (ANR: application not responding).

  • El layout propio, que ha sido configurado anteriormente en el primer punto. Se define de igual manera que el caso de las Activity: utilizando un fichero XML y los views tradicionales.

Podéis obtener más información sobre los widgets en la siguiente página:
4.4.5.Sincronización de datos
Android permite crear sistemas de sincronización de datos entre nuestro dispositivo y otros puntos, como pueden ser los servidores propios o servidores en la nube.
Como requisito para poder sincronizar datos, es imprescindible tener una cuenta de usuario de Android. Generalmente, se suele tener al menos la cuenta de Google, que nos permite sincronizar contactos, calendarios, etc. Además, podemos crear nuestros propios servicios de usuario a través del AccountManager y el AbstractAccountAuthenticator, lo que nos daría acceso a cuentas de otros servicios.
El proceso de sincronización puede ser lanzado de manera automática por parte del propio sistema operativo, lo cual es ideal para mantener todas las aplicaciones sincronizadas desde un punto central. Para ello, tendremos que desarrollar un service que se encargará de llamar a un adaptador (SyncAdapter), que será quien realice la lógica de la sincronización. Este service de sincronización, a través del SyncAdapter, deberá trabajar con algún ContentProvider, para leer los datos a sincronizar y guardarlos posteriormente.
Para más información, tenemos un ejemplo de implementación disponible en http://developer.Android.com/resources/samples/SampleSyncAdapter/index.html y también como parte de los ejemplos del SDK.

5.Herramientas de desarrollo de Android

Hasta ahora hemos visto la potencia de nuestras aplicaciones y hemos podido definir acceso a prácticamente todas las partes de nuestro dispositivo en nuestra aplicación, con varias maneras de realizar la misma acción (por ejemplo, mediante ficheros XML o en código). Pero muchas veces hay que tener en cuenta mucha información, y hacerlo sin ayuda es difícil.
Para ello, en este apartado os mostraremos las principales herramientas de las que disponéis. Veréis las herramientas estándar del SDK de Android (algunas de ellas en profundidad, pero no todas, ya que además de que se escapan del alcance de este apartado, se añaden constantemente nuevas herramientas).
Después veréis los entornos de desarrollo principales, con especial antención en el plugin oficial de Google para desarrollo.
Finalmente, veréis algunas herramientas externas que os permitirán conocer la potencia de vuestra plataforma.

5.1.SDK de Android

Algunas de las herramientas que vienen con el SDK (7) oficial de Android son generales y se usan en cada una de nuestras aplicaciones. En cambio, algunas son específicas para el tipo de desarrollo que deseamos hacer, o las que habíamos pensado para la aplicación.
Algunas de las más interesantes pueden ser:
  • Sqlite3: Herramientas para gestionar bases de datos mediante sentencias SQL.

  • Hprof-conv y dmtracedump: Herramientas para hacer perfilado (en inglés, profiling) de nuestra aplicación; es decir, para mejorar el rendimiento mediante la detección de posibles problemas de memoria o de CPU.

  • Layoutopt y Draw 9-patch: Herramientas para mejorar nuestra interfaz gráfica. La primera, para mejorar y analizar el rendimiento de nuestros layouts y, así, optimizar su rendimiento. La segunda, para la creación de gráficos.

  • Monkey y monkeyrunner: Herramientas para realizar tests de estrés sobre nuestra aplicación.

  • Zipalign, ProGuard: Herramientas para mejorar los ficheros correspondientes a nuestra aplicación.

  • Emulator: El emulador donde podemos probar nuestras aplicaciones.

  • Logcat: Visualizador de los logs de sistema de un dispositivo o emulador.

  • Android: Gestor de los dispositivos virtuales o AVD.

  • Adb: Herramienta para poder ver el estado de nuestro emulador.

Algunos se usan constantemente y requieren de una explicación más detallada.
Para empezar a desarrollar, lo primero que debéis hacer es crear un AVD o dispositivo virtual, que corresponde a una configuración del emulador, y definir las opciones de hardware y software que queréis que tenga dicho emulador. Si no disponéis de una herramienta más potente, como el AVD Manager, debéis hacer líneas de comandos (con el comando android se pueden listar, crear, borrar o actualizar los AVD disponibles). También lo podéis hacer desde el AVD Manager, que os permite hacer lo mismo, tal como podéis ver en las imágenes siguientes.
Vista del AVD Manager
Creación de un nuevo AVD
Además, os permite bajar nuevas versiones de las librerías del SDK, de manera que siempre podéis actualizar desde aquí, antes de la aparición de una nueva versión para desarrollo.
Una herramienta importante es el adb, que se instala en el emulador o dispositivo y permite ver información de estado de la aplicación, hacer volcados de estado para su análisis, acceder a los logs e, incluso, debugar la aplicación o tener un entorno de comandos del emulador.
Es importante que tengáis una trazabilidad de las acciones que van sucediendo. Para esto, podéis utilizar en vuestro código la clase android.util.Log con los métodos para escribir sobre el log según la verbosidad que se desee. Para ver esta información, podéis acceder a ella con el subcomando logcat del comando adb.
Sin duda, una de las herramientas esenciales es el emulador de Android, accesible con el comando android. Con este emulador podéis emular muchas acciones de usuario, muchas de ellas directamente con combinaciones de teclas (desde acceder al menú o abrir la cámara, hasta cambiar la orientación de la pantalla). También hay algunas otras que se pueden hacer desde la consola del emulador, donde podemos cambiar la velocidad de la red, simular SMS, cambiar la posición geográfica, etc.
La mayoría de estas herramientas son de entorno de comandos y requieren una serie de parámetros específicos para trabajar. Además, cambian de contexto constantemente para poder realizar trabajos habituales. Para mejorar esto, muchas de estas herramientas se agrupan en los plugins o extensiones de desarrollo para Android, de los cuales cabe destacar el que tiene soporte oficial de Google: ADT plugin for Eclipse.

5.2.Plugin ADT para Eclipse

El plugin de Eclipse incorpora la gran mayoría de las herramientas previamente vistas y de manera transparente para el desarrollador. Así, se puede realizar un debugging de una aplicación en un dispositivo o emulador, o ver la información de perfilado de la memoria o el sistema de ficheros actual y trabajar con él. Todo esto está integrado dentro del IDE Eclipse.
Otra utilidad que nos ofrece la interfaz de desarrollo de android es la gestión integrada de los ficheros XML mediante editores gráficos. Uno de los más interesantes es la edición gráfica de los las interfaces gráficas, como podéis ver en la figura siguiente.
Edición de interfaz gráfica desde Eclipse
Esta edición lleva incorporada, además, la gestión de las diferentes versiones de los recursos alternativos, que dependen de cada característica, lo que que facilita mucho el desarrollo.

5.3.Depurando la aplicación en dispositivo real

A pesar de que nuestro emulador es una herramienta potente, hay aspectos que no se pueden probar del todo, como los events de multi-touch o algunos sensores, o conexiones como Bluetooth, o sensores como el acelerómetro o similar. Existen algunas herramientas en la comunidad para mejorar esta falta, pero la mayor seguridad la proporcionan, sin duda, las pruebas sobre el dispositivo real.
Además, siempre es deseable que realicéis pruebas lo más reales posibles con el dispositivo objetivo para poder apreciar también la responsabilidad de vuestra aplicación.
Para depurar vuestra aplicación sobre un dispositivo real, debéis hacer los siguiente:
  • Marcar vuestra aplicación como debuggable. Para ello debemos fijar el atributo Android:debuggable a valor true.

  • Permitir que se conecte el debugger en vuestro dispositivo En vuestro dispositivo, id a la pantalla principal, pulsad MENU, después Applications > Development > USB debugging.

  • Hacer que vuestro sistema operativo reconozca el dispositivo. Dependerá del sistema operativo que estéis usando para desarrollar.

Finalmente, podéis lanzar la aplicación o depurar como lo haríamos normalmente (por ejemplo, desde Eclipse), y dispondréis de la misma información que si tuvierais un emulador.

5.4.Herramientas de testeo

Android, al igual que el resto de desarrollos móviles, requiere de muchas pruebas para conseguir un software de calidad (pruebas con herramientas de testeo y pruebas en dispositivos reales).
Hay algunas herramientas que están integradas en el propio SDK, basadas, sobre todo, en JUnit, que es una librería típica de testeo unitario para Java.
5.4.1.Herramientas de testeo incluidas en el SDK
Las herramientas incluidas para testeo en el SDK de Android se pueden dividir en las siguientes:
  • Tests unitarios normales, basados en las librerías de JUnit, pero sin utilizar ni instalar objetos especiales de Android. Sirven para probar la lógica de aplicación, principalmente.

  • Tests unitarios que utilicen la infraestructura de Android.

  • Tests unitarios de estrés.

Los primeros son ejecuciones normales de test unitarios, que se basan en probar que la lógica hace lo que debe hacer y en comprobarlo con asserts tradicionales de JUnit. Es decir, comprueban que el resultado de la ejecución es el esperado o está dentro de los rangos esperados. En caso de ser cierto, continúan hasta acabar y, por tanto, el test es válido. En caso de no serlo, el test es fallido.
El segundo caso tiene una especificidad más cercana a Android, pues permite interceptar o provocar los events del ciclo de vida de una activity, por lo que se pueden probar cosas para una aplicación y su estado se recupera correctamente. Esto lo hace gracias a la API instrumentation.
Si realizáis los tests con la infraestructura de Android, se os proporcionan muchas clases base para vuestros tests, como ActivityTestCase, ServiceTestCase, ApplicationTestCase, etc. Además de ellos, hay muchos objetos Mock que permiten emular el comportamiento estándar de vuestra aplicación para que sea más fácil probar la aplicación de manera aislada. La clase que se encarga de ejecutar los test se llama InstrumentationTestRunner, que os permite interaccionar de una manera más directa sobre las clases de vuestra aplicación.
Finalmente, existe una herramienta que sirve para probar la aplicación de manera automática y pseudoaleatoria. Esta herramienta se llama Monkey (tiene la metáfora de un mono tocando el dispositivo), y lanza events de clic, events táctiles o gestos, además de events de sistema.
A Monkey se le pueden definir las siguientes opciones:
  • número de events a lanzar

  • limitaciones (como solo lanzar events hacia un paquete de código)

  • tipo y frecuencia de los events

  • opciones de debugging

A partir de este momento, podéis lanzar los test. La herramienta os avisará en los siguientes casos:
  • Si queréis testear solo un paquete, y se intenta ejecutar alguna parte fuera de este paquete, la aplicación bloquea esta ejecución, con las posibles consecuencias.

  • Si la aplicación tiene un problema o una excepción no controlada, la herramienta parará e informará sobre el error.

  • Si la aplicación provoca que aparezca un error del tipo "Application not responding", la herramienta parará e informará sobre el error.

Con esta herramienta podéis comprobar si vuestra aplicación se comporta correctamente ante situaciones de estrés.
5.4.2.Herramientas externas de testeo
Además de estas herramientas, existen algunas herramientas externas que ayudan a realizar tests más específicos, por ejemplo:
  • Roboelectric: Tests unitarios para cada activity de Android.

  • Robotium: Tests de aceptación. Es decir, se lanza la aplicación y vuestro test va realizando acciones como si fuera un usuario normal. Si este test funciona, significa que la parte probada de vuestra aplicación está aceptada y funcionando.

Roboelectric permite ejecutar tests unitarios, como en el caso de los tests de activities lanzados desde las herramientas de Android, pero sin necesidad de lanzar un emulador. Esto hace que los tests sean mucho más rápidos.
En cambio, Robotium sirve para hacer pruebas automatizadas del tipo de caja negra; es decir, tests en los que no sabemos qué hay dentro de la aplicación, pero que podemos probar como si fuéramos usuarios, de modo que recibiremos respuestas como tales.
Lo que intentan este tipo de tests es lanzar events como si fuéramos un usuario, sin necesidad de conocer los elementos (Spinners, Buttons, TextBoxes, etc.) que existen en el código de las activities. Por tanto, se basan mucho en lo que el usuario ve.
Ejemplo
En este ejemplo, se persigue realizar cambios navegando por los menús. Como veis, no especifica el tipo de objeto sobre el que hacemos clic, sino el texto que contiene.
public class EditorTest extends
             ActivityInstrumentationTestCase2<EditorActivity> {
             
...

 public void testPreferenceIsSaved() throws Exception {
 
           solo.sendKey(Solo.MENU);
           solo.clickOnText("More");
           solo.clickOnText("Preferences");
           solo.clickOnText("Edit File Extensions");
           Assert.assertTrue(solo.searchText("rtf"));
           
           solo.clickOnText("txt");
           solo.clearEditText(2);
           solo.enterText(2, "robotium");
           solo.clickOnButton("Save");
           solo.goBack();
           solo.clickOnText("Edit File Extensions");
           Assert.assertTrue(solo.searchText
           ("application/robotium"));
 }
...
}
Estos tests son muy potentes, ya que no requieren del conocimiento de la aplicación (como en el resto de los casos) y, además, prueban la aplicación al completo. Como contrapartida, presentan algunos problemas (dejan de funcionar con pequeños cambios de la interfaz, realizan cambios en el texto y son lentos de construir y de ejecutar).

5.5.Otras herramientas

También existen otras herramientas generadas por Google o por la comunidad. Entre ellas destacamos DroidDraw, App Inventor y Sensor Simulator.
5.5.1.DroidDraw
DroidDraw es un herramienta que sirve para generar, de manera sencilla, interfaces visuales de Android en formato XML. La peculiaridad de esta herramienta es que se puede ejecutar dentro de nuestro navegador o de manera nativa en el sistema operativo del desarrollador.
Ejemplo de edición de un layout dentro de DroidDraw
La aplicación permite descargar en el dispositivo una versión previa de la interfaz creada en nuestro dispositivo. Para ello se utiliza la aplicación para el móvil llamada AnDroidDraw.
5.5.2.Sensor Simulator
Sensor Simulator es una herramienta creada por la comunidad para poder simular los sensores de nuestro emulador o dispositivo. El objetivo es poder simular cambios de orientación (o de temperatura, etc.). Para ello se necesita un servidor en funcionamiento en nuestro entorno de desarrollo y una aplicación instalada en el emulador.
Uso de Sensor Simulator para cambiar datos de los sensores
5.5.3.App Inventor
App Inventor es una aplicación "en línea" de Google cuyo propósito es que personas sin conocimientos de programación sean capaces de programar una aplicación sencilla y descargarla y ejecutarla en su móvil.
Para facilitar la edición visual, incorpora un editor gráfico con capacidades reducidas y algunas peculiaridades que hacen más sencillo su uso, al estilo de DroidDraw:
Ejemplo de edición de la interfaz gráfica con App Inventor
Además, para programar la lógica de la aplicación, utiliza objetos que representan las formas de control más típicas de una aplicación móvil:
Ejemplo de edición de una lógica de aplicación utilizando App Inventor

6.Distribución y negocio

Una vez terminada vuestra aplicación (o, al menos, una versión), es el momento de que la distribuyáis.
En el caso de Android, se puede distribuir directamente el fichero .apk correspondiente a la aplicación, pero también se puede hacer mediante alguno de los mercados de aplicaciones (markets) o, por ejemplo, mediante el mercado oficial de Google. En estos mercados podéis ofrecer la opción de vender la aplicación y conseguir remuneración por ella, pero lo más importante es que estos mercados abren el nuevo canal de distribución de vuestra aplicación.
También existen otros métodos de remuneración por las aplicaciones, como la publicidad o los pagos en la propia aplicación.

6.1.Firma de la aplicación

Firmar una aplicación es un proceso en el que se utiliza un certificado digital privado para marcar la aplicación, de manera que se puede saber de forma unívoca quién es el autor de la aplicación. Esta unicidad se valida mediante la clave pública correspondiente.
Para poder utilizar vuestra aplicación en un dispositivo físico, siempre debe estar firmada, bien con una clave definitiva, bien con una de prueba. El certificado, a diferencia de los utilizados en los navegadores, no necesita estar certificado por una entidad certificadora, sino que puede estar generado por el propio desarrollador. A pesar de esto, los certificados deben ser auténticos y vigentes, aunque solo se comprueba su fecha de validez la primera vez que se instala la aplicación.
Es importante que la firma de la aplicación se haga con un certificado que no caduque durante la vida de la aplicación. Si sucede, deberéis asignar un nuevo paquete a vuestra aplicación para poder firmarla correctamente y, finalmente, el usuario deberá instalarla como una aplicación diferente. En concreto, para instalar la aplicación mediante el market oficial de Android, se debe firmar la aplicación con un certificado cuya fecha de final de validez sea posterior al 22 de octubre del 2033.
Los certificados se pueden utilizar para firmar más de una aplicación. Esto puede ocurrir en varios casos:
  • Dos aplicaciones quieren compartir información en tiempo de ejecución. Esto es debido a que dos aplicaciones con el mismo certificado se pueden ejecutar dentro del mismo proceso y, por tanto, tienen los mismos recursos de sistema, como si fueran un único proceso. Con esto se pueden tener aplicaciones distintas que interactúan intensamente.

  • Modularizar nuestra aplicación. Si tenéis vuestra aplicación dividida en partes y queréis que cada una de estas partes se pueda actualizar por separado, una manera de hacerlo es realizar aplicaciones distintas, pero firmadas con el mismo certificado.

Las firmas de debugging se pueden generar con las herramientas estándar del JDK. En el caso de trabajar con otro IDE (como Eclipse), este hará el trabajo por nosotros.
A la hora de generar una versión pública deberemos:
1)Obtener una clave privada.
2)Compilar la aplicación para su distribución.
3)Firmar la aplicación con la clave obtenida en el primer paso.
4)Alinear el paquete APK.
Estas fases, si no disponéis de un IDE, se realizan mediante diferentes comandos (como keytool, jarsigner, ant, zipalign). Si disponéis de un IDE (como Eclipse), simplemente deberéis exportar la aplicación para que sea distribuida. Las acciones de firmado y alineación son controladas por el plugin ADT de Eclipse.
Es importante que mantengáis en un lugar seguro las claves privadas con las que firmáis aplicaciones públicas, pues si alguien malintencionado las consigue, puede cambiar el código y realizar actualizaciones de vuestra aplicación sin vuestro permiso, pero todos los usuarios verán que es una actualización más.

6.2.Versionado de las aplicaciones

Las aplicaciones de Android permiten gestionar las versiones de la misma aplicación. Esto sirve para mantener información de lo que contiene cada aplicación, para pedir nuevos permisos en el caso de que sea necesario, o bien para que otras aplicaciones sean conscientes de la versión actual. Esto último es útil para evitar incompatibilidades entre versiones, de manera que otra aplicación puede saber con qué versión es compatible y preguntar cuál es la versión actual de dicha aplicación o (por lo general) servicio.
Las versión actual se define en el manifiesto con dos atributos:
  • android:versionCode: Corresponde a un entero que representa la versión del código de la aplicación y es relativo a versiones previas.

  • android:versionName: Es un texto que identifica, para los usuarios, el nombre de la versión. Puede ser algo (como sucede con Android) que identifique la versión de manera decimal (X.Y.Z), para identificar claramente el nivel de cambios de una versión respecto a otra.

Se puede obtener información de la versión de una aplicación concreta mediante la clase PackageManager y el método getPackageInfo(packageName, flags).
Es posible que queráis actualizar datos de una versión a otra, cosa que ocurre con las versiones del SDK que están soportadas, al igual que con todas las aplicaciones que nos permiten "setear" los requerimientos mínimos de la aplicación. Si actualizamos la versión y esta es incompatible o requiere nuevos permisos, Android tomará las acciones correspondientes para garantizar su correcto funcionamiento según las definiciones del manifiesto.

6.3.Consideraciones previas a publicación

Hay algunos puntos que debéis tener en cuenta antes publicar la aplicación para el usuario final:
  • Debéis haber probado la aplicación con dispositivos reales. Como habéis visto anteriormente, existen herramientas en el SDK de Android (y fuera del mismo) que os ayudan a ello. Esto es importante para evitar la frustración de los usuarios y la posible mala reputación de nuestra aplicación.

  • En el caso de que sea necesario, debéis añadir un contrato de licencia de usuario final (EULA), en inglés end user license agreement, para informar de las condiciones de nuestra aplicación y, en especial, de sus repercusiones.

  • Si se trata de una aplicación no gratuita, considerad añadirle una licencia a la aplicación, de manera que podáis gestionara dentro del sistema de licencias de Android.

  • Definir el icono y el nombre de la aplicación.

  • Verificar que vuestros filtros del manifiesto son correctos, de manera que no se podrá instalar la aplicación en un dispositivo o tipo de dispositivo que haya sido probado.

  • Eliminar del código correspondiente la depuración, ya sea de logging excesivo o de otras fuentes.

  • Conseguir las claves propias para producción de librerías, como, por ejemplo, las claves de la API de Google Maps.

  • Realizar la firma para distribuir la aplicación.

  • Finalmente, probar la aplicación firmada en dispositivos reales.

6.4.Publicación y seguimiento

Cuando tengáis la aplicación preparada para su distribución, se puede transmitir de manera habitual (con el correspondiente fichero .apk) o en el market. Este canal de distribución añade mucho valor, por lo que es importante que lo conozcáis. Este canal ofrece la posibilidad de llegar a millones de potenciales clientes con una sola acción.
Para publicar en el Android market de Google, necesitáis una cuenta de Google Checkout. Además, debéis abrir una cuenta de desarrollador, que tiene un coste único de veinticinco dólares. A partir de ese momento, si vuestra aplicación es de pago, recibiréis en vuestra cuenta de Google Checkout el 70% de las ganancias directas o indirectas del market.
Las posibles opciones de publicación de una aplicación en el mercado y sus modelos de negocio son las siguientes:
  • Una aplicación gratuita: Puede descargarse fácilmente y ser utilizar sin ninguna restricción. En este caso, suele tratarse de aplicaciones de soporte a negocios mayores fuera del entorno móvil, como bancos, publicidad bajo demanda, etc.

  • Una aplicación gratuita con publicidad: Estas aplicaciones suelen ser muy populares, y lo que consiguen es que la aplicación sea totalmente gratuita. A cambio, el usuario debe ver ciertos anuncios, por ejemplo mediante AdMob.

  • Una aplicación de pago: Son aplicaciones que requieren que el usuario pague por ellas. Por lo general, al usuario final se le da la posibilidad de probar la aplicación durante un corto periodo de tiempo, con la opción de devolverla y retirar el pago.

  • Una aplicación en versión lite: Este tipo de aplicaciones son versiones de aplicaciones de pago que tienen unas funcionalidades reducidas o eliminadas. El objetivo es atraer al usuario final y que este compre la versión de pago.

  • Pagos por bienes virtuales: Se utiliza para pedir pagos en la propia aplicación, que son gestionados por ella. Android tiene actualmente una API para ello, llamada In-app billing. Podéis ver el esquema de pagos en siguiente imagen.

Todas las aplicaciones que hemos comentado se comercializan en un market. Podéis llegar al usuario de tres formas distintas:
  • Mediante los listados de aplicaciones más recientes: Estas están organizadas por tipo de aplicación (juegos o aplicaciones) y categoría. En este listado de aplicaciones entran todas las nuevas aplicaciones, por lo que el tiempo de permanencia es limitado. Por ello, es importante elegir bien la categoría, sopesando el número de aplicaciones nuevas que van a llegar.

  • Mediante las búsquedas por keywords: Un usuario puede realizar una búsqueda en cualquier momento, por lo que debéis elegir bien las palabras e, incluso, incluir palabras internacionalizadas.

  • Mediante las aplicaciones top: Este listado depende de las descargas y de las valoraciones de los usuarios. Este listado es el más difícil de mantener y, a la vez, el que puede dar mayores beneficios. Para conseguir que se mantenga, es importante que escuchéis a vuestros usuarios y realicéis las mejoras que sugieran. También es bueno que realicéis actualizaciones habitualmente.

En los mercados de aplicaciones, las aplicaciones suelen tener diversos componentes de promoción que hacen que el usuario se decante o no por ellas. Entre los más importantes están el nombre y la descripción, las imágenes o vídeos de la aplicación y, finalmente, los comentarios y las votaciones de los usuarios.

Resumen

Este módulo didáctico introduce al estudiante a los principales conceptos del desarrollo móvil nativo basado en Android.
Introducimos el módulo con la historia reciente de esta tecnología, poniendo las bases sobre cómo se estructuran las aplicaciones.
Posteriormente hemos visto los principales componentes comunes a todas o gran parte de las aplicaciones Android, como son las fases del ciclo de vida, los Intents, el Manifiesto, etc.
A continuación hemos profundizado en la parte relacionada con la interfaz gráfica, viendo las posibilidades que ofrece Android para combatir la fragmentación. Y posteriormente hemos introducido al estudiante algunas de las partes más interesantes del SDK como son las aplicaciones LBS, los almacenes de datos, o tecnologías como NFC o SIP.
Finalmente hemos visto las herramientas que existen para facilitar su desarrollo, y también las herramientas necesarias para su distribución y comercialización.

Actividades

1. Hemos visto que las activities pueden volver al punto en que dejamos la activity en caso de ser interrumpida, pero hay algunas especiales que no tienen este comportamiento. ¿Cuáles son y por qué?
2. Cuando invocamos una nueva activity en la misma task, la activity suele estar asociada a la task y pertenece por completo a su pila de activities. Sin embargo, hay algunos casos en que esto no es del todo cierto. ¿Cuáles son estos casos y qué aportan?
3. Desarrollad pruebas de concepto para cada uno de los componentes explicados, desde las vistas más simples hasta las aplicaciones para la sincronización de datos.
4. Averiguad en qué se diferencian las nuevas versiones de Android para la gestión de dispositivos tipo tabletas PC de las antiguas.
5. Enumerad los tipos de componentes principales que se utilizan para el desarrollo de aplicaciones Android.
6. Identificad el comando que se utiliza para acceder al terminal de Android.
7. Haced una lista de los objetos utilizados para lanzar aplicaciones diferentes a la actual (como por ejemplo, enviar un correo) e indicad cómo se configuran.

Glosario

API f
Sigla de application programming interface
bytecode m
Código formado por instrucciones ejecutables independientes del hardware final de la máquina.
dalvik f
Maquina virtual Java donde se ejecutan las aplicaciones Android.
debug m
Proceso que identifica y corrige errores de programación.
driver m
Componente de software responsable de ofrecer acceso a un componente hardware.
evento m
Acción que se inicia generalmente fuera del ámbito de aplicación de un programa y que se maneja por un fragmento de código dentro del programa.
GPS m
Sigla de global positioning system. El sistema de posicionamiento global determina la posición de un objeto, persona o vehículo en todo el mundo, pudiendo llegar a precisiones de centímetros, aunque normalmente hablamos de metros. Fue desarrollado e instalado por el Departamento de Defensa de Estados Unidos. Para poder dar este servicio se utilizan decenas de satélites que giran alrededor de la Tierra en una órbita superior a los 20.000 km.
Alternativas al GPS: GLONASS, de la Federación rusa y Galileo, de la Unión Europea.
jUnit m
Conjunto de bibliotecas utilizadas en programación para hacer pruebas unitarias de aplicaciones Java.
keywords f
Palabras clave que pueden servir para identificar un objeto a través de otros conceptos, especialmente útil para búsquedas.
layout m
Distribución visual de los objetos gráficos en la aplicación.
LBS m
Sigla de location based service. Servicio basado en la posición geográfica del usuario.
listener m
Parte del patrón de diseño Observer, que es notificado cuando sucede un evento para el cual ha registrado interés.
middleware m
Capa de software encargada de independizar el desarrollo de los detalles que están por debajo.
modularizar v tr
Dividir una aplicación en módulos.
multithreading m
Aplicado a la industria móvil, quiere decir poder mantener varias aplicaciones ejecutándose a la vez.
Open GL f
Especificación estándar que define una API multilenguaje y multiplataforma para escribir aplicaciones que produzcan gráficos 2D y 3D.
Open Handset Alliance f
Consorcio de empresas: Broadcom Corporation, Google, HTC, Intel, LG,Marvell Technology Group, Motorola, Nvidia, Qualcomm, Samsung Electronics, Sprint Nextel, T-Mobile y Texas Instruments.
renderización f
Proceso de generación de una imagen desde un modelo.
retrollamada f
Llamada a un método o función donde uno de los parámetros será una referencia al método o función.
SQL Lite m
Motor de base de datos relacionales.
UI f
Sigla de user interface. Interfaz gráfica o interfaz de comunicación con el usuario.
URI m
Sigla de universal resource identified. Identificador único dentro de la aplicación. Las URL son un tipo de URI.
WebKit m
Plataforma para aplicaciones que funciona como base para los navegadores Safari, Google Chrome, Epiphany o Midori, entre otros. Está basada originalmente en el motor de renderizado KHTML del navegador web del proyecto KDE, Konqueror.
XML m
Sigla de extensible markup language (lenguaje de marcas extensible). Metalenguaje extensible de etiquetas desarrollado por el World Wide Web Consortium (W3C). Es una simplificación y adaptación del SGML y permite definir la gramática de lenguajes específicos (de la misma manera que HTML, es a su vez un lenguaje definido por SGML). Por lo tanto, XML no es realmente un lenguaje en particular, sino una manera de definir lenguajes para diferentes necesidades.

Bibliografía

Murphy, Mark L. (2009). The Busy Coder's Guide to Android Development. Commonware.
Steele, James; To, Nelson (2011). The Android Developer's Cookbook. Developer's Library.
Enlaces de Internet