SlideShare una empresa de Scribd logo
Desarrollo de Aplicaciones para
Android (con Android Studio)
Introducción y objetivos
En este Módulo 0 introductorio, veremos:
 Una visión general de lo que es Android
 Las características más importantes de este sistema operativo.
Máquinas virtuales Dalvik y ART
 La tipología de dispositivos que actualmente lo utilizan
 La cuota de mercado que tiene Android en el conjunto de sistemas
operativos móviles
 La fragmentación de las distintas versiones Android (su % de
implementación/uso en los dispositivos actuales)
El objetivo de este módulo es que obtengas una visión general de lo que es Android y sus
principales características, así como conocer su grado de uso/implementación en el mercado
actual de smartphones y dispositivos móviles en general.
Dado que este tema tiene un carácter principalmente informativo y no planteamos ejercicios
prácticos, lo hemos numerado como '0' para diferenciarlo del resto de temas donde
ya empezamos a tratar de forma práctica el desarrollo en Android.
Aunque es un módulo que puede considerarse opcional, te recomendamos leerlo
para conocer mejor el contexto de este sistema operativo, y si quieres, realizar el
test, para comprobar tus conocimientos de una manera informal.
Última modificación: viernes, 2 de septiembre de 2016, 18:10
Qué es Android
Android es un sistema operativo diseñado principalmente para trabajar sobre smartphones
(teléfonos inteligentes), aunque hoy en día nos lo podemos encontrar también en tablets,
relojes (smartwatches), netbooks, ordenadores, televisores, vehículos...Pero Android no es
solamente un sistema operativo, también es un lenguaje de programación y un framework
para desarrollo de aplicaciones. Al conjunto de todos estos elementos es a lo que llamamos
Android.
Inicialmente fue desarrollado por una pequeña empresa llamada Android Inc., fundada, entre
otros, por Andy Rubin en 2003, la cual fue comprada por Google en el año 2005. Dos años
más tarde, el 5 de noviembre de 2007, fue anunciada la distribución de Android junto con la
fundación de la Open Handset Alliance, un conjunto de fabricantes y desarrolladores de
hardware, software y telecomunicaciones dedicados a la promoción de estándares abiertos
para dispositivos móviles.
Google lanzó la mayor parte del código de Android bajo la licencia Apache, una licencia de
software libre. Pero no fue hasta septiembre del año siguiente cuando salió el primer terminal
con Android, el HTC Dream, que disponía de Android 1.0. Desde entonces han ido
apareciendo diversas versiones hasta llegar a la versión 7.0 (Junio de 2016. Puedes ver un
listado de versiones y fecha de aparición en el apartado final de este módulo).
Tiene una gran comunidad de desarrolladores escribiendo aplicaciones de todo tipo, tanto
gratis como de pago. Ya en 2014 se sobrepasó la cifra de 1.000.000 de aplicaciones activas
en Google Play, la tienda de aplicaciones oficial de Android, superando al número que tenía la
App Store de Apple para iOS. Los programas principalmente están escritos en el lenguaje de
programación Java, aunque se pueden implementar partes de un programa en un lenguaje
nativo, como C o C++ mediante la herramienta Android NDK.
Las aplicaciones son compiladas por el Android SDK en formato .apk, instalables en cualquier
dispositivo Android. Una vez instaladas, cada aplicación posee su propia seguridad:
 El sistema operativo Android es un sistema Linux multiusuario en
donde cada aplicación es un usuario diferente.
 Por defecto, el sistema asigna a cada aplicación un identificador
único de usuario, que es usado sólo por el sistema.
 Cada proceso tiene su propia máquina virtual, luego el código de
una aplicación se ejecuta aisladamente de las demás aplicaciones.
 Por defecto, cada aplicación corre su propio proceso Linux.
Android inicia el proceso cuando alguno de los componentes de la
aplicación necesita ser ejecutado, después para el proceso
cuando ya no se necesita más o cuando el sistema necesita
recuperar memoria para otras aplicaciones.
De este modo, el sistema Android implementa el principio del mínimo privilegio, es decir, cada
aplicación por defecto sólo tiene acceso a los componentes que sean necesarios para poder
funcionar correctamente. Esto genera un entorno muy seguro en el que una aplicación no
podrá acceder a partes del sistema sin antes pedir permiso para ello.
Sin embargo, hay modos mediante los cuales una aplicación puede compartir datos con otras
y poder acceder a servicios del sistema:
 Es posible disponer de dos aplicaciones que compartan el mismo
identificador de usuario, por lo que será posible acceder a los
archivos de cada uno de ellos. Para preservar los recursos del
sistema, estas aplicaciones podrán ser ejecutadas bajo el mismo
proceso Linux y compartir la misma máquina virtual (para ello
deben ser firmadas con el mismo certificado).
 Una aplicación puede pedir permiso para acceder a los datos del
dispositivo, como pueden ser los contactos, los mensajes SMS, la
tarjeta SD, la cámara, el Bluetooth, etc. Todos estos permisos
han de ser aceptados por el usuario en el momento de su
instalación.
En este segundo tema, explicaremos cómo empezar a programar en Android, desde la
instalación del entorno, pasando por la instalación del SDK y las Android Development Tools
(en adelante ADT) hasta llegar a la creación y ejecución de un programa ejemplo, el Hola
Mundo.
Al término de este tema, el alumno será capaz de:
 Instalar y configurar un entorno de desarrollo junto con las
herramientas necesarias para empezar a programar en Android.
 Identificar los distintos canales y tipos de versiones que están
disponibles para Android Studio
 Crear su primera aplicación en Android y la ejecución de la misma
en un emulador.
1.2. Entorno de desarrollo Android
Studio
1.2 Entorno de desarrollo Android
Studio.
Android Studio es un entorno de desarrollo integrado (IDE), desarrollado por Google a partir
de IntelliJ IDEA (de la compañia JetBrains).
A finales de 2014, Google lo convirtió en el IDE oficial para Android, sutituyendo
al plugin ADT (Android Developer Tools) para el IDE Eclipse que venía siendo la
herramienta recomendada y más utilizada hasta ese momento.
Con la aparición de Android Studio, Google conseguía crear un entorno dedicado
específicamente a la programación de aplicaciones para dispositivos
Android, teniendo además un mayor control sobre su proceso y ritmo de desarrollo y
la incorporación de nuevas funcionalidades. Android Studio utiliza una licencia de
software libre Apache 2.0, está programado en Java y es multiplataforma.
Android Studio se presentó en mayo de 2013 y la primera versión estable 1.o se liberó
en diciembre de 2014, manteniéndose desde entonces un alto ritmo de actualizaciones (a
fecha de Septiembre de 2016, ya están disponibles las versiones 2.X).
Logos de Android Studio: original de 2013 (robot androide: izquierda) y logo
actual (compás: derecha)
Principales características que incluye Android
Studio
Vamos a enumerar algunas de las características más destacadas de este IDE (hay que tener
en cuenta que la incorporación de nuevas funcionalidades es casi continua con las nuevas
versiones que van apareciendo):
 Soporte para programar aplicaciones no solo
para teléfonos y tablets sino también para las otras plataformas
Android como Android Wear (para dispositivos corporales
o wearables como los relojes smartwatch), Auto (para
vehículos), Glass (para gafas) y TV (televisión).
 Instant Run que permite visualizar al instante los cambios que
introduzcamos en el código y los recursos de la app en ejecución en un
dispositivo o emulador, sin necesidad de compilar nuevamente.
 Editor de código inteligente que ofrece refactorización y completado
avanzado de código (presenta sugerencias en una lista desplegable
mientras escribes)
 Herramientas Lint: detecta código no compatible entre arquitecturas
diferentes o código confuso que no es capaz de controlar el compilador,
para detectar problemas de rendimiento, usabilidad y compatibilidad de
versiones.
 Utiliza ProGuard para optimizar y reducir el código del proyecto al
exportar a APK (muy útil para dispositivos de gama baja con limitaciones
de memoria interna).
 Permite construir variantes y generación de múltiples APK. Podemos
por tanto crear diferentes versiones de la misma aplicación, por
ejemplo una versión de pago y otra gratuita, o para diferentes dispositivos
o almacenes de datos.
 Integración de la herramienta Gradle encargada de gestionar y
automatizar la construcción de proyectos, como pueden ser las tareas de
testing, compilación o empaquetado.
 Construcción y gestión de proyectos basado en Maven (herramienta de
software para la gestión y construcción de proyectos Java, similar a
Apache ANT, pero su modelo es más simple ya que está basado en XML)
 Soporte para NDK (Native Development Kit: herramientas para
implementar código nativo escrito en C y C++)
 Interfaz específica para el desarrollo en Android.
 Editor de diseño que muestra una vista previa de los
cambios realizados directamente en el archivo xml.
 Vista previa en diferentes dispositivos y resoluciones.
 Permite la importación de proyectos realizados en el entorno Eclipse,
que utiliza ANT (a diferencia de Android Studio que utiliza Gradle) .
 Posibilita el control de versiones accediendo a un repositorio desde el
que poder descargar Mercurial, Git, Github o Subversion.
 Alertas en tiempo real de errores sintácticos, compatibilidad o
rendimiento antes de compilar la aplicación.
 Integración con Google Cloud Platform, para el acceso a los
diferentes servicios que proporciona Google en la nube.
Requerimientos del sistema
Te presentamos los requisitos hardware y software que necesita tu equipo para que Android
Studio funcione adecuadamente. Destacamos la necesidad de disponer de suficiente memoria
RAM (aconsejable 8 GB), sobre todo si pruebas con un emulador y no en dispositivo físico.
Windows Mac OS Linux
Microsoft Windows
7/8/10 (32 o 64
bit)
Mac OS X 10.8.5 o
superior, hasta la
10.11.4 (El Capitan)
GNOME o entorno de
escritorio KDE (probado en
Ubuntu 12.04 Precise
Pangolin)
Mínimo de 2 GB de RAM, recomendado 8 GB de RAM
2 GB de espacio mínimo en disco (500 MB para IDE + 1,5 GB para SDK)
Para emulador acelerado: sistema operativo 64 bits y procesador Intel con
VT-x, EM64T y Executable Disable (XD) Bit
Resolución mínima de pantalla de 1280 x 800
Java Development Kit (JDK) 7 o superior
Nota: Para los sistemas Linux será necesaria la biblioteca de C GNU (glibc) 2.11 o posterior.
Además para los sistemas Mac OS será necesario ejecutar Android Studio con Java Runtime
Environment (JRE) 6 para la renderización optimizada de fuentes.
Los requisitos generales que hemos indicado en la tabla pueden variar con nuevas versiones.
Puedes consultar las últimas especificaciones al final de la página de descarga de Android
Studio
Android Studio vs Eclipse: si has trabajado con Eclipse en el desarrollo de Apps
Android, puedes ver una comparación de este IDE con las primera versión estable de
Android Studio en nuestra web Academia Android
1.3. Descarga e instalación de
Android Studio
La última versión de Android Studio disponible la puedes descargarse desde el siguiente
enlace: https://developer.android.com/sdk/index.html.
La versión para Windows aparece destacada según vemos en esta imagen (en el momento
de consultarla seguramente te aparecerá una versión disponible más avanzada que
la de esta imagen):
pero podemos acceder también a las versiones para Linux o Mac al hacer scroll hacia abajo
en esta página:
Otras versiones de Android Studio: puedes descargar las diversas versiones estables
que han ido apareciendo en el canal Stable, así como versiones en proceso de desarrollo y
pruebas a través de los diferentes canales Canary, Dev, y Beta a los que puedes acceder
a través del enlace: http://tools.android.com/download/studio
Proceso de instalación
Tras la descarga del instalador, bastará con realizar doble click sobre el archivo con extensión
.exe descargado. A continuación, comenzará el proceso de instalación:
Notas:
 Debes tener instalado en tu equipo el JDK (Java Development Kit),
en versión 7 ó superior. El proceso de instalación de Android
Studio lo comprobará y si no lo detecta te ofrecerá descargarlo e
instalarlo desde la web de Oracle. Aunque es muy probable que ya
hayas trabajado con Java y lo tengas disponible y actualizado, te
hemos preparado un video que tienes a continuación de este
apartado donde puedes ver todo el proceso y cómo configurar las
variables de entorno Java en Windows.
 Cuando realices el proceso de instalación de Android Studio,
éste puede variar ligeramente respecto a los pasos e imágenes
que te mostramos a continuación dado los continuos cambios que
introduce Google. En cualquier caso serán muy similares y fáciles
de entender a partir de esta guía.
1. Inicialmente, mostrará una pantalla de bienvenida a la instalación de Android Studio,
en la que sólo se deberá pulsar en "Next":
2. Posteriormente, solicitará que se indiquen los componentes que se desean
instalar/desinstalar. Elegiremos la opción por defecto que instala tanto el SDK como el
AVD. Una vez seleccionados los componentes, se continuará pulsando en "Next" :
SDK: El Software Development Kit es como su nombre indica un kit o conjunto de
herramientas con él podremos desarrollar aplicaciones Android para cualquiera de las
versiones disponibles de este sistema. Cuando lo instalemos podremos seleccionar a través
del entorno SDK Manager (al que accederemos a través de un botón en el menú de
herramientas de Android Studio), la instalación y descarga de paquetes (Packages) de
herramientas, APIs, fuentes, ejemplos, ... Por tanto las Apps Android las desarrollaremos en
lenguaje Java con este kit.
AVD: para probar nuestras aplicaciones, podemos crear máquinas virtuales que emulen las
características de un teléfono Android, una tablet, o un dispositivo Android Wear o Android TV.
El administrador de AVD (Android Virtual Devices), al que accederemos también a través de
un botón en la barra de herramientas de Android Studio, nos permite crear y definir dichos
dispositivos virtuales. Veremos que hay otras opciones como el emulador GenyMotion,
además de poder probar directamente en nuestro dispositivo Android si lo tenemos.
3. En la siguiente ventana, se deberán aceptar los términos de licencia, seleccionando la
opción "I Agree":
4. A continuación, se deberá indicar los directorios de instalación del IDE Android
Studio y del SDK Android. En este caso, dejamos las opciones por defecto, aunqeu podemos
elegir lógicamente otras. Será necesario un espacio en disco de al menos 500 MB para
Android Studio y 3,2 GB para el SDK. Se pulsará en "Next" para continuar el proceso de
instalación:
5. Tras seleccionar los directorios de instalación, mostrará una ventana indicando si se ha
detectado que nuestro sistema puede iniciar un emulador de Android en modo de
rendimiento acelerado. Además solicitará que se indique la cantidad máxima de
memoria RAM disponible para el motor de virtualización asistido por hardware, que
proporciona Intel(r) HAXM. Se pulsará en "Next" para continuar:
Nota: veremos más sobre HAXM (Intel Hardware Accelerated Execution Manager) es el
apartado de creación de un emulador
6. Otra opción de configuración durante el proceso de instalación, será la selección o
creación de las carpetas que formen el menú de inicio de Android Studio,
para el acceso directo al programa en cuestión. En el ejemplo se dejan los valores por defecto
de la instalación:
7. Al pulsar en el botón "Install" de la ventana anterior, comenzará el proceso de
instalación:
8. Una vez el proceso ha finalizado, se pulsará sobre "Next", indicando en la siguiente
ventana que el proceso de instalación se ha completado. Además permitirá tanto el inicio del
IDE Android Studio, como la importación de proyectos realizados con el plugin ADT de
Android en Eclipse o en versiones anteriores de Android Studio. Se pulsará
sobre "Finish" para terminar el proceso de instalación:
9. Al arrancar Android Studio por primera vez nos aparecerá la pantalla de asistente de
configuración ("Setup Wizard") donde nos dará a elegir entre una configuración
'Standard' o 'Custom' (personalizada). Si elegimos la opción estándar completará la
descarga e instalación de paquetes seleccionados en el proceso anterior y si elegimos
la personalizada, aparecerán una serie de ventanas preguntándonos sobre diversas
elecciones, tal como te mostramos en el segundo video que tienes sobre la instalación de
Android Studio.
Video: instalación JDK (Java
Development Kit)
En el caso de que no tengas el JDK (Java Development Kit) en tu equipo, el proceso de
instalación de Android Studio te pedirá que lo instales ya que es imprescindible para el
funcionamiento del entorno de desarrollo.
En este video puedes ver cómo instalarlo y cómo configurar las variables de entorno para Java
en tu equipo (se muestra el ejemplo con el sistema operativo Windows)
2.1. Introducción y objetivos
En este tema veremos los distintos componentes software que podemos utilizar en Android y
cómo construir una primera App con algunos de esos componentes (activity e intents).
También describiremos el fichero AndroidManifest.xml, fundamental en cualquier
aplicación Android.
En este tema aprenderás:
 Cuáles son los componentes básicos con lo que crear una App
Android: Activities, Services, Intents, Content Provider y
Broadcast Receivers.
 Cómo implementar una Activity y su ciclo de vida.
 La estructura y función del fichero AndroidManifest.xml.
 Construir un archivo APK del proyecto desarrollado.
 Cómo usar de un Intent para enviar información entre Activities y
cómo crear intefaces de usuario básicas, a través de un proyecto
ejemplo que crearemos.
2.2 Componentes de una Aplicación
Android: Activities, Services, Intents,
Content Provider y Broadcast
Receivers
Activities, Services, Intents, Content
Provider y Broadcast Receivers
Android facilita la creación de aplicaciones gracias al uso de un conjunto
de componentes software reutilizables. Vamos a explicar los principales y
cómo podemos implementarlos dentro de un proyecto Android:
Activity
Éste es el componente principal de la interfaz gráfica de una aplicación en
Android. A cada Activity se le asigna una ventana en la cual se dibuja
la interfaz de usuario, con la que el usuario podrá interaccionar para realizar las
diversas acciones que hayamos contemplado en la aplicación.
Para construir la interfaz gráfica, cómo veremos en el tema 3, tenemos los
componentes denominados Views (vistas) con lo que dispondremos de numerosos
controles básicos, como por ejemplo, botones, listas desplegables o cuadros de
texto, pudiendo extender la funcionalidad de estos controles o crear otros
personalizados.
Por lo general, una aplicación está formada por diferentes Activities, que están
más o menos ligadas entre sí. Cuando se suceden varias, éstas se
van almacenando en una pila mediante el mecanismo de LIFO (Last In - First
Out: la última que entra en la pila es la primera que sale) y cuando el usuario
pulsa el botón atrás, se extrae la Activity actual de la pila y se reanuda la anterior
Activity situada allí.
Cada Activity que creemos, la tenemos que definir en
el AndroidManifest.xml (explicamos este fichero en un siguiente apartado) con
la etiqueta <activity>.
Para iniciar una Activity, podemos utilizar dos métodos (como veremos más
adelante):
 Método Context.startActivity()
 Método Context.startActivityForResult() , cuando queramos que se devuelva
algún resultado.
También mencionar que tenemos otros componentes que funcionan dentro del
ámbito de una Activity, los Fragments, que amplían y enriquecen las
posibilidades de interacción con el usuario.
Service
Los services (servicios) son componentes sin interfaz gráfica que se ejecutan
en segundo plano. Son llamados a través de otro componente, como puede
ser una Activity, y seguirán ejecutándose en segundo plano aunque la Activity
haya finalizado o, incluso, aunque hayamos salido de la aplicación.
Cada servicio que creemos lo tenemos que declarar en
el AndroidManifest.xml mediante la etiqueta <service> . Para ser iniciados
podemos usar dos métodos:
 Método Context.startService()
 Método Context.bindService()
Intent
Un Intent es el elemento básico de comunicación entre los
componentes que estamos describiendo, es decir, mediante un Intent se podrá
llamar a una Activity, iniciar un servicio, enviar un mensaje broadcast, iniciar otra
aplicación, etc.
Su uso más importante es para iniciar Activities, por lo que puede
considerarse como la unión entre Activities. Más adelante veremos cómo hacer
esto.
Los objetos Intent están formados por un paquete de información. Contienen
información de interés para el componente que la recibe, como la acción que será
ejecutada y los datos necesarios, más la información de interés para el sistema
Android, como la categoría del componente que manejará el Intent y las
instrucciones de cómo lanzar la Activity.
Principalmente pueden contener lo siguiente:
 Nombre de componente: el nombre del componente que manejará el
Intent. Es una combinación del nombre de la clase del componente y el
nombre del paquete especificado en el AndroidManifest.xml de la
aplicación donde reside el componente (por ejemplo,
com.academiaandroid.holamundo.Activity). Esto es opcional. Si lo
definimos, se creará una instancia de la clase designada. Si no es así, se
usará otro tipo de información para localizar el objetivo deseado.
 Acción: una cadena de texto que designa la acción a ser ejecutada. La
clase Intent define una serie de ellas como pueden ser las siguientes,
entre otras:
o ACTION_CALL :Inicia una llamada telefónica.
o ACTION_EDIT :Muestra datos para que el usuario pueda editarlos (como
los datos de un contacto).
o ACTION_MAIN :Indica la Activity principal de una aplicación, la que se
ejecutará al iniciarse.
Nosotros también podemos definir las nuestras propias para activar componentes
en nuestra aplicación. Las que definamos, tienen que incluir el nombre del paquete
como prefijo, por ejemplo: com.academiaandroid.holamundo.SHOW_COLOR .
Estas acciones se podrán establecer mediante el método setAction() y obtenerlas a
través de getAction() .
Nota: en este mismo tema veremos un ejemplo completo del uso del componente Intent para
lanzar y enviar parámetros a una segunda Activity.
Content Provider
Un Content Provider es un componente destinado a compartir datos entre
aplicaciones. Dichos datos pueden ser almacenados en el sistema de archivos, en
una base de datos SQLite o en cualquier otro lugar que sea accesible desde
nuestra aplicación. Un ejemplo de Content Provider es el que utiliza Android para
gestionar la información de un contacto, mediante el cual cualquier aplicación
podrá acceder a estos datos haciendo una petición al método query() sobre la
interfaz ContentResolver .
Broadcast Receiver
Un Broadcast Receiver es un componente que detecta y reacciona frente
a mensajes globales del sistema, como puede ser batería baja, SMS recibido,
llamada recibida, etc. Además de esto, una aplicación también puede iniciar un
Broadcast Receiver (por ejemplo, para saber si se han descargado datos al
dispositivo y poder ser usados por esa aplicación).
Al igual que ocurría con los Services, un Broadcast Receiver tampoco muestra
ninguna interfaz gráfica. Al igual que los servicios y Activities, los Broadcast
Receiver también los tenemos que registrar, pero esta vez tenemos dos formas de
hacerlo:
 Método Context.registerReceiver()
 declarándolos en el AndroidManifest.xml con la etiqueta <receiver>
Si registramos un broadcast receiver en el onResume() de una Activity, se debe
borrar en el onPause() de la misma Activity mediante el
método Context.unregisterReceiver() .
Nota: en el próximo apartado veremos el ciclo de vida de una Activity donde explicaremos los
diferentes estados por los que puede pasar y los métodos asociados.. Por ejemplo, los dos
que hemos citado en el párrafo anterior: método onPause(), para pasar a estado 'en pausa o
interrumpida' y método onResume(), para reanudarla.
Para iniciar un Broadcast Receiver podemos usar dos alternativas:
 Método Context.sendBroadcast() , si queremos iniciar un broadcast
'desordenado' (sin esperar nada a cambio, sería un modo de comunicación
hacia un lado)
 Método Context.sendOrderedBroadcast() , si queremos que por el contrario
sea 'ordenado' (lo que significa que los receptores de este broadcast
pueden devolver información como respuesta a ello)
2.3. Activity: creación y ciclo de vida
Tras presentar los componentes fundamentales de una Aplicación Android, vamos
a ver cómo podemos implementarlos utilizando el IDE Android Studio y en
concreto, nos centraremos en la creación de una Activy, de la que también
describiremos su ciclo de vida posterior.
Creación de una Activity
En el siguiente diagrama, vemos como es el proceso de implementación de un
nuevo componente dentro de un proyecto ya existente (pincha la imagen para ampliarla):
Si utilizamos como ejemplo la implementación de una nueva Activity en un
proyecto ya disponible, realizaríamos los siguientes pasos:
 Como se puede apreciar en el diagrama de arriba, pulsaremos con el
botón derecho del ratón sobre el packages del proyecto donde se
encuentran las clases del mismo.
 A continuación, seguimos la ruta New > Activity y seleccionamos la
opción Blank Activity que permitirá crear una plantilla con un diseño
básico en el proyecto (en las nuevas versiones de Android Studio
elegiríamos Empty Activity, que sería la opción similar a ésta).
 Si nos fijamos en la imagen de abajo, vemos la siguiente ventana que
nos aparecerá, con las distintas opciones (están numeradas de acuerdo a
como hemos marcado en la imagen):
o 1: nombre de Activity
o 2: nombre de layout
o 3: el título que se mostrará en la parte superior de la Activity
o 4: si se trata o no de la Activity que será lanzada al compilar el
proyecto
o 5: si hará uso de un Fragment
o 6: permite establecer herencia de otras clases ya implementadas
o 7: indicar el nombre del paquete al que pertenecerá
o 8: visualizar el resultado de la interfaz de usuario (situado a la
izquierda de las opciones de configuración).
Por último pulsaremos sobre "Finish" para crear una nueva Activity en el proyecto.
Ciclo de vida de una aplicación Android
Como explicamos en la anterior publicación, una Activity es un componente
principal de la interfaz gráfica de una aplicación en Android, y se asocia con una
ventana donde se define la interfaz de usuario para interaccionar con la aplicación.
Estas serán manejadas como una pila en el sistema, es decir, cuando una Activity
se inicia, ésta se posiciona al principio de la pila, y pasará a ser la Activity que
veamos en ese momento. Una Activity tiene esencialmente cuatro estados:
 Activa: si la Activity está en primer plano (si la estamos viendo
actualmente), se dice que está activa o ejecutándose.
 En pausa: si la Activity ha perdido el foco, pero sigue siendo visible (por
ejemplo, cuando se inicia otra Activity que no ocupa la pantalla entera), se
dice que está en pausa o detenida. Una Activity detenida sigue
permaneciendo en memoria pero puede ser 'matada' o interrumpida por el
sistema en condiciones de baja memoria.
 Parada: si la Activity deja de ser visible (por ejemplo, cuando se inicia
otra Activity que ocupe la pantalla entera), se dice que está parada. Aun
así sigue permaneciendo en memoria, aunque puede ser 'matada' por el
sistema en condiciones de baja memoria.
 Eliminada: si una Activity está pausada o parada, el sistema puede
eliminarla de memoria matando el proceso o mandándole la señal de que
finalice. Cuando vuelva a ser visible por el usuario, ésta debe ser
completamente reiniciada.
A nivel de código podríamos reflejarlo de la siguiente manera:
public class Activity extends ApplicationContext
{
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}
El siguiente diagrama describe de forma gráfica los distintos estados por los que puede pasar
una Activity:
Imagen de Android Developer, licencia Apache 2.0
2.4. Fichero AndroidManifest.xml
Continuando con los primeros pasos para la creación de una Aplicación Android,
vamos a describir el archivo AndroidManifest.xml, un fichero indispensable en un
proyecto Android que cada aplicación deberá contener (con ese mismo nombre) en
su directorio raíz.
Este archivo contendrá información esencial acerca de la App, por lo que el sistema
Android deberá acceder a él antes de compilar cualquier línea de código del proyecto. De
manera resumida, cumple las siguientes funciones:
 Establece el nombre del package de la aplicación, para identificar de
manera única a la aplicación.
 Permite definir los componentes de la aplicación, es decir, Activities,
Services, Content Providers etc., estableciendo qué clases
implementan cada componente.
 Determina que Activity será lanzada inicialmente.
 Declara el nivel mínimo de la API que Android requiere para la
aplicación.
 Se declaran los permisos que necesita la aplicación para realizar
determinadas tareas, cómo el acceso a contactos del teléfono o realizar
llamadas de teléfono, accediendo a zonas restringidas de la API e
interactuando con otras aplicaciones (ampliamos un poco este punto más
abajo),
A continuación mostramos la estructura general del archivo AndroidManifest.xml,
con los elementos que puede contener. Hemos incluido un breve comentario en
cada uno para dar una primera idea de su función.
<?xml version="1.0" encoding="utf-8"?>
<manifest> //Elemento raíz del fichero. Debe contener un elemento <application>
<uses-permission /> //Permisos que debe aceptar el usuario al instalar la App
<permission /> //Permiso de seguridad para limitar acceso a un componente o
funcionalidad específica
<permission-tree /> //Nombre base para un árbol de permisos (ej: com.academiaand
roid.proyecto.audio)
<permission-group /> //Nombre para un grupo lógico de permisos afines
<instrumentation /> //Permite monitorizar interacciones de la App con el sistema
<uses-sdk /> //Compatibilidad de la App con una ó más versiones Android (
nivel de APIs soportadas)
<uses-configuration /> //HW y SW específico que necesita la App (por ejemplo, un te
clado físico)
<uses-feature /> //HW o SW que utiliza la App (ej: bluetooth, cámara...)
<supports-screens /> //Tamaños de pantallas soportadas por la App
<compatible-screens /> //Configuraciones de pantallas compatibles con la App
<supports-gl-texture /> //Formatos de compresión de textura GL soportados
<application> //Declaración de la Aplicación
<activity> //Declaración de Activity
<intent-filter> //Especifica tipo de Intents a los que puede responder
<action />
<category />
<data />
</intent-filter>
<meta-data />
</activity>
<activity-alias> //Alias para la Activity
<intent-filter> . . . </intent-filter>
<meta-data />
</activity-alias>
<service> //Declaración de Servicio
<intent-filter> . . . </intent-filter>
<meta-data/>
</service>
<receiver> //Declaración de Broadcast Receiver
<intent-filter> . . . </intent-filter>
<meta-data />
</receiver>
<provider> //Declaración de Content Provider
<grant-uri-permission />
<meta-data />
<path-permission />
</provider>
<uses-library /> //Especifica librería compartida que debe ser enlazada
</application>
</manifest>
XML: este fichero AndroidManifest, al igual que veremos por ejemplo en los ficheros de
diseño, utiliza el formato XML. De forma simplificada se identifica a XML como un lenguaje
que estructura e identifica la información de un archivo en base a etiquetas. Es un lenguaje
cuyo código suele ser fácil de leer, lo que nos permite entender más o menos la estructura y
contenido del mismo, aún sin conocer todos los detalles del lenguaje.
En realidad XML es un meta-lenguaje, es decir, unas especificaciones que nos permiten
construir lenguajes de marcado basados en etiquetas. Por ejemplo, (X)HTML, que nos permite
identificar las partes de una página web, encerrándolas entre unas etiquetas de apertura y
cierre (título nivel 1: <h1>...</h1>, párrafo: <p>....</p>, enlace: <a href=....>...</a>, etc.).
Si quieres saber más sobre XML, en este tutorial hablamos sobre ello. Al final del mismo
tienes también enlaces a páginas donde lo explican, como ésta de la W3C.
En la siguiente lista se enumeran todos los elementos que pueden aparecer dentro
de un archivo AndroidManifest.xml. Hay que tener en cuenta que estos son los
únicos permitidos y que no podemos crear nuestros propios elementos o atributos.
Tienes una descripción detallada de cada uno de esos elementos en la web de Android
Developers si quieres profundizar en ellos
<action>
<activity>
<activity-alias>
<application>
<category>
<data>
<grant-uri-permission>
<instrumentation>
<intent-filter>
<manifest>
<meta-data>
<permission>
<permission-group>
<permission-tree>
<provider>
<receiver>
<service>
<supports-screens>
<uses-configuration>
<uses-feature>
<uses-library>
<uses-permission>
<uses-sdk>
Dentro del proyecto que describiremos en este tema, veremos un ejemplo de
archivo AndroidManifest.xml y comentaremos los elementos y atributos que
incluye.
Esos elementos y atributos implementados en el archivo XML, como pueden
ser el nombre de aplicación, el nombre del paquete, la versión mínima de SDK
soportada o la Activity que será lanzada, se generan de manera automática al
crear el proyecto. Si implementamos algún componente posterior, se irá
añadiendo igualmente a este fichero.
Permisos en AndroidManifest
Como comentamos al inicio, una de las funciones del archivo AndroidManifest.xml
es indicar los permisos que tiene la App. Cada aplicación que se ejecuta en
Android, lo hace desde un entorno limitado. Si desea acceder a recursos del
sistema o de otra aplicación, necesitará solicitar permisos de manera explícita, y
dependiendo del tipo de permiso, el sistema lo concederá de manera automática o
solicitará al usuario la aprobación de dicha solicitud.
Hasta la versión Android 6.0, la declaración de permisos de la App debía
hacerse previamente en el AndroidManifest.xml, antes de su instalación y ejecución
en el dispositivo. A partir de la versión Marshmallow, es posible declarar permisos
de una aplicación en tiempo de ejecución, simplificando en gran medida el proceso de
instalación de la aplicación.
En las siguientes líneas se muestra varios ejemplos de permisos que es posible
declarar:
android.permission.CALL_EMERGENCY_NUMBERS
android.permission.READ_OWNER_DATA
android.permission.SET_WALLPAPER
android.permission.DEVICE_POWER
y finalmente la sintaxis completa de la implementación de un ejemplo concreto,
en este caso el permiso para escribir en un almacenamiento externo, que se
deberá añadir directamente al archivo AndroidManifest.xml dentro del elemento
<manifest>:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="co
m.academiaandroid.interfazusuario">
<application
android:allowBackup="true" //si se tendrá en cuenta la aplicación al
realizar/restaurar un backup
android:icon="@mipmap/ic_launcher" //icono para lanzar la aplicación
android:label="@string/app_name" //etiqueta para la App, leíble por el usua
rio
android:supportsRtl="true" //soporte a layouts "derecha a izquierda (
right-to-left)
android:theme="@style/AppTheme"> //theme (estilo) para la aplicación
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- Permiso declarado para escritura en almacenamiento externo del dispositivo
-->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
</manifest>
En el apartado "Proyecto ejemplo" de este tema, cuando describimos su código, encontrarás
una explicación a la notación "@id/nombreElemento" como la que utilizamos
en android:icon="@mipmap/ic_launcher
2.5. Generación de APK y depuración
de aplicaciones
En este apartado veremos como generar un fichero apk con nuestra aplicación que podremos
distribuir e instalar en distintos dispositivos. También aprenderemos a depurar nuestras
aplicaciones en caso de que tengamos algún error que no seamos capaces de resolver.
Fichero APK
Para poder distribuir nuestra aplicación Android y que ésta pueda ser ejecutada,
debemos generar un APK, que no es más que un archivo compilado
ejecutable con extensión .apk
Este formato (una variante que cumple el mismo objetivo en Android que el
formato JAR (*)
para Java) es básicamente un fichero comprimido ZIP que empaqueta
los componentes del proyecto (Android Manifest, clases, recursos...) para que éstos
puedan ser desplegados como aplicación y ser ejecutada en un emulador Android
Nota (*) JAR: Java Archive; permite distribuir y ejecutar aplicaciones Java
El fichero en sí lo podemos abrir para ver sus componentes con un programa de compresión
de archivos como 7-Zip, WinRAR o similar.
Generar APK
Para generar el fichero a APK de nuestra aplicación tan sólo tenemos que dirigirnos al
menú Build de Android Studio y seleccionar la opción Build APK
Una vez
generado, aparecerá en la parte superior derecha de la ventana de Android Studio
un mensaje indicando que se ha generado el APK y un enlace para abrir una
ventana del navegador con la ruta del
fichero.
También podemos encontrarlo dirigiéndonos a la carpeta de nuestro proyecto y navegando
hasta la ruta "appbuildoutputsapk" , donde se irá actualizando cada vez que
compilemos nuestra aplicación.
Depuración de aplicaciones
En cualquier desarrollo, siempre llega un punto en el que nuestra aplicación no funciona de la
forma que esperamos o bien se cierra inesperadamente sin que sepamos por qué. En estos
casos es importante que sepamos encontrar el error lo antes posible de forma que podamos
seguir avanzando en el desarrollo.
Ya vimos en el primer tema del curso la pestaña LogCat en la que van
apareciendo los mensajes que lanza el sistema, incluyendo los errores. Sin
embargo, hay otra herramienta muy potente y que nos puede ser gran utilidad si
aprendemos a utilizarla: el depurador. El depurador nos permite detener la
ejecución de una aplicación en un punto concreto y evaluar en ese
momento el valor de las distintas variables y elementos de la
aplicación. De este modo, podremos ver si alguno de ellos tiene un valor extraño
que pueda estar provocando el error que buscamos. Lo primero que debemos
hacer es añadir un punto de interrupción (breakpoint) en nuestro código
fuente: este será el lugar donde se detendrá la ejecución del programa. Para
añadirlo, haremos clic con el botón izquierdo del ratón en la parte izquierda de la
linea de código que elijamos; veremos que aparece un circulo rojo, ésto nos indica
que hemos añadido un punto de interrupción en esa linea de código. Podemos
añadir tantos como
deseemos.
Para
ejecutar nuestra aplicación en modo depuración, pulsaremos el icono que hay
junto al de ejecución o utilizar la combinación de
teclas Mayusculas+F9 A continuación,
utilizaremos nuestra aplicación de forma normal. Cuando lleguemos al punto de
interrupción ésta se detendrá, y la interfaz de Android Studio, cambiará
mostrándonos el panel de
depuración.
El panel de depuración cuenta con varios elementos interesantes:
 En primer lugar, en la parte superior, encontramos una serie
de botones que nos permiten controlar la ejecución de nuestro código,
saltando de linea en linea, entrando en las funciones para evaluarlas, etc.
 También muy importante es el panel central denominado Variables, que
muestra todas las variables que existen en ese punto del código, así como
su valor. Podemos desplegarlas en el caso de que sean objetos para ver
cada uno de sus atributos. Estos valores irán actualizándose según nos
movamos por el código.
 Por último, a la derecha, encontramos un último panel, también muy útil,
denominado Watches. En él, podemos añadir cualquier variable o
expresión, y se evaluará su valor en ese momento. De este modo,
podemos por ejemplo adelantarnos, ejecutando un código antes de que el
programa llegue a ese punto, para obtener más información de cara a
encontrar posibles errores.
2.6. Proyecto ejemplo con dos
Activities y un Intent
Siguiendo con nuestros primeros pasos en la creación de una Aplicación Android con
el IDE Android Studio, vamos desarrollar un proyecto muy básico, al estilo del típico 'Hola
mundo' aunque con alguna funcionalidad adicional.
En esta App ejemplo, en vez de utilizar una sola activity que presente dicho mensaje,
permitiremos al usuario introducir un texto cualquiera, en un campo EditText de la primera
activity,y pulsando un botón (control
tipo Button) podrá enviar dicho mensaje como parámetro a una segunda activity,
utilizando el componente Intent .
Esta sencilla aplicación, que describiremos también en un video posterior, estaría formada por
las dos pantallas básicas que mostramos a continuación:
Curso Android  2021
Elementos de la aplicación
Vamos a enumerar los elementos necesarios para el desarrollo de este proyecto que
denominado "HolaMundo":
 Clase MainActivity , que herede de la clase base Activity , y que definirá la
lógica del parámetro que se enviará a la siguiente pantalla.
 Clase MainActivity2 , que herede de la clase base Activity , encargada de
mostrar el texto introducido en la pantalla principal.
 Layout main_activity.xml , formado por un control EditText , que permitirá al
usuario introducir texto, y un control Button para enviar dicho texto a la
siguiente Activity.
 Layout main_activity2.xml , formado por un control TextView para mostrar el
texto introducido por el usuario.
Estructura del proyecto
En la siguiente imagen, se puede apreciar cómo quedaría la estructura de elementos que
componen el proyecto que vamos a describir, y que hemos desarrollado con la versión
1.5.1 de Android Studio:
Descripción del código fuente
Vamos a explicar de forma detallada el código que interviene en el envío de información entre
dos activities. Puedes descargar el código completo del proyecto en el apartado
siguiente del curso.
Nota: aunque lo explicaremos en más detalle en el próximo tema, al tratar del diseño de
interfaces de usuarios, comentar brevemente que un layout define la estructura visual
de una interfaz de usuario (UI), como puede ser la UI para una Activity o Widget de
aplicación. En Android los definimos en ficheros XML (igual formato que el que hemos visto
en el fichero AndroidManifest.xml, donde describimos los elementos y sus propiedades
delimitándolos mediante etiquetas).
El objetivo principal de este proyecto ejemplo es la creación y uso de las Activities y
el componente Intent, por lo que aunque introduciremos algunos elementos del
interfaz de usuario (ficheros de layout, componentes como un campo de texto o
un botón) no nos detendremos en explicarlos, dejándolo para el siguiente
tema. Una vez hayas visto dicho módulo, puedes volver para revisar de nuevo
este proyecto y de esta forma comprender mejor la parte del interfaz de
usuario. .
HolaMundoappsrcmainjavacomacademiaandroidholamundoMainAc
tivity.class
Activity que presenta la particularidad de controlar la pulsación del botón definido a nivel de
layout, y que enviará el texto introducido a la siguiente pantalla:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
Se declaran dos variables de tipo EditText y Button a nivel de clase:
private EditText edNombre;
private Button btnEnviar;
El método onCreate() será llamado cuando se inicie la Activity , por lo que todo lo situado
en su interior se inicializará al llamar a dicha Activity :
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
En la siguiente línea se establecerá la referencia a qué layout (interfaz de usuario) se asocia a
esta Activity :
setContentView(R.layout.main_activity);
Se asignan las referencias a los controles EditText y Button , definidos a nivel de layout, con
sus respectivas variables:
edNombre = (EditText)findViewById(R.id.edNombre);
btnEnviar = (Button)findViewById(R.id.btnEnviar);
Nota: con el método findViewById() referenciamos objetos con un determinado identificativo
(id) que le hayamos asignado. Ver nota un poco más abajo sobre la identificación de
elementos y el fichero R.java.
Se invoca al método setOnClickListener() , encargado de controlar la pulsación de la vista
asociada al botón:
btnEnviar.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Veremos la detección de eventos en más detalle en el tema próximo
Previamente a la instanciación de la clase Intent , será necesario comprobar que el
campo EditText no esté vacío:
if(!edNombre.getText().toString().equals(""))
{
A continuación, se instancia la clase Intent , pasándole como parámetros de entrada el
contexto (en este caso la Activity actual) y la Activity de destino:
Intent intent = new Intent(MainActivity.this,MainActivity2.class)
;
Se invoca al método putExtra() , que almacenará el valor introducido en el campo de texto
por clave/valor (clave->"nombre" / valor -> edNombre.getText().toString() ), para
finalmente llamar al método startActivity() que recibe como parámetro la instancia creada,
y que lanzará la Activity establecida como segundo parámetro:
intent.putExtra("nombre",edNombre.getText().toString());
startActivity(intent);
}else
{
En el supuesto de no introducir ningún valor en la caja de texto, se mostrará un mensaje
emergente del tipo "Debe indicar los datos requeridos":
Toast.makeText(MainActivity.this, "Debe indicar los datos requeridos"
, Toast.LENGTH_LONG).show();
}
}
});
}
}
Toast: son las notificaciones más sencillas que podemos usar en Android. Consisten en
mensajes de texto que se muestran en la pantalla durante un tiempo y desaparecen
automáticamente transcurrido dicho periodo.
Para crear un mensaje de estos, usaremos la clase Toast. Esta clase dispone de un método
estático que nos facilitará la creación de un mensaje, éste es makeText() . Este método
recibe como parámetros el contexto de la activity, el mensaje a mostrar y la duración del
periodo de tiempo que permanecerá visible (admite dos
valores: Toast.LENGTH_SHORT ó Toast.LENGTH_LONG, según queramos que sea
un tiempo corto o largo, respectivamente). Una vez creado el texto, ya solo queda mostrarlo al
usuario, para ello llamamos al método show() de la clase Toast.
HolaMundoappsrcmainjavacomacademiaandroidholamundoMainAc
tivity2.class
Activity encargada de recibir el parámetro enviado por la pantalla anterior. Como se puede
apreciar, cada clase utilizada en la Activity deberá ser importada previamente para poder
acceder a sus métodos y propiedades:
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
Clase MainActivity2 , que hereda de la clase base Activity , asociada a una ventana
de la aplicación:
public class MainActivity2 extends Activity {
Se declaran dos variables de tipo Bundle y TextView a nivel de clase:
private Bundle bundle;
private TextView tvSaludo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity2);
A continuación, se asigna la referencia del control TextView definido a nivel de layout, con la
variable de tipo TextView :
tvSaludo = (TextView)findViewById(R.id.tvSaludo);
Posteriormente, se asocia a la variable de tipo Bundle , los datos recibidos de
la Activity anterior:
bundle = getIntent().getExtras();
String saludo = bundle.getString("nombre");
Finalmente, se invocará al método append() de la variable de tipo TextView , para mostrar el
texto por pantalla:
tvSaludo.append(" " + saludo + "!!!!");
}
}
HolaMundoappsrcmainreslayoutmain_activity.xml
Layout main_activity.xml que define un control EditText (campo de texto editable) donde el
usuario podrá introducir texto, y un control Button , que permitirá al usuario interaccionar con
la aplicación enviando información a la siguiente Activity:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nombre"
android:id="@+id/tvNombre"
android:layout_alignBottom="@+id/edNombre"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edNombre"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/tvNombre"
android:layout_marginLeft="76dp"
android:layout_marginStart="76dp"
android:inputType="text" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/enviar"
android:id="@+id/btnEnviar"
android:layout_below="@+id/tvNombre"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="34dp" />
</RelativeLayout>
Identificación: habrás visto que empleamos en estos ficheros la notación '@' y '@+id'. Se
trata de un atributo muy importante, android:id, que debemos tener presente siempre,
tanto para los layouts como para los elementos gráficos o cadenas de texto que queramos
referenciar. Mediante este atributo, podremos identificar a cada elemento para
luego acceder a ellos desde el código o para posicionarlos de manera
relativa como veremos en el próximo tema o modificar los textos que aparecen en ellos. Es
por tanto muy recomendable asignarles siempre un identificador (id).
Para asignarles un id nuevo, usaremos la siguiente
sintaxis: android:id=”@+id/nombreElemento” , en la que hemos creado un nuevo id
llamado nombreElemento. Si en cambio queremos referirnos a un id ya creado, el carácter
"+” sobra, quedando @id/nombreElemento .
Todos los id que creemos, se añaden automáticamente a un fichero llamado R.java (no
debemos editarlo nunca, se autogenera solo), por lo que para acceder a un id tenemos que
hacer referencia a dicha clase mediante R.id.nombre_id, como vimos por ejemplo al
asignar las referencias a los controles de campo de texto: edNombre =
(EditText)findViewById(R.id.edNombre); o del botón: btnEnviar =
(Button)findViewById(R.id.btnEnviar);
HolaMundoappsrcmainreslayoutmain_activity2.xml
Layout main_activity2.xml que define un control TextView (vista de texto) que recogerá el
valor introducido por el usuario en la pantalla principal:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/saludo"
android:id="@+id/tvSaludo"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
HolaMundoappsrcmainAndroidManifest.xml
Archivo AndroidManifest.xml, que define los aspectos generales del proyecto, y dónde se
diferencian las siguientes partes:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.academiaandroid.holamundo">
<application
En las siguientes líneas se definen si se permiten las copias de seguridad, el icono que se
mostrará en el launcher del dispositivo, el nombre de la aplicación, si soporta la escritura de
derecha a izquierda y el tema de la aplicación:
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
Se implementa la Activity inicial, indicando en su diferentes atributos el nombre de la clase y
de la ventana, y el tema a utilizar:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
Permite definir que Activity será lanzada cuando se inicie la aplicación:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Se define una segunda Activity también con los atributos de nombre de la ventana y tema;
<activity
android:name=".MainActivity2"
android:label="@string/title_activity_main2"
android:theme="@style/AppTheme.NoActionBar">
</activity>
</application>
</manifest>
3.1. Introducción y objetivos
En este tema vamos a tratar la creación de interfaces de usuario. (También nos
referiremos a ellos como UI ó User interfaces).
A lo largo de sus apartados describiremos los principales controles para el diseño
y construcción de interfaces de usuario, veremos cómo referenciarlos a nivel
de código, para finalizar creando nuestra propia interfaz de usuario desde las
clases Java implementadas.
Los objetivos de aprendizaje de este módulo serán:
 Conocer e implementar controles básicos para el diseño de
interfaces de usuario.
 Saber referenciar los controles definidos a nivel visual con el
código de la aplicación.
 Comprender la estructura global para la construcción de interfaces
sólidas.
 Poder implementar acciones que permitan al usuario interaccionar
con la aplicación.
3.2. Panel de diseño de UI de
Android Studio. Controles básicos
En este apartado nos encargaremos de describir los controles básicos disponibles
dentro del diseñador de interfaces de usuario que proporciona Android
Studio al seleccionar un layout de nuestro proyecto.
Layout: es el esquema de distribución de los elementos dentro un diseño (es un
término que podría traducir por 'plano' o 'disposición'). En él se sustentan los
diferentes elementos de la interfaz de usuario, definiéndose la distribución,
posición y dimensiones de dichos elementos.
En Android tenemos diversas opciones de layout disponibles para construir
nuestras UI: diseño tabular, lineal, de rejilla ó cuadrícula (grid),...
Veremos todo ésto en más detalle a lo largo de este tema.
Como se puede apreciar en la siguiente imagen, tras seleccionar un layout del
proyecto, se mostraría la siguiente ventana, denominada "Palette", con los
diferentes layouts y controles que podrán añadirse a la interfaz de usuario:
Nota: esta ventana puedes ampliarla, como cualquier otra en Android Studio deslizando su
linea delimitadora, o eligiendo en la configuración (icono de rueda dentada, arriba a la
derecha) otro modo de presentación: flotante,...
Sin entrar a describir las opciones de Layouts, Expert y Custom (de mayor complejidad), se
podrán observar controles bien delimitados en función de sus características.
Para poder añadir cualquiera de los elementos de la imagen anterior, bastará con
seleccionar el control elegido de la ventana "Palette" e indicar en qué posición
del layout se desea establecer:
Controles de entrada
Nos detendremos en aquellos controles que nos proporcionan mayor funcionalidad para
la interacción con el usuario, como es el caso de los controles de entrada, y que
podemos definir como componentes interactivos en la interfaz de usuario de la aplicación,
como vemos en esta imagen:
Android ofrece una amplia variedad de controles que se pueden utilizar en la interfaz de
usuario, tales como botones, campos de texto, barras de búsqueda, casillas de verificación,
botones de zoom, botones de conmutación, y muchos más.
Button
Un Button consiste en representación de texto o un icono (o ambas cosas) que se
comunica cuando el usuario lo toca, produciendo una acción sobre la aplicación.
Dependiendo de si desea un botón con texto, un icono, o ambos, puedes crear el diseño del
botón de tres maneras:
Con el texto, usando la clase Button:
<Button
android:layout_width = "wrap_content" //ancho del botón
android:layout_height = "wrap_content" //altura del botón
android:text = "@string/button_text" //texto del botón
... />
XML: verás que los ficheros que definen los componentes y los layouts están en formato
XML. Si tienes dudas sobre este formato, consulta la nota sobre XML que incluíamos en el
apartado 2.4 del fichero AndroidManifest
Atributos: los atributos de anchura y altura
( android:layout_width y android:layout_height) tienen en este caso el valor
'wrap_content' que les indica que tomen la dimensión de su contenido.
Puedes consultar lo que significa cualquier atributo que aparezca en estos ficheros
XML (notación: " android:nombreAtributo”) en la referencia oficial de la clase
R.attr. Hay mucha información (en inglés) y puede ser a veces complicado
localizarlo, aunque puedes utilizar una búsqueda en la página con Ctrl+F y el
nombre del atributo (sin el prefijo 'android:')
Con un icono, utilizando la clase ImageButton
<ImageButton
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:src = "@drawable/button_icon" //fuente (source) donde está la imagen del i
cono
... />
Con texto y un icono, utilizando la clase Button con el atributo android:drawableLeft =
"@drawable/button_icon" :
<Button
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "@string/button_text"
android:drawableLeft = "@drawable/button_icon"
... />
Text Field
Un Text Field o campo de texto permite al usuario escribir texto en su aplicación.
Puede ser una sola línea o varias líneas. Al tocar un campo de texto, se colocará el cursor
mostrando automáticamente el teclado. Además de escribir, un text field permite otras
actividades, como la selección de texto (cortar, copiar, pegar) y consulta de información a
través de auto-completado.
Puedes añadir un Text Field a un layout mediante el control EditText, a través de
su elemento <EditText> para el diseño XML o mediante su objeto EditText a nivel
de código.
Ejemplo de EditText para introducir un correo electrónico:
<EditText
android:id = "@+id/email_address"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:hint = "@string/email_hint"
android:inputType = "textEmailAddress" />
En este caso, vemos el valor 'fill-parent' que indica que tome la dimensión del elemento padre,
es decir, en el que esté incluido este Text Field.
Checkbox
Un CheckBox permite al usuario seleccionar una o más opciones de un conjunto. Por
lo general, se debe presentar cada opción de CheckBox en una lista vertical. Al heredar
indirectamente de un TextView, se le puede asignar cualquiera de sus atributos.
Ejemplo de un CheckBox a través del archivo XML:
<? Xml version = "1.0" encoding = "utf-8" ?>
<LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" >
<CheckBox android:id = "@+id/checkbox_meat"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "@string/meat"
android:onClick = "onCheckboxClicked" />
</LinearLayout>
Radio Button
Los RadioButtons permiten al usuario seleccionar una opción de un conjunto.
Este control será de gran utilidad cuando se deseen establecer varias opciones de
selección pero sólo será posible mantener seleccionada una de ellas de forma
obligatoria. Al heredar indirectamente de un TextView, se le puede asignar
cualquiera de sus atributos.
Ejemplo de dos RadioButtons agrupados en un RadioGroup:
<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_pirates"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pirates"
android:onClick="onRadioButtonClicked"/>
<RadioButton android:id="@+id/radio_ninjas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ninjas"
android:onClick="onRadioButtonClicked"/>
</RadioGroup>
Toggle Button
Un Toggle Button permite al usuario cambiar un ajuste entre dos estados. En la
imagen de abajo tienes un ejemplo:
Es posible añadir un Toogle Button a su diseño con el objeto ToggleButton.
Android 4.0 (API de nivel 14) introduce otro tipo de botón llamado Switch (objeto), que
proporciona un control deslizante. Vemos un ejemplo en la siguiente imagen:
Si necesitamos cambiar el estado de un botón, es posible utilizar los
métodos CompoundButton.setChecked() o CompoundButton.toggle() .
Ejemplo de diseño de un Toogle Button:
<ToggleButton
android:id="@+id/toggle_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:textOff="@string/text_off"
android:textOn="@string/text_on" />
Spinner
Un Spinner proporciona una manera rápida de seleccionar un valor de un conjunto. En
su estado por defecto, un Spinner muestra su valor seleccionado en ese momento. Al tocar el
Spinner muestra un menú desplegable con todos los demás valores disponibles, de
los cuales el usuario puede seleccionar uno nuevo.
Se puede agregar un Spinner a un layout con el objeto Spinner, y a través
del elemento en su diseño XML.
<Spinner
android:id="@+id/planets_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
Picker
Control para que el usuario escoja una fecha para su uso dentro del proyecto. Cada picker
proporciona controles para la selección de cada parte del tiempo (horas, minutos, AM / PM) o
fecha (mes, día, año). El uso de estos recolectores garantiza que los usuarios pueden elegir
una hora o fecha que sea válida, el formato correcto, y se ajusta a la configuración regional del
usuario.
TextView
Además de los controles de entrada que se han expuesto con anterioridad, es conveniente
describir también el control TextView.
Este control se usa para mostrar texto al usuario.
Se le pueden asignar diferentes atributos (aparte de las ya conocidas
como android:layout_width y android:layout_height para definir la anchura y altura) como
pueden ser:
 Tamaño de fuente: android:textSize (recordad usad la medida sp en este
caso)
 Color de fuente: android:textColor
 Un fondo personalizado: android:background
 etc..
Para definir un texto se usa el atributo: android:text :
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/some_text" />
Si queremos cambiar este texto desde código, tenemos que hacerlo de la siguiente manera:
TextView textView = (TextView) findViewById(R.id.text_view);
textView.setText("Cambio de texto TextView por esta frase.");
Se puede ver que hemos usado el método findViewById() que ya presentamos en el
proyecto ejemplo del anterior tema . Mediante este método referenciamos
el objeto TextView creado en la clase Java con el id del control que hemos definido
en el XML. Todos los id que creemos, se añaden automáticamente al fichero R.java, por
lo que para acceder a un id tenemos que hacer referencia a
dicha clase mediante R.id.nombre_id . Y si lo que queremos es acceder al texto que
contiene, haremos lo siguiente:
String texto = textView.getText().toString();
Nota: imágenes de controles de Android Developer con licencia Creative
Commons Attribution 2.5. En el apartado 'recursos adicionales' , tienes
un documento recopilatorio de controles comunes de esa misma web.
3.3. Views y Layouts
En este apartado describiremos los diseños o layouts más utilizados para
una interfaz de usuario en una Aplicación Android. También
explicaremos cómo crearlos, incluyendo algunos elementos, como campos de
texto editables y botones, con un sencillo ejemplo práctico. Para diseñar
interfaces de usuario en Android utilizamos una capa (llamada layout),
descrita mediante un fichero XML, sobre la que se dispondrán los diferentes
elementos gráficos que componen dicho interfaz. Todos estos componentes
heredan directa o indirectamente de la clase View.
Veamos la definición de los términos View y ViewGroup, necesarios para
comprender el funcionamiento de la interfaz gráfica en Android:
 View (o Vista). Esta clase es básica para la creación de todos los
componentes usados en la interfaz. Una View ocupa un área rectangular
en la pantalla y es el responsable de dibujar los componentes y manejar
los eventos que definamos sobre ellos, o dicho de una forma más simple,
dibuja los componentes en la pantalla con los que el usuario puede
interaccionar. Es la clase base para los widgets, que son Views
'preconstruidas' que vienen incluidas en la plataforma Android, como
los botones, campos de textos, check boxes, radio buttons, etc.
 ViewGroup (o Grupo de Vista). Hereda directamente de View y se usa
para, como su nombre indica, contener y controlar la lista de Views y de
otros ViewGroups. Es la clase base para los Layouts, mediante los cuales
podemos diseñar una estructura para un conjunto de Views.
El fichero XML que generamos (por ejemplo activity_main.xml) se ubica en la
carpeta res/layout, y se carga(*)
a través del método setContentView() en el
método onCreate() de la activity, como veremos en un ejemplo práctico que
desarrollaremos en una publicación posterior.
Nota(*): a esta acción del método setContentView también se le suele denominar 'inflar' una
vista (view). Más detalle en estas explicaciones algo más avanzadas (en inglés).
Tenemos dos grandes ventajas al utilizar un fichero XML externo para declarar
la UI:
 Nos permite separar mejor la presentación de nuestra Aplicación
Android del código que controla su comportamiento. Esto nos facilita
realizar cambios o adaptaciones de dicha interfaz sin necesidad de
modificar el código y recompilar de nuevo, pudiendo crear layouts XML por
ejemplo para distintas orientaciones o tamaños de pantalla.
 Es más fácil visualizar y entender la estructura del layout en un
fichero XML que podemos leer sin mucha dificultad. Esto nos facilita
también las tareas de depuración.
En cualquier caso, también es posible construir la interfaz de usuario
utilizando únicamente código. Lo veremos también en ese proyecto ejemplo
que desarrollaremos más adelante, creando dos versiones del mismo interfaz, uno
usando fichero XML y otro solo basado en código..
Antes de empezar a describir distintos tipos de layouts y algunos de los elementos que
podremos agregarle (TextView, EditText, Button) utilizándolos en un ejemplo de interfaz que
realizaremos en cada uno de esos layouts, vamos a mencionar dos aspectos importantes:
Identificación
Ya explicamos en el proyecto ejemplo del tema anterior que hay un atributo muy
importante, android:id, que debemos tener presente siempre, tanto para los Layouts como
para los elementos gráficos. Mediante este atributo, podremos identificar a cada
elemento para luego acceder a ellos desde el código o para posicionarlos de
manera relativa como veremos en el RelativeLayout. Es por tanto muy
recomendable asignarles siempre un identificador (id).
Para asignarles un id nuevo, usaremos la siguiente
sintaxis: android:id=”@+id/botonaceptar” , en la que hemos creado un nuevo id
llamado botonaceptar. Si en cambio queremos referirnos a un id ya creado, el carácter "+”
sobra, quedando @id/boton_aceptar
Unidades de medidas
Otra consideración a tener muy en cuenta es que, al existir tanta diversidad de dispositivos
Android, es conveniente usar siempre medidas relativas al tamaño de
pantalla de cada uno. Esto lo podemos hacer usando:
 La medida dip (density-independent pixel ó dp, que al caso es la misma),
recomendada para especificar el tamaño de los views en nuestro layout
(siendo 160dp el equivalente a una pulgada (2,54 cm) de pantalla física)
 La medida sp (scaled-independent pixel), similar a dp y recomendada
para definir tamaños de fuentes.
Layout
Los Layouts son los elementos sobre los cuales se sustentan los
diferentes componentes de la interfaz de usuario, y controlan la
distribución, la posición y las dimensiones de dichos componentes. Es decir,
un layout define la estructura o diseño del UI. Para poder implementar cualquiera
de estos elementos para la distribución visual de la aplicación, bastará con
seleccionarla en la ventana "Palette", y añadirlo al árbol de componentes en la
ventana "Design". A continuación describiremos diferentes tipos de Layouts muy
comunes, con un ejemplo simple de diseño basado en cada uno.
FrameLayout
Es el más simple de todos. En él, todos los elementos se alinean teniendo en
cuenta la esquina superior izquierda de la pantalla, no pudiendo ser
ubicados en otro lugar, por lo que se colocarían unos encima de otros tapando
completa o parcialmente a los demás, a menos que el nuevo elemento sea
transparente. Por esta razón, se usa normalmente para mostrar un único
elemento, ya que puede resultar difícil organizar la posición de los elementos, o
bien una serie animada de imágenes donde cada una se va posicionando sobre la
anterior. Los elementos incluidos en este layout han de tener los
atributos android:layout_width y android:layout_height , que podrán tomar los
valores:
 match_parent (fill_parent) si lo que se quiere es que se tome la
dimensión completa del padre
 wrap_content, si se desea que tome la dimensión de su contenido.
A partir de la versión 8 de la API de Android, el valor fill_parent fue renombrado a
match_parent, por lo que aún nos podemos encontrar con uno u otro. Se permiten ambos,
aunque se recomienda match_parent.
Si queremos posicionar los elementos de otra forma, deberíamos de "jugar” con los
atributos android:layout_gravity (especifica cómo la vista hijo (child view) debe
posicionarse en su contenedor) y con las destinadas a controlar los márgenes y alineaciones,
como android:layout_marginTop , android:layout_marginLeft , android:layout_alignParentLe
ft , etc...
Veamos un ejemplo de cómo quedaría una interfaz con FrameLayout:
y del fichero XML que lo describe, donde vemos cómo se definen los diferentes
componentes: TextView ("Datos del curso"), tres EditText ("Nombre",
"Duración", "Curso") y un Button (botón "Enviar"):
Este fichero XML es generado automáticamente por Android Studio al utilizar su editor visual
de creación de interfaces.Si alguna vez has creado páginas Web con un
editor WYSIWYG tipo KompoZer o DreamWeaver, es algo similar: compones gráficamente la
página y se genera el código HTML acorde a esos elementos y disposición.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.Main2Activity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Datos del curso:"
android:id="@+id/textView"
android:textStyle="bold"
android:layout_row="0"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp" />
<EditText
android:layout_width="159dp"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:hint="Nombre"
android:layout_row="1"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_gravity="left|center_vertical" />
<EditText
android:layout_width="157dp"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/editText3"
android:hint="Temario"
android:layout_row="3"
android:layout_below="@+id/editText2"
android:layout_alignLeft="@+id/editText2"
android:layout_alignStart="@+id/editText2"
android:layout_gravity="right|center_vertical" />
<EditText
android:layout_width="165dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/editText2"
android:hint="Duración"
android:layout_row="2"
android:layout_below="@+id/editText"
android:layout_alignLeft="@+id/editText"
android:layout_alignStart="@+id/editText"
android:layout_gravity="center" />
<Button
android:layout_width="141dp"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/button"
android:layout_row="4"
android:layout_alignParentBottom="true"
android:layout_alignRight="@+id/editText3"
android:layout_alignEnd="@+id/editText3"
android:layout_marginBottom="45dp"
android:layout_gravity="right|bottom" />
</FrameLayout>
LinearLayout
Este layout alinea los elementos en una única dirección, que puede
ser vertical u horizontal, dependiendo del valor que le demos al
atributo android:orientation . Todos los elementos aparecerán uno detrás de otro, sin
solaparse entre ellos, como ocurría con el FrameLayout.
El LinearLayout respeta los márgenes entre los elementos hijos y su gravedad dentro de la
pantalla (ésta puede ser a la derecha, a la izquierda o en el centro).
En este layout, al igual que en el anterior, los elementos hijos deben establecer sus
atributos android:layout_height y android:layout_width para determinar sus dimensiones
dentro del layout, aunque en este caso dispondremos de otro atributo
llamado android:layout_weight . Este atributo permite que un elemento se expanda para
llenar cualquier espacio que quede libre. Por defecto este valor es 0, es decir, no se expande.
Pongamos un ejemplo. Si agregamos dos cuadros de texto, según los valores que pongamos
a este atributo, tendremos:
 Si a uno se le da el atributo de android:layout_weight=”1” , sucede que entre
los dos cuadros de texto se ocupa toda la pantalla, uno de ellos
permanecerá en su tamaño normal y al que le hemos asignado el
atributo android:layout_weight ocupará el resto de la pantalla.
 Si le hubiéramos asignado a los dos este atributo igual a 1, cada uno
ocuparía la mitad de la pantalla.
 Si le hubiéramos dado a uno el valor 2 y al otro le hubiéramos dado el
valor 1, entre los dos ocuparían también toda la pantalla pero uno de ellos
tendrá el doble de altura/anchura que el otro.
El layout genérico creado con un LinearLayout tendría este diseño:
Ahora vamos a realizar el mismo ejemplo que hicimos en el layout anterior (TableLayout) en
este caso con un LinearLayout con orientación horizontal:
y el fichero XML que lo describe:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.Main2Activity"
android:orientation="horizontal"
android:gravity="top">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Datos del curso:"
android:id="@+id/textView"
android:textStyle="bold"
android:layout_row="1"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:layout_column="0" />
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:hint="Nombre"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_column="0"
android:layout_row="2" />
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/editText2"
android:hint="Duración"
android:layout_below="@+id/editText"
android:layout_alignLeft="@+id/editText"
android:layout_alignStart="@+id/editText"
android:layout_column="0"
android:layout_row="3" />
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/editText3"
android:hint="Temario"
android:layout_below="@+id/editText2"
android:layout_alignLeft="@+id/editText2"
android:layout_alignStart="@+id/editText2"
android:layout_column="0"
android:layout_row="4" />
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/button"
android:layout_row="23"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/editText"
android:layout_toEndOf="@+id/editText"
android:layout_column="0" />
</LinearLayout>
TableLayout
En este layout, los elementos hijos se distribuyen de forma tabular, como si de
una tabla se tratara, definiendo las filas y columnas necesarias, y la posición de
cada elemento dentro de la tabla. Para definir una fila, se usa el
objeto TableRow, y dentro de éste se van agregando los elementos que
compondrá la fila, sin necesidad de definir un objeto columna. De este modo, la
tabla vendrá definida por tantas filas como objetos TableRow hayamos insertado, y
tantas columnas como elementos que hayamos insertado en cada TableRow.
Vemos un diseño genérico, con la disposición de los elementos en este formato de tabla:
Ahora veamos el ejemplo que estamos utilizando en los otros layouts, con controles ya
implementados en un LayoutTable:
El fichero XML que describiría este ejemplo sería:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.Main2Activity"
android:gravity="top">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Datos del curso:"
android:id="@+id/textView"
android:textStyle="bold"
android:layout_row="1"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:layout_column="0" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:hint="Nombre"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_column="0"
android:layout_row="2" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/editText2"
android:hint="Duración"
android:layout_below="@+id/editText"
android:layout_alignLeft="@+id/editText"
android:layout_alignStart="@+id/editText"
android:layout_column="0"
android:layout_row="3" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/editText3"
android:hint="Temario"
android:layout_below="@+id/editText2"
android:layout_alignLeft="@+id/editText2"
android:layout_alignStart="@+id/editText2"
android:layout_column="0"
android:layout_row="4" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/button"
android:layout_row="23"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/editText"
android:layout_toEndOf="@+id/editText"
android:layout_column="0" />
</TableRow>
</TableLayout>
RelativeLayout
Este layout permite que los elementos se dispongan en la pantalla de forma
relativa al elemento padre o a cualquier otro elemento agregado al layout,
por lo tanto, podríamos hacer cosas como alinear dos elementos a la derecha, o
crear uno debajo del otro, centrarlos en la pantalla, a la izquierda, etc. Veamos
también un ejemplo de uso de este layout, usando los mismos elementos que en
los casos anteriores.
y el fichero XML correspondiente:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.Main2Activity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Datos del curso:"
android:id="@+id/textView"
android:textStyle="bold"
android:layout_row="0"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp" />
<EditText
android:layout_width="159dp"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:hint="Nombre"
android:layout_row="1"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_gravity="left|center_vertical" />
<EditText
android:layout_width="165dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/editText2"
android:hint="Duración"
android:layout_row="2"
android:layout_below="@+id/editText"
android:layout_alignLeft="@+id/editText"
android:layout_alignStart="@+id/editText"
android:layout_gravity="center" />
<EditText
android:layout_width="157dp"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/editText3"
android:hint="Temario"
android:layout_row="3"
android:layout_below="@+id/editText2"
android:layout_alignLeft="@+id/editText2"
android:layout_alignStart="@+id/editText2"
android:layout_gravity="right|center_vertical" />
<Button
android:layout_width="141dp"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/button"
android:layout_row="4"
android:layout_marginBottom="45dp"
android:layout_gravity="right|bottom"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/editText"
android:layout_toEndOf="@+id/editText" />
</RelativeLayout>
GridLayout
Layout que define un diseño situando a sus hijos en una forma de rejilla rectangular.
Dicho grid o rejilla se compone de un conjunto de líneas que separan el área de
visualización de las celdas. Las líneas de cuadrícula son referenciadas por índices. Un
grid con N columnas tiene n + 1 índices del grid que van de 0 a N, ambos inclusive.
En el siguiente ejemplo, puedes comprobar cómo quedaría esta forma de distribución de los
controles:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.Main2Activity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Datos del curso:"
android:id="@+id/textView"
android:textStyle="bold"
android:layout_row="1"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:layout_column="0" />
<EditText
android:layout_width="159dp"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:hint="Nombre"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_gravity="left|center_vertical"
android:layout_column="0"
android:layout_row="2" />
<EditText
android:layout_width="165dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/editText2"
android:hint="Duración"
android:layout_below="@+id/editText"
android:layout_alignLeft="@+id/editText"
android:layout_alignStart="@+id/editText"
android:layout_gravity="left|center"
android:layout_column="0"
android:layout_row="3" />
<EditText
android:layout_width="165dp"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/editText3"
android:hint="Temario"
android:layout_below="@+id/editText2"
android:layout_alignLeft="@+id/editText2"
android:layout_alignStart="@+id/editText2"
android:layout_gravity="left|center_vertical"
android:layout_column="0"
android:layout_row="4" />
<Button
android:layout_width="141dp"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/button"
android:layout_row="23"
android:layout_marginBottom="45dp"
android:layout_gravity="left|bottom"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/editText"
android:layout_toEndOf="@+id/editText"
android:layout_column="0" />
</GridLayout>
Layouts para contenido dinámico
Cuando el contenido que mostramos en el layout no esta predeterminado y se
genera dinámicamente, por ejemplo como resultado de una consulta a una base
de datos, podemos utilizar un adaptador que hace de intermediario entre el layout
y el contenido, insertando éste último en formas de vistas en el layout. Vemos dos
ViewGroups que utilizan esta técnica que nos aparecen en el Panel de Diseño de
Android Studio en la sección 'Containers' (contenedores):
ListView
Un ListView es un ViewGroup que muestra una lista de elementos
desplazables. Los elementos o items de la lista se insertan automáticamente en
ella utilizando un adaptador que extrae el contenido de una fuente tal como
una matriz o una consulta a una base de datos y convierte cada item en una
vista que se coloca en la lista.
GridView
Un GridView es un ViewGroup que muestra los elementos en una rejilla de dos
dimensiones desplazable. Los elementos de cada cuadrícula
se insertan automáticamente usando un ListAdapter .
Avanzado:
Para los que quieran profundizar en este tema, más allá del curso, en nuestra web de
Academia Android desarrollamos en unas series de publicaciones dedicada a controles de
selección en una UI, un proyecto ejemplo de implementación de un ListView y un
GridView, extrayendo datos de una base de datos y la creación de una ListView
personalizada
En esa misma web, dispones también de una introducción a Material Design, las
especificaciones de diseño que lanzó Google a partir de Android 5.0 Lollipop. Son
recomendaciones y pautas para crear Apps con un aspecto visual más consistente y unificado,
tratando de mejorar la experiencia de usuario.
Créditos: diagramas de layouts de Android Developer con licencia Creative
Commons Attribution 2.5
.4 Detección de eventos en la
interfaz de usuario
Tras describir cómo crear distintos tipos de layouts (diseños) para una interfaz de
usuario en una Aplicación Android, veremos cómo hacer
posible la interacción del usuario con los elementos de esa interfaz(botones,
campos de texto,...) utilizando la pantalla táctil o las teclas de navegación.
Dentro de las posibilidades que proporciona Android para controlar los eventos de
interacción del usuario con la interfaz gráfica, veremos aquellos encargados
de detectar cuando se produce una pulsación sobre un objeto View, como por
ejemplo un Button (botón).
Un detector de eventos podemos definirlo como una interfaz de la clase View, que
contiene un método callback o de devolución de llamada. Dicho método será
llamado cuando la vista donde se ha registrado el oyente (listener) es desencadenada por la
interacción del usuario con el elemento perteneciente a la interfaz.
Nota: en el anterior apartado ya vimos que una View (vista) ocupa un área rectangular en la
pantalla y es la responsable de dibujar los componentes y manejar los eventos que definamos
sobre la interfaz de usuario.
En la siguiente lista se describen los métodos que detectarán los eventos
producidos por el usuario:
onClick()
Implementado con la interfaz View.OnClickListener . Este método será llamado cuando el
usuario toca el elemento en una interfaz táctil o se centra en dicho elemento cuando lo
selecciona con las teclas de navegación y pulsa la opción de entrar.
onLongClick()
Implementado con la interfaz View.OnLongClickListener . Este método será llamado cuando el
usuario toca el elemento manteniéndolo pulsado en una interfaz táctil o se centra en
dicho elemento cuando lo selecciona con las teclas de navegación y pulsa la opción de entrar
dejándolo pulsado.
onFocusChange()
Implementado con la interfaz View.OnFocusChangeListener . Este método será llamado cuando
el usuario se posicione sobre el elemento.
onKey()
Implementado con la interfaz View.OnKeyListener .Este método será llamado cuando el
usuario se posiciona sobre el elemento pulsando o soltando una tecla del dispositivo.
onTouch()
Implementado con la interfaz View.OnTouchListener . Este método será llamado cuando el
usuario realice cualquier acción relacionada con la pulsación, dejar de pulsar o gestos
sobre la pantalla táctil del dispositivo.
onCreateContextMenu()
Implementado con la interfaz View.OnCreateContextMenuListener . Este método será llamado
cuando el usuario mediante una pulsación prolongada, defina la visualización de
un menú contextual.
Construcción de un detector de entradas
Vamos a ver un sencillo ejemplo práctico, mostrando tres posibilidades de
implementación del evento onCLick() . En el ejemplo, cuando el usuario toca-pulsa
el botón, se lanza un mensaje por pantalla informando de este hecho:
Método setOnClickListener() , pasándole una instancia de ClickListener :
public class MainActivity extends Activity
{
private Button btnOnClick;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
btnOnClick = (Button)findViewById(R.id.btnOnClick);
btnOnClick.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
Toast.makeText(MainActivity.this, "Ha pulsado el botón 'Even
to onClick()'.", Toast.LENGTH_SHORT).show();
}
});
}
}
Implementando la interfaz OnClickListener como parte de la Activity, y el
método onClick(View v) . Al implementar la interfaz View.OnClickListener , mostrará un error,
y bastará con seleccionar con el cursor dicha interfaz y con la combinación Alt + Enter, nos
mostrará una ventana modal con la opción "Implement methods" que añadirá
automáticamente el método onClick() :
public class MainActivity extends Activity implements View.OnClickListener
{
private Button btnOnClick;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
btnOnClick = (Button)findViewById(R.id.btnOnClick);
}
@Override
public void onClick(View v)
{
Toast.makeText(MainActivity.this, "Ha pulsado el botón 'Evento onCli
ck()'.", Toast.LENGTH_SHORT).show();
}
}
Definiendo el evento onClick() en dicha propiedad a nivel de layout (a nivel de código, se
puede observar cómo se define un método llamado lanzarEvento() ,que recibe como
parámetro de entrada una objeto de tipo View , y que debe coincidir con el método declarado
en la propiedad onClick ):
public class MainActivity extends Activity
{
private Button btnOnClick;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
btnOnClick = (Button)findViewById(R.id.btnOnClick);
}
public void lanzarEvento(View v)
{
Toast.makeText(MainActivity.this, "Ha pulsado el botón 'Evento onClick()'.", Toas
t.LENGTH_SHORT).show();
}
}
Dentro del layout se define un método llamado lanzarEvento en la propiedad onClick. Este
método deberá implementarse en la Activity que mostrará esta pantalla:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.MainActivity"
android:id="@+id/rlPrincipal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Evento onClick()"
android:id="@+id/btnOnClick"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="61dp"
<!-- Propiedad donde se define el evento -->
android:onClick="lanzarEvento" />
</RelativeLayout>
Proyecto: creación de interfaz de
usuario básico (versión XML y
versión código)
Vamos a mostrar a través de un ejercicio práctico, cómo construir elementos de la interfaz
de usuario. Se tratará de una aplicación Android muy simple que presentará un control
de entrada Button que al ser pulsado, mostrará un mensaje en la pantalla.
Haremos dos versiones de este sencillo ejemplo, cuyo código podrás descargar al
final de este tutorial:
 Proyecto que denominaremos "InterfazUsuario"
donde implementamos los controles de forma programática, es
decir, se construyen dichos elementos en tiempo de ejecución (cuando
la App se ejecuta en el dispositivo).
 Proyecto que denominaremos "InterfazUsuarioXML"
donde definiremos los controles a nivel de layout.
Descripción y estructura del proyecto
InterfazUsuario
La aplicación será muy simple. Constará de una sola pantalla con el botón y el mensaje que
aparecerá al pulsarlo, como vemos aquí:
Los elementos necesarios para el desarrollo de este son:
 Clase MainActivity , que herede de la clase base Activity , y que definirá la
lógica de creación de instancias y diseño programático de las propiedades
de la interfaz de usuario.
 Layout activity_main.xml , formado por un layout de tipo RelativeLayout , que
servirá como base para el resto de elementos que vayan construyéndose
en tiempo de ejecución.
En la siguiente imagen, se podrá apreciar cómo quedaría finalmente la estructura de
elementos que intervienen en el proyecto (vista Android en el IDE Android Studio):
Descripción del código fuente proyecto
"InterfazUsuario"
Una vez presentado brevemente el proyecto, vamos a explicar el código que contiene:
InterfazUsuarioappsrcmainjavacomacademiaandroidinterfazusuarioMainActivity.class
Activity que mostrará un control de tipo Button, creado en tiempo de ejecución, y que
permitirá al usuario interaccionar con la aplicación al pulsar dicho botón:
package com.academiaandroid.interfazusuario;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
Se declara tres variables de tipo TextView , Button y RelativeLayout a nivel de clase:
private TextView tvHolaMundo;
private Button btnSaludo;
private RelativeLayout rlGeneral;
El método onCreate() será llamado cuando se inicie la Activity , por lo que todo lo situado
en su interior se inicializará al llamar a dicha Activity :
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
En las siguientes líneas se crean las instancias de los objetos que serán inicializados al
ejecutar la aplicación (reciben como parámetro de entrada el contexto de la aplicación). En
este caso se trata del layout base de la Activity , y el control Button que aparecerá
inicialmente:
rlGeneral = new RelativeLayout(getApplicationContext());
btnSaludo = new Button(getApplicationContext());
El objeto btnSaludo invocará al método setText() para establecer el texto que mostrará el
botón:
btnSaludo.setText("Pulsa aquí");
Finalmente se añade el control Button al layout definido, para establecer dicho layout como
base de la interfazde la aplicación:
rlGeneral.addView(btnSaludo);
setContentView(rlGeneral);
A continuación, y todavía dentro del método onCreate() , se invoca al
método setOnClickListener() del objeto btnSaludo ,encargado de controlar la pulsación del
botón:
btnSaludo.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Dentro de este evento, se crea una instancia de TextView , para en las siguientes líneas
invocar al método setTextColor() encargado de establecer el color del texto, y además
establecer los parámetros para definir la posición del objeto tvHolaMundo dentro del layout.
Para este último aspecto se crea una instancia de LayoutParams , que recibirá como
argumentos para dicha instancia, el ancho y alto del layout definido:
tvHolaMundo = new TextView(getApplicationContext());
tvHolaMundo.setTextColor(Color.BLACK);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutP
arams(
RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.Layou
tParams.WRAP_CONTENT);
En las siguientes líneas se establece el margen con respecto a la parte izquierda, superior,
derecha e inferior de la pantalla, además de asignar los parámetros del layout y asignarle el
texto "Hola Academia Android!!!" al invocar al método setText() :
layoutParams.setMargins(5, 200, 150, 0);
tvHolaMundo.setLayoutParams(layoutParams);
tvHolaMundo.setText("Hola Academia Android!!!");
Por último se añade al layout implementado, para finalmente cerrar el
método setOnClickListener, onCreate() y la clase MainActivity:
rlGeneral.addView(tvHolaMundo);
}
});
}
}
InterfazUsuarioappsrcmainreslayoutactivity_main.xml
Layout activity_main.xml que al definir los elementos de forma programática, sólo estaría
formado por un RelativeLayout :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuario.MainActivity"
android:id="@+id/rlPrincipal">
</RelativeLayout>
Descripción del código fuente
proyecto "InterfazUsuarioXML"
Si por el contrario, deseamos crear una aplicación similar a la anterior, enlazando los controles
definidos en la interfaz de usuario, con las variables definidas en la clase, bastaría con realizar
los siguientes pasos:
A nivel de layout añadir dos controles, uno de tipo Button , y otro de tipo TextView . Para ello
sólo bastará con seleccionar el layout creado por defecto al construir un proyecto con una
Activity vacía, y que podremos encontrar dentro de la ruta
InterfazUsuarioXMLappsrcmainreslayoutactivity_main.xml .
Una vez estemos situados sobre dicho fichero XML, en la vista diseño, seleccionar los
controles comentados anteriormente con un click, e indicaremos en qué posición queremos
colocarlo en la interfaz de usuario. Tanto a nivel visual, como desde el punto de vista XML,
quedaría de la siguiente forma:
Como se puede apreciar en la imagen anterior, aunque se ha definido un
control TextView (árbol de componentes), este no mostrará contenido debido a que la
propiedad "text" se deja vacía, para posteriormente desde la clase MainActivity indicar que
texto deseamos visualizar.
InterfazUsuarioXMLappsrcmainreslayoutactivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.interfazusuarioxml.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pulsa aquí"
android:id="@+id/btnSaludo"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/tvHolaMundo"
android:layout_below="@+id/btnSaludo"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
A nivel de clase, se crearán dos variables de tipo Button y TextView :
package com.academiaandroid.interfazusuarioxml;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView tvHolaMundo;
private Button btnSaludo;
Para finalmente, dentro del método onCreate() , definir el resto de lógica del contenido de la
vista y referencias de variables con sus recursos a nivel de layout. Como se puede apreciar, a
diferencia del ejemplo anterior, el método setContentView() establece la referencia con el
layout definido en los recursos de la aplicación, además de también referenciar las variables
de tipo TextView y Button con los identificadores (propiedad id del control a nivel de layout).
Esta tarea se realizará mediante el método findViewById() , que recibirá el identificador único
asignado a ese control:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvHolaMundo = (TextView)findViewById(R.id.tvHolaMundo);
btnSaludo = (Button)findViewById(R.id.btnSaludo);
btnSaludo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
tvHolaMundo.setText("Hola Academia Android!!!");
}
});
}
}
El resultado final con la pantalla de la App ejemplo sería muy similar a la otra versión:
4.1. Introducción y objetivos
Siguiendo con los fundamentos para crear aplicaciones Android vamos a tratar en este
tema la ejecución de tareas en segundo plano (background) en Android.
Los objetivos que vamos a cubrir en este módulo son:
 Entender la importancia de los hilos o subprocesos en un sistema
operativo.
 Conocer la lógica de jerarquías de procesos para aplicaciones
Android.
 Conocer las principales características de las clases AsyncTask,
Handler, Thread y Runnable que nos permiten implementar
tareas en segundo plano.
 Saber cuando se recomienda el uso de AsyncTask o el uso de
Threads.
 Ver con un proyecto un ejemplo práctico de uso e implementación
de tareas en background.
4.2. Hilo principal (main thread)
Android es un sistema operativo multitarea que permite la ejecución de varias tareas
simultáneamente. Esta característica que a simple vista nos puede parecer algo básico,
facilita que en muchas ocasiones las aplicaciones actualicen información sin afectar a la
respuesta y manejo del dispositivo donde se ejecutan.
Para proporcionar esa funcionalidad, los procesos que se ejecutan han de poder
descomponerse en hilos (threads). Un hilo de ejecución o subproceso es la unidad
de procesamiento más pequeña que un sistema operativo puede manejar.
Al desarrollar para Android, debemos tener muy presente la experiencia final del usuario que
va a utilizar las aplicaciones que creamos. Toda tarea que necesite de recursos
costosos del sistema deberá realizarse en un hilo secundario para evitar que
bloquee el hilo principal de la aplicación, y afecte al usuario durante la ejecución de la
misma.
Por defecto, todos los componentes de la misma aplicación se ejecutan en el mismo proceso y
es por eso que cuando hablamos del hilo principal o main thread, nos referimos al hilo
de ejecución donde se ejecutan los componentes, servicios, actividades, etc. de
una aplicación Android. Debido a la filosofía de Android respecto al consumo de
recursos, el sistema se encarga de monitorizar el hilo principal y cualquier operación
que supere los 5 segundos dará lugar a un mensaje de "Application Not Responding",
permitiendo al usuario esperar o forzar el cierre de la aplicación.
Android trata de mantener un proceso de aplicación durante el tiempo que sea necesario,
pero necesita liberar recursos de memoria para procesos nuevos o de mayor
importancia. Es aquí donde se delimita cada proceso en una "jerarquía de
importancia", basado en los componentes que se ejecutan en el proceso y el estado de los
mismos.
Hay cinco niveles en la jerarquía de importancia. La siguiente lista muestra los diferentes tipos
de procesos en orden de importancia:
Procesos en primer plano:
Proceso requerido para lo que el usuario está haciendo actualmente. Un proceso se considera
que está en el primer plano si se dan cualquiera de las siguientes condiciones:
 Activity que interactúa con el usuario (el método onResume() de la Activity
ha sido llamado).
 Cuando la Activity con la que interactúa el usuario aloja un Servicio
( Service ).
 Cuando un Servicio ha llamado al método startForeground() , y por lo tanto
se ejecuta en primer plano.
 Cuando aloja un Servicio que será llamado durante el ciclo de vida de la
aplicación ( onCreate() , onStart() u onDestroy() ).
 Cuando aloja un BroadcastReceiver que está ejecutando el
método onReceive() .
Procesos visibles:
Este tipo de procesos no define ningún componente en primer plano. Un proceso se considera
visible:
 Si se define una Activity que no está en primer plano pero es visible para
el usuario (llamada al método onPause() del ciclo de vida de la aplicación).
 Si se aloja un Servicio destinado a ser invocado en primer plano o a una
actividad visible.
Procesos de servicio:
Aquellos procesos que se ejecutan en un Servicio (iniciados con StartService() ) y no pasan
a las dos categorías superiores.
Procesos en segundo plano:
Proceso que se mantiene en una Activity en segundo plano, y que por lo tanto no es visible
para el usuario (ocurre cuando se llama al método onStop() del ciclo de vida de la aplicación).
Procesos vacíos:
Se trata de procesos que no están presentes en los componentes de la aplicación.
Android clasifica a un proceso en el nivel más alto que puede, en base a la
importancia de los componentes activos en dicho proceso. Si por ejemplo un proceso
recibe un servicio y una actividad visible, el proceso está clasificado como un proceso visible y
no como un proceso de servicio.
Créditos: parte de estos contenidos están basados en la documentación oficial de Android
Developers que están publicados bajo licencia Creative Commons Attribution 2.5. Imagen
de Cburnett publicada con licencia CC-BY-SA-3.0, via Wikimedia
4.3. Multitarea en Android con clases
AsyncTask, Thread, Handler y
Runnable
En este apartado vamos a conocer las principales características de las clases
AsyncTask, Handler, Thread y Runnable que nos permiten implementar tareas
en segundo plano en una Aplicación Android. Al final, encontrarás también un
cuadro comparativo donde vemos las situaciones donde se recomienda el uso de AsyncTask
o de Threads.
Como explicamos en el apartado anterior, cualquier componente de Android, como puede ser
una Activity, se ejecuta en el hilo principal o main thread (UIThread).
Si bien es cierto, que para operaciones rápidas no se encontrará ningún problema, es
probable que necesitemos realizar procesos más costosos, y por lo tanto el hilo
principal, encargado de mostrar la interfaz de usuario, quedaría bloqueado, con
la consiguiente lentitud de cara al usuario. Es aquí donde interviene el sistema
operativo Android, monitorizando todos los procesos que están en ejecución,
y forzando a salir de la aplicación a aquellos que superen los 5 segundos.
Para evitar este tipo de situaciones, Android proporciona una serie de clases, que
permiten trabajar en segundo plano, para aquellas operaciones que necesiten un
mayor tiempo para ser procesadas. Vamos a describirlas a continuación:
AsyncTask
Clase que permite comunicarse con el subproceso del hilo de interfaz de usuario o
hilo principal. Para ello realiza operaciones en segundo plano, mostrando los resultados en
subprocesos de la interfazde usuario.
Características principales de la clase
AsyncTask:
 Proporciona un mayor control y orden en la ejecución de nuestros
procesos en segundo plano.
 Marco de trabajo para operaciones no muy costosas.
 Las tareas se ejecutan en un sólo hilo, para evitar errores derivados de
ejecuciones en paralelo.
 Tarea asíncrona definida en 4 pasos:
( OnPreExecute() , doInBackground(Params...) , OnProgressUpdate(Progress...) y onP
ostExecute(Result...)
 Se añadió a partir de la versión Honeycomb (API nivel 11, versión Android
3.0). Aquí, puedes consultar la documentación oficial de la clase
AsyncTask
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
Implementación de AsynTask
A nivel de implementación, se deberá heredar de la clase AsyncTask, donde se definen tres
tipos genéricos:
public class TareaAsyncTask extends AsyncTask<params, progress, result>{
 Params: Tipo de parámetro que se recibirá como entrada para la tarea en
el método doInBackground(Params).
 Progress: Parámetros para actualizar el hilo principal o UIThread.
 Result: Es el resultado devuelto por el procesamiento en segundo plano.
Además de los tipos genéricos comentados anteriormente, será necesario sobreescribir los
siguientes métodos para procesar y devolver la información tratada en segundo plano:
 OnPreExecute() : Método llamado antes de iniciar el procesamiento en
segundo plano.
 doInBackground(Params...) : En este método se define el código que se
ejecutará en segundo plano. Recibe como parámetros los declarados al
llamar al método execute(Params).
 OnProgressUpdate(Progress...) : Este método es llamado
por publishProgress(), dentro de doInBackground(Params) (su uso es
muy común para por ejemplo actualizar el porcentaje de un componente
ProgressBar).
 onPostExecute(Result...) : Este método es llamado tras
finalizar doInBackground(Params). Recibe como parámetro el resultado
devuelto por doInBackground(Params).
 OnCancelled() : Se ejecutará cuando se cancele la ejecución de la tarea
antes de su finalización normal.
Thread
Clase que proporciona su propia unidad concurrente de ejecución, y se puede definir como la
unidad de procesamiento más pequeña que puede ser planificada por un
sistema operativo. Una de sus principales características es permitir a una aplicación
realizar varias tareas de manera simultánea. Define sus propios argumentos,
variables y pila de llamada a métodos.
Formas de ejecutar un hilo
 Heredando (extends) de la clase base Thread y creando una instancia de
dicha clase.
 Implementando (implements) la interfaz Runnable, y creando una
instancia de la clase que implementa dicha interfaz. Esta opción es muy
útil cuando no es posible heredar de la clase base Thread.
Nota: Ambas formas deben realizar la llamada al método start(), para procesar el código
situado en el método run().
Características principales de la clase Thread:
 Ejecución de tareas en paralelo o de manera concurrente.
 Los hilos de ejecución comparten el espacio de memoria.
 El conjunto de hilos en ejecución que comparten los mismos recursos es
conocido como un proceso.
 Cualquier modificación de un dato en memoria, por parte de un hilo,
permite el acceso al dato modificado para el resto de hilos de manera
inmediata.
 Cada hilo presenta de manera propia el contador de programa, la pila de
ejecución (o pila de llamadas, que consiste en una estructura dinámica de
datos, en las que el último proceso en entrar será el primero en salir, o lo
que es lo mismo, el último proceso se ejecutará primero) y el estado de la
CPU.
 Un proceso seguirá en ejecución si al menos uno de sus hilos de ejecución
sigue activo. Si un proceso finaliza, todos sus hilos de ejecución también
lo harán.
 Añadida a partir de la API nivel 1, puedes encontrar aquí la documentación
oficial de la clase Thread
Implementación de Thread
Se instancia la clase Thread, posteriormente se implementa el método run() , dónde se
definirá el código a ejecutar cuando la instancia creada llame al método start() .
Thread hilo1 = new Thread(new Runnable()
{
@Override
public void run()
{
//Código a ejecutar
}
});
hilo1.start();
Handler
Es aquella que permite manejar y procesar mensajes, proporcionando un
mecanismo para su envío (a modo de puente) entre threads o hilos, y así poder enviar
mensajes desde nuestro hilo secundario al UIThread o hilo principal.
Características principales de la clase Handler:
 Permiten poner en cola una acción que se realiza en un subproceso
distinto al suyo.
 Cada instancia de la clase Handler está asociada a un sólo hilo y a la cola
de mensajes de este.
 Comunicación del hilo secundario con el hilo principal o UIThread a través
de un controlador.
 Proporciona varios métodos para poner en cola un mensaje en la parte
delantera o enviar al final de la cola después de un determinado tiempo
( sendMessageAtFrontOfQueue(Message msg) y sendMessageAtTime(Message msg, long
uptimeMillis) )
 Añadida a partir de la API nivel 1, puedes consultar aquí la documentación
oficial de la clase Handler
Implementación de Handler
Se instancia la clase Handler, para posteriormente llamar al método sendMessage() ,
encargado de avisar al UIThread para realizar las tareas de repintado incluidas en el
método handleMessage(Message msg) .
private Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
}
};
[...]
handler.sendMessage(handler.obtainMessage());
[...]
Runnable
Interfaz que representa un comando que puede ser ejecutado. Es muy común su uso para la
ejecución de código en un hilo diferente.
Dicha interfaz implementa el método run() , que será llamado cuando un hilo es iniciado y
creado dentro de una clase que implemente la interfaz Runnable .
Implementación de Runnable
Bastará con implementar la interfaz Runnable, y añadir el método run() (tras implementar
la interfaz Runnable, nos indicará un error, y sólo deberemos posicionarnos sobre él y pulsar
las teclas Alt + Enter y seleccionar la opción "Implement Methods", seleccionando el método a
implementar, en nuestro caso el método run() ):
public class Hilo implements Runnable
{
@Override
public void run()
{
//Código a ejecutar al lanzar hilo.
}
}
Aquí puedes consultar la documentación oficial de la clase Runnable
AsyncTask vs Thread
Para finalizar esta presentación de las clases que nos permiten implementar tareas en
segundo plano en Android, vamos a comprender las situaciones en las que se recomienda el
uso de la clase AsyncTask o la clase Thread, dependiendo de las necesidades del proyecto:
Uso de AsynTask Uso de Threads
 En operaciones de red que
no requieran la descarga
de grandes cantidades de
datos.
 Tareas sobre disco que no
tomen más de algunos
segundos.
 En tareas cuyo resultado
del procesamiento en
segundo plano vaya a ser
publicado en el subproceso
del hilo de la interfaz de
usuario.
 No es necesario el uso de
Handler.
 En operaciones de red, ya sea
de carga o descarga, con una
moderada o alta cantidad de
datos.
 En tareas de gran consumo de
CPU que deban ejecutarse en
segundo plano.
 En tareas que sea necesario
controlar el consumo de CPU
por parte del hilo gráfico a
GUI (graphical user
interface).
 En tareas que deseemos
controlar la prioridad de
ejecución (cola de
procesamiento).
 No interacciona con el hilo de
interfaz de usuario, siempre y
cuando, el ciclo de vida de la
aplicación no esté destinada a
ejecutarse en segundo plano.
4.4. Proyecto ejemplo: tareas en
segundo plano en Aplicación Android
Vamos a ver un ejemplo práctico de implementación de tareas
background en Android, con un proyecto en el que gestionaremos varios hilos en
segundo plano mediante el uso de la clase AsyncTask.
La aplicación que vamos a describir paso a paso, se encargará de simular tres barras
de progreso , actualizando tanto el aspecto visual de la barra como el porcentaje asociado
a la misma. Cada barra estará controlada por un hilo secundario en el que se
modificarán los tiempo de duración para comprobar que dichos procesos no
bloquean el hilo principal de la aplicación.
Puedes descargar todo el código del proyecto en el siguiente apartado del curso.
Descripción de la Aplicación
Aunque mostraremos la aplicación en funcionamiento en un próximo video, para hacernos una
idea podemos ver la pantalla principal de la app en la imagen de abajo.
Como se aprecia, mostrará un botón junto con tres barras de progreso. Al ser pulsado dicho
botón ("Tareas Segundo Plano"), se mostrará el proceso de avance de los diferentes
componentes visuales:
A continuación, enumeramos los elementos necesarios para el desarrollo del proyecto que
vamos a denominar "TareasSegundoPlano":
 Clase MainActivity , que herede de la clase base Activity , y cuya principal
característica será la de lanzar las tareas que se ejecutarán en segundo
plano, mostrando el progreso de las mismas.
 Clase PorcentajeDos , que herede de la clase AsyncTask , y que gestionará una
barra de progreso en segundo plano, actualizando el porcentaje cada 200
milésimas (1/5 segundo).
 Clase PorcentajeCinco , que herede de la clase AsyncTask , y que gestionará
una barra de progreso en segundo plano, actualizando el porcentaje cada
500 milésimas (1/2 segundo).
 Clase PorcentajeDiez , que herede de la clase AsyncTask , y que gestionará
una barra de progreso en segundo plano, actualizando el porcentaje cada
1000 milésimas (1 segundo).
 Layout activity_main.xml , formado por un layout de tipo RelativeLayout , y
que a su vez contiene un TableLayout , que dispondrá en diferentes filas
tanto el botón como las barras de progreso implementadas.
Versiones utilizadas: para realizar este proyecto se ha utilizado la versión de Android
Studio 2.1.2 y la Versión SDK de compilación: API 23 para Android 6.0
Marshmallow.
Estructura del proyecto
Siguiendo con la lógica general de presentación del proyecto, en la siguiente imagen se
visualizará la estructura de elementos que intervienen, todo desde la vista Android:
Descripción del código fuente
Continuando con la descripción del proyecto, en las siguientes líneas explicamos el código de
las clases y fichero de layout que componen el mismo.
TareasSegundoPlanoappsrcmainjavacomacademiaandroidtareass
egundoplanoMainActivity.class
Activity que mostrará un control de tipo Button y tres controles de tipo ProgressBar (control
que indicará de manera gráfica el progreso de una tarea), que comenzarán su progreso una
vez el usuario pulse el botón definido:
package com.academiaandroid.tareassegundoplano;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity
{
Se declara una variable de tipo Button a nivel de clase:
private Button btnTareaSegundoPlano;
Posteriormente, dentro del método onCreate() ,se asigna a la variable de tipo Button , el
identificador único del control definido a nivel de layout, mediante el método findViewById() :
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnTareaSegundoPlano = (Button)findViewById(R.id.btnTareaSegundoPlano);
[...]
Finalmente, y todavía dentro del método onCreate() , se invoca al
método setOnClickListener() del objeto btnTareaSegundoPlano , encargado de controlar la
pulsación del botón y crear una instancia de la clase PorcentajeDos() .Procesará una de las
tareas en segundo plano y recibe como argumento de entrada el contexto de la aplicación.
Además como se puede apreciar, invoca al método execute() ,para la realización de la tarea:
[...]
btnTareaSegundoPlano.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
new PorcentajeDos(MainActivity.this).execute("Carga Finalizada X2
");
}
});
}
}
TareasSegundoPlanoappsrcmainjavacomacademiaandroidtareass
egundoplanoPorcentajeDos.class
Clase encargada de gestionar el porcentaje de una barra de progreso, en segundo plano,
actualizando dicho componente cada 200 milésimas.
Esta clase heredará de la clase base Asynctask<String, Integer, String> que como se comenta
en apartados anteriores, define tres tipos genéricos, que en este ejemplo se trata de:
 String: parámetro que se recibirá como entrada para la tarea en el método
doInBackground(Params), y que mostrará el texto "Carga Finalizada X2"
 Integer: parámetro que actualizará el hilo principal mediante el avance de
la barra de progreso
 String: que será el resultado devuelto por el procesamiento en segundo
plano, en este caso el texto pasado como parámetro desde el
método execute() :
public class PorcentajeDos extends AsyncTask<String, Integer, String>
{
Se declaran a nivel de clase una variable de tipo MainActivity (establecerá el contexto de la
aplicación para mostrar los diferentes mensajes por pantalla), una variable de
tipo ProgressBar (permitirá actualizar la barra de progreso), y una variable de
tipo TextView (actualizará el porcentaje actual):
private MainActivity context;
private ProgressBar progressBarDos;
private TextView tvDos;
Se define un constructor para establecer el contexto de la Activity de la aplicación:
public PorcentajeDos(MainActivity context)
{
this.context = context;
}
El siguiente método será invocado al lanzar el hilo, mostrando el mensaje de "Progreso X2":
@Override
protected void onPreExecute()
{
super.onPreExecute();
Toast.makeText(context, "Progreso X2", Toast.LENGTH_LONG).show();
}
El método doInBackground() , procesará el parámetro de entrada (en nuestro caso sólo será
un mensaje que se muestre al finalizar la tarea) y actualizará el progreso del componente
ProgressBar. Una de las particularidades del código situado dentro de este método, consiste
en invocar al método sleep() de la clase Thread , para realizar una pausa de 200 milésimas
en cada iteración (así se simula correctamente el funcionamiento de una barra de progreso):
@Override
protected String doInBackground(String... params)
{
Se establecen 100 iteraciones, por lo tanto se actualizará ese número de iteraciones el hilo
principal de la aplicación:
for(int i = 0; i <= 100; i++)
{
try
{
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
}
return String.valueOf(params[0]);
}
Este método asigna a la variable de tipo TextView su identificador único (control definido en el
layout de la Activity principal). Como se puede apreciar, se invoca al
método findViewById() desde el contexto de la aplicación definido en el constructor de esta
clase. Finalmente se actualizará el valor de la variable TextView por cada ciclo del
método doInBackground() :
@Override
protected void onProgressUpdate (Integer... valores)
{
super.onProgressUpdate(valores);
progressBarDos = (ProgressBar)context.findViewById(R.id.progressBarDos);
progressBarDos.setProgress(valores[0]);
tvDos = (TextView)context.findViewById(R.id.tvDos);
tvDos.setText(valores[0] + "%");
}
El siguiente método tiene la particularidad de instanciar la clase PorcentajeCinco , para
ejecutar dicha tarea en segundo plano:
@Override
protected void onPostExecute(String s)
{
super.onPostExecute(s);
Toast.makeText(context, s,Toast.LENGTH_LONG).show();
new PorcentajeCinco(context).execute("Carga Finalizada X5");
}
}
Nota: Se utiliza la clase PorcentajeDos como ejemplo para describir el código
fuente, ya que el resto de clases (PorcentajeCinco y PorcentajeDiez) tiene una estructura
similar, salvo en el texto que se mostrará al lanzar y finalizar el hilo, como la frecuencia de
actualización de la barra de progreso (parámetro del método sleep() dentro
de doInBackground() ).
TareasSegundoPlanoappsrcmainreslayoutactivity_main.xml
Layout activity_main.xml que estará formado por un TableLayout , que establece la
disposición de los elementos ordenados en filas, en las que se definen un control de
tipo Button , y tres controles de tipo ProgressBar para las diferentes tareas que serán
lanzadas por el usuario:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.academiaandroid.tareassegundoplano.MainActivity">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="50dp">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tarea Segundo Plano"
android:id="@+id/btnTareaSegundoPlano"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:id="@+id/progressBarDos"
android:layout_toRightOf="@+id/progressBarCinco"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/tvDos"
android:layout_column="2" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:id="@+id/progressBarCinco" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/tvCinco"
android:layout_column="2" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:id="@+id/progressBarDiez" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/tvDiez"
android:layout_column="2" />
</TableRow>
</TableLayout>
</RelativeLayout>
5.1. Introducción y objetivos
En este tema estudiaremos las distintas formas de almacenar información de forma
permanente en nuestras aplicaciones. Además veremos cómo integrar en nuestras
aplicaciones elementos multimedia como el audio y el vídeo.
Una vez finalizado el módulo seremos capaces de:
 Almacenar datos sencillos a través de las configuraciones de
usuario
 Crear bases de datos SQLite, así como insertar, modificar y
consultar datos de las mismas en nuestra aplicación.
 Conocer las posibilidades de acceso a otros sistemas de bases de
datos mas complejos.
 Integrar en nuestras aplicaciones audios y vídeos.
5.2 Gestionar preferencias de
usuario
La clase SharedPreferences
La forma más sencilla de almacenar datos en nuestras aplicaciones es recurrir a la
clase SharedPreferences. Esta nos permite guardar y consultar posteriormente datos en
forma de clave-valor, de modo que la clave será el nombre que demos al dato que
queremos almacenar y el valor estará representado por alguno de los tipos de datos
básicos: boolean, float, int, long y string.
Las preferencias se almacenan en uno o varios ficheros que pueden
ser privados o públicos para que otras aplicaciones puedan acceder a nuestras
preferencias de usuario.
Acceder a las preferencias de usuario
Podemos crear y acceder a nuestros ficheros de preferencias de dos formas:
Usando el método getSharedPreferences()
Éste se usa si necesitamos diferentes ficheros de preferencias identificados por un nombre,
que pasaremos como primer parámetro. Como segundo parámetro pasaremos el modo de
acceso, que indicará si el fichero de preferencias es privado a nuestra aplicación, o si por el
contrario otras aplicaciones podrán acceder a él.
Tendremos varias posibilidades distintas para especificar el modo:
 MODE_PRIVATE. Privado a nuestra aplicación. En la mayoria de los casos
será el único modo que necesitemos.
 MODE_WORLD_READABLE. Cualquier aplicación puede acceder al fichero
de preferencias pero sólo en modo lectura. (Obsoleto desde la API 17).
 MODE_WORLD_WRITABLE. Cualquier aplicación puede acceder al fichero
en modo lectura y escritura. (Obsoleto desde la API 17).
 MODE_MULTI_PROCESS. Permite comprobar si se han producido
cambios en el fichero de preferencias, incluso aunque éste este abierto.
 MODE_APPEND. Permite añadir nuevas preferencias en un fichero
existente.
 MODE_ENABLE_WRITE_AHEAD_LOGGING. Se utiliza para labores de
depuración.
Usando el método getPreferences()
Éste se usa si sólo necesitamos un fichero de preferencias para una Activity. Únicamente
recibe un parámetro, que será el modo de acceso a este fichero, el nombre vendrá implícito y
será el nombre de la Activity.
Añadir datos
Para escribir datos usando la clase SharedPreferences lo haríamos de la siguiente
manera:
Obtenemos las preferencias usando por ejemplo el método getSharedPreferences() , a
continuación obtenemos el objeto Editor mediante el método edit() , este objeto será el
que nos permita modificarlas.
SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = propiedades.edit();
En este caso hemos utilizado el método para un único fichero de preferencias y el modo de
acceso privado a la aplicación.
Para añadir datos, podemos usar métodos tales como putBoolean() para almacenar un
valor booleano, putString() para almacenar un String, putInt() para almacenar un
entero, etc. Veamos cómo almacenar por ejemplo una cadena de texto y un entero:
editor.putString("name", "Digital Learning");
editor.putInt("idCurso", 3);
Para guardar los datos debemos hacer un commit del siguiente modo:
editor.commit();
Recuperar datos
Para recuperar los datos almacenados obtenemos de nuevo las preferencias del mismo modo
que vimos antes.
SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE);
Sobre este objeto ya podremos obtener los valores directamente así:
String name= preferences.getString("name", "");
int id = preferences.getInt("idCurso", -1);
Vemos que los métodos getString y getInt reciben dos parámetros, uno es la clave del
dato almacenado, y otro es un valor por defecto por si no se encuentra el dato representado
por la clave dada.
Crear una PreferenceActivity
Normalmente necesitaremos que sea el usuario quien introduzca los valores de
las preferencias de la aplicación, para ello podemos crear una interfaz en la
que recoger los datos.
Existe un tipo de Activity especial para este fin llamada PreferenceActivity, que nos
permitirá crear de forma sencilla una interfaz en la que podremos añadir preferencias de
distintos tipos para que el usuario defina sus valores.
Para crear nuestra PreferenceActivity seguiremos los siguientes pasos:
En primer lugar crearemos un fichero preferences.xml dentro de la carpeta res/xml con
el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:title="Nombre"
android:key="username"
android:summary="Introduce tu nombre de usuario"></EditTextPreference>
<CheckBoxPreference android:title="Buscar actualizaciones"
android:defaultValue="false"
android:summary="Marca si quieres que se busquen actualizaciones automáticamente"
android:key="applicationUpdates" />
<ListPreference android:title="Interfaz"
android:summary="Selecciona el tipo de interfaz de la aplicación"
android:key="interfaz"
android:defaultValue="1"
android:entries="@array/listKeys"
android:entryValues="@array/listValues" />
</PreferenceScreen>
Podemos observar como se definen los 3 principales tipos de preferencias:
 EditTextPreference
 CheckBoxPreference
 ListPreference
Las dos primeras nos permiten crear campos de entrada de texto
y CheckBox respectivamente, mientras que la tercera nos mostrara una lista desplegable
cuyos valores seleccionables deben ser definidos en dos arrays: listKeys para el texto
mostrado y listValues para el valor que se asignara a la variable.
Para definir los dos arrays mencionados en el apartado anterior crearemos un fichero
llamado array.xml dentro de la carpeta res/values con el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="listKeys">
<item>Por defecto</item>
<item>Clara</item>
<item>Oscura</item>
</string-array>
<string-array name="listValues">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>
Este fichero tiene la misma utilidad que los mencionados en los primeros temas
(strings, styles, etc) pero en esta ocasión servirá para almacenar listados de elementos que
puedan ser consultados en cualquier parte de la aplicación.
Ahora necesitamos crear la Activity que mostrará los datos. Para ello, creamos una
nueva clase vacía en la misma carpeta de nuestra actividad principal que contendrá el
siguiente código:
package com.academiaandroid.demopreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
public class PrefActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPrefe
renceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
@Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
}
En la última línea de código vemos cómo
el método addPreferencesFromResource() carga el contenido del XML creado en el primer
paso.
Por último modificaremos el código de nuestra actividad principal para que lance la
ventana de preferencias al iniciar la aplicación:
package com.academiaandroid.demopreferences;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Lanzamos la ventana de Preferencias
Intent i = new Intent(this, PrefActivity.class);
startActivity(i);
}
}
Si ejecutamos la aplicación nos aparecerá una venta como esta:
Curso Android  2021
Para consultar los valores de las preferencias en cualquier parte la aplicación
utilizaremos el siguiente código:
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext())
;
String username = prefs.getString("username", "NA");
boolean applicationUpdates = prefs.getBoolean("applicationUpdates",false);
String interfaz = prefs.getString("interfaz","1");
Muy similar al que vimos al principio de este apartado con la diferencia del método necesario
para obtener el fichero de preferencias, que podemos ver en la primera linea de código.
Última modificación: miércoles, 28 de septiembre de 2016, 19:59
5.2 Gestionar preferencias de
usuario
La clase SharedPreferences
La forma más sencilla de almacenar datos en nuestras aplicaciones es recurrir a la
clase SharedPreferences. Esta nos permite guardar y consultar posteriormente datos en
forma de clave-valor, de modo que la clave será el nombre que demos al dato que
queremos almacenar y el valor estará representado por alguno de los tipos de datos
básicos: boolean, float, int, long y string.
Las preferencias se almacenan en uno o varios ficheros que pueden
ser privados o públicos para que otras aplicaciones puedan acceder a nuestras
preferencias de usuario.
Acceder a las preferencias de usuario
Podemos crear y acceder a nuestros ficheros de preferencias de dos formas:
Usando el método getSharedPreferences()
Éste se usa si necesitamos diferentes ficheros de preferencias identificados por un nombre,
que pasaremos como primer parámetro. Como segundo parámetro pasaremos el modo de
acceso, que indicará si el fichero de preferencias es privado a nuestra aplicación, o si por el
contrario otras aplicaciones podrán acceder a él.
Tendremos varias posibilidades distintas para especificar el modo:
 MODE_PRIVATE. Privado a nuestra aplicación. En la mayoria de los casos
será el único modo que necesitemos.
 MODE_WORLD_READABLE. Cualquier aplicación puede acceder al fichero
de preferencias pero sólo en modo lectura. (Obsoleto desde la API 17).
 MODE_WORLD_WRITABLE. Cualquier aplicación puede acceder al fichero
en modo lectura y escritura. (Obsoleto desde la API 17).
 MODE_MULTI_PROCESS. Permite comprobar si se han producido
cambios en el fichero de preferencias, incluso aunque éste este abierto.
 MODE_APPEND. Permite añadir nuevas preferencias en un fichero
existente.
 MODE_ENABLE_WRITE_AHEAD_LOGGING. Se utiliza para labores de
depuración.
Usando el método getPreferences()
Éste se usa si sólo necesitamos un fichero de preferencias para una Activity. Únicamente
recibe un parámetro, que será el modo de acceso a este fichero, el nombre vendrá implícito y
será el nombre de la Activity.
Añadir datos
Para escribir datos usando la clase SharedPreferences lo haríamos de la siguiente
manera:
Obtenemos las preferencias usando por ejemplo el método getSharedPreferences() , a
continuación obtenemos el objeto Editor mediante el método edit() , este objeto será el
que nos permita modificarlas.
SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = propiedades.edit();
En este caso hemos utilizado el método para un único fichero de preferencias y el modo de
acceso privado a la aplicación.
Para añadir datos, podemos usar métodos tales como putBoolean() para almacenar un
valor booleano, putString() para almacenar un String, putInt() para almacenar un
entero, etc. Veamos cómo almacenar por ejemplo una cadena de texto y un entero:
editor.putString("name", "Digital Learning");
editor.putInt("idCurso", 3);
Para guardar los datos debemos hacer un commit del siguiente modo:
editor.commit();
Recuperar datos
Para recuperar los datos almacenados obtenemos de nuevo las preferencias del mismo modo
que vimos antes.
SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE);
Sobre este objeto ya podremos obtener los valores directamente así:
String name= preferences.getString("name", "");
int id = preferences.getInt("idCurso", -1);
Vemos que los métodos getString y getInt reciben dos parámetros, uno es la clave del
dato almacenado, y otro es un valor por defecto por si no se encuentra el dato representado
por la clave dada.
Crear una PreferenceActivity
Normalmente necesitaremos que sea el usuario quien introduzca los valores de
las preferencias de la aplicación, para ello podemos crear una interfaz en la
que recoger los datos.
Existe un tipo de Activity especial para este fin llamada PreferenceActivity, que nos
permitirá crear de forma sencilla una interfaz en la que podremos añadir preferencias de
distintos tipos para que el usuario defina sus valores.
Para crear nuestra PreferenceActivity seguiremos los siguientes pasos:
En primer lugar crearemos un fichero preferences.xml dentro de la carpeta res/xml con
el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:title="Nombre"
android:key="username"
android:summary="Introduce tu nombre de usuario"></EditTextPreference>
<CheckBoxPreference android:title="Buscar actualizaciones"
android:defaultValue="false"
android:summary="Marca si quieres que se busquen actualizaciones automáticamente"
android:key="applicationUpdates" />
<ListPreference android:title="Interfaz"
android:summary="Selecciona el tipo de interfaz de la aplicación"
android:key="interfaz"
android:defaultValue="1"
android:entries="@array/listKeys"
android:entryValues="@array/listValues" />
</PreferenceScreen>
Podemos observar como se definen los 3 principales tipos de preferencias:
 EditTextPreference
 CheckBoxPreference
 ListPreference
Las dos primeras nos permiten crear campos de entrada de texto
y CheckBox respectivamente, mientras que la tercera nos mostrara una lista desplegable
cuyos valores seleccionables deben ser definidos en dos arrays: listKeys para el texto
mostrado y listValues para el valor que se asignara a la variable.
Para definir los dos arrays mencionados en el apartado anterior crearemos un fichero
llamado array.xml dentro de la carpeta res/values con el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="listKeys">
<item>Por defecto</item>
<item>Clara</item>
<item>Oscura</item>
</string-array>
<string-array name="listValues">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>
Este fichero tiene la misma utilidad que los mencionados en los primeros temas
(strings, styles, etc) pero en esta ocasión servirá para almacenar listados de elementos que
puedan ser consultados en cualquier parte de la aplicación.
Ahora necesitamos crear la Activity que mostrará los datos. Para ello, creamos una
nueva clase vacía en la misma carpeta de nuestra actividad principal que contendrá el
siguiente código:
package com.academiaandroid.demopreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
public class PrefActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPrefe
renceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
@Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
}
En la última línea de código vemos cómo
el método addPreferencesFromResource() carga el contenido del XML creado en el primer
paso.
Por último modificaremos el código de nuestra actividad principal para que lance la
ventana de preferencias al iniciar la aplicación:
package com.academiaandroid.demopreferences;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Lanzamos la ventana de Preferencias
Intent i = new Intent(this, PrefActivity.class);
startActivity(i);
}
}
Si ejecutamos la aplicación nos aparecerá una venta como esta:
Curso Android  2021
Para consultar los valores de las preferencias en cualquier parte la aplicación
utilizaremos el siguiente código:
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext())
;
String username = prefs.getString("username", "NA");
boolean applicationUpdates = prefs.getBoolean("applicationUpdates",false);
String interfaz = prefs.getString("interfaz","1");
Muy similar al que vimos al principio de este apartado con la diferencia del método necesario
para obtener el fichero de preferencias, que podemos ver en la primera linea de código.
Última modificación: miércoles, 28 de septiembre de 2016, 19:59
7.3. Crear una cuenta de
desarrollador
En este apartado vamos a ver como crear una cuenta de desarrollador de Google Play,
requisito necesario si queremos subir nuestras aplicaciones a la tienda de Google.
Registro de datos
El primer requisito es disponer de una cuenta de correo de Google. En caso de que no
tengamos una podemos crearla en la siguiente dirección:
https://accounts.google.com/SignUp?hl=es
Estando identificados con nuestra cuenta nos dirigiremos a la web de Android Developers:
https://developer.android.com/index.html
Y pulsamos en el botón que se encuentra en la parte superior derecha de la misma, que nos
llevará a la consola de desarrollo.
En la siguiente ventana nos indicará la cuenta con la que estamos identificados, que será la
que quedará asociada a nuestra cuenta de desarrollador; si es correcta, sólo tendremos que
aceptar las condiciones del acuerdo de distribución de Google Play.
Pago de la cuota de desarrollador
La cuenta de desarrollador tiene un coste de 25 dolares; este pago es único y lo
realizamos al darnos de alta. Actualmente, no es necesario realizar ninguna renovación
periódica ni pago adicional para subir nuestras aplicaciones.
Una vez aceptado el acuerdo de distribución hacemos click en el botón de
completar el pago y nos aparecerá un popup como el que se muestra en la
siguiente captura.
Completaremos nuestros datos personales y dirección pulsaremos Continuar accediendo al
siguiente paso.
Aquí introduciremos los datos de la tarjeta con la que vayamos a pagar y finalizaremos el
proceso pulsando en el botón Pagar
A continuación se nos solicitarán nuestros datos de desarrollador, nombre,
dirección de correo electrónico para notificaciones, sitio web y número de teléfono.
Finalmente pulsaremos en el botón Completar Registro y con esto habremos finalizado el
proceso de registro.
Acceder a la consola de desarrolladores
Para acceder a nuestra consola de desarrollo nos dirigiremos a la siguiente
dirección: https://play.google.com/apps/publish/ En nuestro primer acceso se nos
desplegará la pestaña de notificaciones en la que podremos acceder a distintas
guías en las que se explican algunas funciones y características de la consola de
desarrollo.
7.4. APK: generación de ejecutable
de App Android y firma digital
Si queremos publicar nuestras aplicaciones, estas deben ir firmadas
digitalmente, quedando de esta manera asociadas de forma única a una clave de
desarrollador que estará en nuestro poder.
Esta clave puede ser única para todas nuestras aplicaciones o independiente para cada una
de ellas (o para un grupo); lo único que debemos tener claro es que una vez publicada una
aplicación, tan solo podremos actualizarla si va firmada con la misma clave.
Si por cualquier motivo perdiéramos nuestra clave, no podríamos subir nuevas versiones de la
misma, debiendo eliminar la aplicación publicada y crear una nueva si quisiéramos modificarla.
Por esto, es importante que una vez generada una clave y firmada un aplicación con ella, la
guardemos en un lugar seguro y creemos copias de seguridad de la misma.
Firma de una aplicación
Vamos a ver el proceso para realizar la firma de nuestra aplicación. Si además queremos
publicar la aplicación en la Play Store de Google, debemos firmar digitalmente el APK
generado. Describiremos el proceso para realizar ambos pasos:
Vamos pues a describir el proceso para realizar ambos pasos:
En primer lugar, para obtener el archivo compilado, se deberá seleccionar la opción "Build
Variants" (ruta View > Tool Windows), y cambiar el estado del módulo a "release".
A continuación se volverá a reconstruir el proyecto desde la ruta Build > Rebuild Project.
En el supuesto de no tener almacenada una firma digital, se deberá crear una nueva a través
de la ruta Build > Generate Signed APK..., en la nueva ventana se pulsará sobre el
botón "Create new...", y será necesario completar los datos de la ventana
denominada "New Key Store":
Al pulsar en "OK", mostrará de nuevo la ventana "Generate Signed APK
Wizard", con los datos de la nueva clave almacenada. Tras pulsar en "Next", se
indicará el directorio dónde se almacenará el APK del proyecto, y a continuación se
pulsará sobre el botón "Finish", mostrando finalmente un mensaje de que se ha
generado correctamente:
7.5 Publicar en Play Store
En este apartado veremos cómo subir nuestra aplicación a la tienda de Google una
vez finalizado el desarrollo de la misma. Necesitaremos firmar nuestra aplicación,
completar los distintos apartados de la ficha de aplicación y el cuestionario sobre
los contenidos de la misma y finalmente, subir el apk de nuestra aplicación para
que ésta esté disponible para la descarga.
Firma de Aplicación
Lo primero que haremos será firmar nuestra aplicación siguiendo los pasos que
vimos en el apartado correspondiente. Nos dirigiremos al menú Build y
seleccionaremos la opción: Generate Signed APK.
Seleccionaremos nuestro almacén de firmas o crearemos uno nuevo en el caso de
que no lo hayamos hecho aún y pulsaremos en Next.
Seleccionaremos el directorio de salida y elegiremos el modo de
compilación Release y finalmente pulsamos en Finish para completar el proceso.
Nos aparecerá un mensaje indicando que el proceso ha terminado y podremos
abrir la ubicación del fichero.
Hay que tener en cuenta que si hemos utilizado Apis de Google que requieran su
propia firma, como el caso de Google Maps, debemos haberlas incluido antes de
generar el APK.
Ficha de Aplicación
Para publicar nuestra aplicación nos dirigiremos a la pagina de desarrolladores de
Android y pulsaremos en Developer Console.
Entre las opciones que aparecerán debemos pulsar el botón Publicar una
aplicacion....
Nos aparecerá una ventana emergente pidiéndonos los datos básicos de nuestra
aplicación, el idioma y el nombre, que no puede superar los 50 caracteres. Una vez
introducidos pasaremos a preparar la ficha de Play Store
Completaremos los datos obligatorios: en primer lugar las descripciones breve y
completa de la aplicación.
Posteriormente las capturas de pantalla (screenshots), icono e imagen
destacada, en caso de que queramos podemos incluir también una imagen
o vídeo promocional.
Por último completamos las distintas categorizaciones de nuestra aplicación y
nuestros datos de desarrollador y política de privacidad si disponemos de
ella.
Con estos datos completados podemos guardar nuestra ficha de aplicación.
El icono verde nos indica que todos los datos obligatorios están rellenos y por
tanto la ficha esta lista para ser publicada.
Subir Apk
Una vez completada la ficha procederemos a subir el APK que generamos
anteriormente, para ello nos dirigimos al menú APK.
Nos aparecen 3 pestañas, nosotros sólo nos preocuparemos de la
de Producción, pulsamos en el botón Subir APK a producción
Nos aparecerá una ventana en la que podemos seleccionar o arrastrar nuestro
APK. Una vez lo hagamos comenzará automáticamente la subida que llevará unos
segundos dependiendo de nuestra conexión y del tamaño del fichero.
Cuando concluya la subida nos aparecerá en el listado de versiones con el
estado borrador en producción, ya que aun no está publicada.
Podemos hacer clic en la versión para ver la información asociada, número y
código de versión, texto con los cambios de la versión, permisos requeridos, etc.
Ya tenemos nuestra aplicación subida, sólo nos quedan unos pocos pasos antes de
poder publicarla.
Política de Precios
El siguiente paso será completar nuestra política de precios, nos dirigiremos al
menú correspondiente.
En nuestro caso indicaremos que la aplicación será gratuita para todos los países.
Y que no contiene anuncios.
En último lugar indicaremos el consentimiento con las directrices y leyes de
exportación.
Por supuesto, es recomendable leer toda la información que aparece en cada
apartado para conocer lo que estamos aceptando. En caso de que queramos que
nuestra aplicación sea de pago, tendremos que seguir una serie de pasos
adicionales que están indicados en la documentación de la Consola de
Desarrolladores. Una vez completado guardamos el borrador con la información
introducida.
Cuestionario de contenidos
El último paso sera completar el formulario para aplicar la clasificación de
contenido a nuestra app.
Una vez en el apartado correspondiente pulsaremos en el botón Seguir para
iniciar el cuestionario.
Primero seleccionaremos el tipo de aplicación y a continuación comenzará el
cuestionario.
En él se nos preguntará por los contenidos y funciones que afecten a
la privacidad de los usuarios para aplicar las distintas clasificaciones existentes.
Es importante asegurarnos de completar este formulario de forma correcta ya que
podría ser motivo de retirada de nuestra aplicación, si se mostraran contenidos
inapropiados para nuestra calificación, por ejemplo, contenidos violentos sin
haberlo indicado.
Una vez completado pulsamos en el botón calcular clasificación.
Se nos mostrarán las calificaciones de nuestra aplicación en las distintas zonas
del mundo y si estamos de acuerdo las aplicaremos pulsando en el botón
correspondiente.
Una vez hecho ésto habremos completado todos los pasos mínimos requeridos
para poder publicar nuestra aplicación. En la parte superior derecha de la pantalla
nos aparecerá activo el botón correspondiente, y una vez lo pulsemos, nos
aparecerá un mensaje indicando que el proceso se esta realizando y que en varias
horas la aplicación estará disponible en la Play Store.
Normalmente en un máximo de 5 horas, menos en la mayoría de los casos la
aplicación estará disponible en la tienda de aplicaciones.
7.6. ASO (App Store Optimization)
En este último apartado conoceremos las medidas que podemos seguir para que las
aplicaciones que subamos a la tienda tengan más posibilidades de ser encontradas por los
usuarios, entre el sinfín de aplicaciones que existen actualmente en la Play Store.
Si bien se trata de conceptos más cercanos al marketing que al propio desarrollo, hoy en día
es muy común que los propios desarrolladores tengan que gestionar todos los aspectos
adicionales una vez lanzada la aplicación, especialmente si se trata de equipos muy pequeños
o incluso de una única persona.
Aunque Lo ideal es contar con personas cualificadas que puedan dedicarse a este tipo de
tareas, los conceptos principales son fáciles de entender y algunos podemos ponerlos en
práctica nosotros mismos sin una inversión excesiva de tiempo, así que es bueno tener unas
nociones sobre este área.
Para qué sirve el ASO
Como su propio nombre indica el ASO (App Store Optimization) es un conjunto
de medidas o prácticas destinadas a mejorar el posicionamiento de nuestra
aplicación en la tienda de aplicaciones (ésto es aplicable también para
aplicaciones iOS en la Apple Store), o lo que es lo mismo, a aumentar las
posibilidades de que los usuarios encuentren y utilicen nuestra aplicación. Algunos
lo llaman el "SEO para aplicaciones móviles".
SEO es un conjunto de técnicas y recomendaciones para que las páginas web salgan mejor
posicionadas en los resultados de búsqueda de buscadores como Google (sobre todo) o Bing.
El ASO suele englobar tres tipos de acciones:
 Optimizar elementos que influyan en los resultados de búsqueda de
las tiendas de Apps.
 Optimizar factores que afecten a las listas o rankings de esas tiendas.
 Optimizar aspectos que mejoren las conversiones en descargas e
instalaciones
Describiremos estos elementos o factores un poco más abajo. Poner en práctica
las recomendaciones ASO nos es muy útil, tanto si distribuimos una aplicación
gratuita que queramos que llegue al máximo número de usuarios, como si
queremos obtener ingresos con ella mediante venta directa, algun modelo
fremium o mediante impresiones de publicidad que mostremos en la aplicación.
Principales medidas o acciones
A continuación vamos a enumerar algunas de las principales medidas que
podemos llevar a cabo para mejorar nuestra posición en la Play Store, y en el
subapartado siguiente, entraremos más en detalle para el que esté interesado:
 Posicionamiento en búsquedas: una gran parte de los usuarios
descubren las aplicaciones a través del buscador de la tienda, por ello
debemos intentar que nuestra aplicación aparezca en las posición más
destacada posible en los resultados de las búsquedas. Lo más importante
para lograrlo es elegir las palabras clave o keywords con las que queremos
aparecer y optimizar los textos al definir la aplicación en la tienda,
utilizando dichos términos. Siempre debemos tener en cuenta que en las
palabras clave más comunes habrá más competencia y también que
siempre deben estar relacionados con nuestra aplicación o apareceremos
en búsquedas que no se convertirán en descargas. Hablaremos un poco
más en detalle de la elección y utilización de las palabras claves abajo.
 Elección de categoría: otra forma muy común que tiene los usuarios de
buscar aplicaciones es acudir directamente a los rankings de aplicaciones
más populares o descargadas en cada categoría. Elegir bien la categoría
de nuestra aplicación es importante ya que si conseguimos colocarnos
entre las destacadas conseguiremos muchas descargas de usuarios de
este tipo. Al igual que con las palabras clave debemos decidir si elegir las
categorías más comunes, con más visitas pero con mucha competencia u
otras en las que será mas fácil posicionarnos pero a cambio llegaremos a
menos usuarios.
 Valoraciones y comentarios: Tan importante como conseguir
instalaciones es que la reputación de nuestra aplicación sea la mejor
posible, y ésta se mide mediante la nota y los comentarios de los
usuarios. Por lógica deberían estar en relación a la calidad de nuestra
aplicación, pero la calidad no es una medida tan objetiva y siempre habrá
usuarios que valoren funciones o características que no hemos
implementado por no considerarlas prioritarias. Debemos responder a las
opiniones criticas de forma razonada, manteniendo un tono correcto,
aunque sean muy negativas e ignorando las provocaciones típicas de
'trolls'. Aprovechemoslos comentarios para corregir errores o aplicar
mejoras sugeridas, en la medida de nuestras posibilidades. Las respuestas
que demos y el nivel de mejora y actualización de la aplicación que
podamos ir ofreciendo, va a influir también en la valoración de los
usuarios.
 Enlaces externos: Los usuarios no llegarán a nuestra aplicación sólo
desde la tienda, también es necesario que puedan encontrarnos en los
principales canales de la red. Para ello es muy recomendable disponer de
una página web de nuestra aplicación bien posicionada en los buscadores
(aplicando técnicas SEO, que mencionamos antes brevemente) así como
de cuentas activas en las principales redes sociales (Twitter, Facebook,
Instagram, etc). Conocer y utilizar correctamente el lenguaje propio de
cada canal es vital para llegar al máximo numero de usuarios. También
podemos plantearnos alojar nuestra aplicación en tiendas alternativas, en
Android existen multitud de ellas.
 Promoción: Por último podemos plantearnos campañas de publicidad
para nuestra aplicación que complementen o refuercen el resto de
medidas. En ocasiones una campaña de anuncios bien diseñada nos
conseguirá un aumento puntual del volumen de instalaciones de la
aplicación, subiendo su posicionamiento en los rankings y mejorando el
resultado del resto de estrategias. Suelen ser recomendable utilizar las
redes de publicidad especializadas en formatosy segmento móvil, aparte
de anuncios en buscadores web o redes sociales, tanto por ser canales
online muy afines, como por el control que podemoshacer del
presupuesto y sus resultados (visitas y descargas conseguidas).
Todas estas medidas nos ayudarán a conseguir instalaciones pero hay tres
aspectos que no debemos olvidar:
 La calidad y originalidad de nuestra aplicación es primordial para
conseguir la recomendación de los usuarios. Hoy en día, el famoso 'boca a
boca', con el uso tan extendido de blogs, foros o redes sociales es uno de
los mejores medios para difundir nuestra aplicación.
 Debemos tener en mente qué necesidades cubre nuestra app y a qué
segmento de usuarios puede interesarle. Si definimos bien esa utilidad y el
tipo de usuario potencial de la aplicación, podremos imaginarnos mejor
cómo la buscarán en la tienda o en la propia web. Vemos un ejemplo
sencillo al final de este apartado.
 Aplicar algunas recomendaciones ASO nos puede ayudar, pero éstas son
mucho más efectivas si se desarrollan de forma continuada a lo largo del
tiempo, midiendo, analizando los resultados, y modificando y adaptando
según este seguimiento de resultados que hacemos.
Elementos/factores ASO
En este subarpartado vamos a ampliar algunos puntos antes expuestos, para aquellos que
tengan interés en este tema. No nos extenderemos en exceso, ya que éste no es un curso
sobre ASO o marketing digital. Esperamos publicar próximamente algunos artículos en
Academia Android para aquellos que quieran saber más sobre este apartado.
Los elementos o factores ASO los podríamos dividir en dos grupos, on-metadata y
off-metada. Explicamos qué significan y cuáles son.
Elementos ASO on-metadata
Son los elementos que podemos controlar directamente ya que son metadatos o
información relacionada con la App que definimos nosotros. Dentro de este
grupo tendríamos los metadatos que influyen en los resultados de búsquedas en
Google Play (en App Store es similar, aunque hay algunos que varían o difieren
respecto a éstos) y que asociamos a la Aplicación:
 Título de la aplicación: 30 caracteres
 Descripción: 4000 caracteres, aunque solo se muestran las primeras
lineas al usuario que tiene que pinchar si quiere ver más. Es por tanto una
descripción larga de lo que hace la aplicación, para qué sirve, que
características destacadas tiene, información sobre ella que queremos
resaltar, etc
 Descripción breve: 80 caracteres. Como indica su nombre, debemos
condensar lo fundamental que caracteriza nuestra aplicación
 Categoría: debemos ubicar nuestra App en alguna de las categorías o
temáticas que nos proporciona la tienda
De forma esquemática y resumida, en este grupo de 'campos', una buena
optimización consiste principalmente en:
 Selección cuidadosa de palabras clave, pensando en si nos interesa
competir en aquellas que tiene mucha popularidad y competencia o en
más específicas y menos populares. .Deberíamos también analizar la
'competencia' (que palabras clave emplean las apps similares a la nuestra)
o por qué términos buscan los usuarios.Citaremos abajo algunas
herramientas que ayudan en esta labor.
 Para el uso de estas keywords, deberemos tener en cuenta, entre otros,
los límites de caracteres de cada 'campo', el evitar la repetición
excesiva o infringir copyrights para no tener penalizaciones , o
la localización (traducción/adaptación a distintos idiomas si nos dirigimos
a mercados internacionales)
 El nombre/título de la App debería ser significativo, diferenciador y
atractivo para el usuario, incluyendo las palabras claves más significativas
 Debemos redactar una descripción clara de la App, que 'venda' y sea
informativa (las primeras líneas, recordemos, son fundamentales,
porque son las que se ven por defecto), destacando por ejemplo lo qué
ofrece al usuario o su valor diferencial. Debemos utilizar las palabras clave
que hemos seleccionado de una forma natural en la redacción.
 La elección de categoría es muy importante, con varios factores a
tener en cuenta: idoneidad, por qué categoría buscarían los usuarios una
App como la nuestra y competencia (quizás haya categorías menos
populares donde puede encajar nuestra App y aumentar nuestras
posibilidades de estar más altos en el ranking).
Habría un segundo conjunto que no influyen en el posicionamiento directamente
sino más en el grado de conversión de visitas a descarga e instalaciones. Se trata
principalmente de elementos que por su diseño e impacto visual puedan llamar la
atención del usuario:
 Icono
 Screenshots, es decir, capturas de pantalla de la aplicación
 Video demostrativo o promocionalde la aplicación
 Datos del desarrollador y actualizaciones de la aplicación
No nos detendremos en ellos, solo indicar que aunque los tres primeros parezcan
elementos accesorios, son muchas veces determinantes para que el usuario elija
entre las opciones que se le presentan en las búsquedas. En cuanto al cuarto, está
claro que ofrece más 'confianza' un perfil más completo y un historial de
actualizaciones activo (una app que se dejó de actualizar hace 3 años, no es un
buen reclamo para un usuario).
Elementos ASO off-metadata
Son elementos o factores en los que quizás podemos influir algo, pero están fuera
de nuestro control, como son:
 Número de descargas
 Valoración: el rating que consigue la aplicación según la puntúan o votan
los usuarios
 Comentarios: el numero y contenido de los comentarios (*reviews*) que
realizan los usuarios
 La velocidad de las descargas: en cuánto tiempo se ha conseguido el
total de descargas. Por ejemplo, si no es un volumen muy alto, pero ha
sido en poco tiempo y de forma reciente, parece indicar que es una app
nueva que ha ganado popularidad en cuanto se está conociendo, lo que
atrae aún más a los usuarios.
Selección y empleo de palabras clave
Vamos a poner un ejemplo muy simplificado, pero que nos puede ayudar a visualizar algunas
cuestiones que hemos expuesto anteriormente.
Imaginemos que desarrollamos una aplicación que facilita la gestión de
información relacionada con el el curso académico de cualquier colegio:
fiestas, fechas de exámenes, reuniones (tutoría, asociación de padres), actividades
extraescolares,...Lo primero que debemos tener en mente es a quiénes la dirigimos y qué
finalidad o necesidades cubre. En este caso vamos a suponer que facilita a los padres de los
alumnos la gestión de los eventos y el recordatorio de información relacionada con la actividad
escolar de sus hijos.
Con estas premisas, ¿cómo creemos que ese tipo de usuario puede buscar una aplicación
como la nuestra? Ahí empieza una investigación que puede partir de un análisis propio ,
donde pensemos en listas de palabras relacionadas con el contexto de la aplicación: colegio,
escuela, exámenes, tutorías..., y donde podemos utilizar diccionarios o thesaurus de
sinónimos para sugerirnos más términos.
El siguiente paso podría ser un análisis en Google Play de aplicaciones similares
a la nuestra viendo que nombres y descripciones emplean. Podríamos incluso ir más allá y
utilizar herramientas online especializadas como ésta, pero es algo que ya exige más
experiencia y/o un coste de uso, y no vamos a entrar en ello.
Por otro lado, tras realizar ese análisis, debemos valorar si las palabras clave que
mejor nos encajan, son las más adecuadas en cuanto a popularidad y la
competencia que podemos encontrar. Por ejemplo, la palabra clave 'agenda'
seguramente tenga muchas búsquedas, pero nuestras posibilidades de salir alto en los
resultados serán seguramente más bajas y además no especifica del todo lo que hace nuestra
aplicación. En cambio con 'agenda escolar' podríamos estar mejor situados y corresponder
más con la utilidad que el usuario estaba buscando (las palabras claves pueden considerarlas
compuestas de varios términos, haciendo que aparezcan seguidos o muy juntos en los
campos de (meta)información de la aplicación).
¿Cómo definimos a los algoritmos de indexación de los buscadores cuáles son nuestras
palabras claves? Realmente no lo hacemos de forma explícita, sino utilizándolas en los
campos de metadatos on-page que presentamos antes (los buscadores suelen también
'entender' y asociar variaciones de esas palabras:singular/plural....). Si queremos
posicionarnos por 'agenda escolar' podemos llamar a nuestra aplicación
"La agenda escolar" y redactar en las descripciones algo así:
"Si quiere gestionar la agenda escolar del colegio de sus hijos, esta es su
aplicación. En ella puede recordar la agenda de reuniones escolares (tutorías,
asambleas de padres de alumnos), registrar los contactos de profesores, llevar
la agenda de actividades extra-escolares......)."
Ésto será más apropiado que llamar a nuestra aplicación "Mi agenda" ó "Gestión de las
actividades del colegio" y redactar una descripción donde no incidimos es esas palabras
claves, como por ejemplo:
"Esta aplicación está principalmente pensada para gestionar reuniones, actividades o
almacenar contactos de temas relacionados con el colegio de nuestros hijos...".
En cualquier caso, ya decimos que este es un ejemplo simplificado, porque puede
interesarnos también posicionarnos por palabras claves como 'agenda del colegio',
'actividades escolares', 'gestión del curso', 'fechas de exámenes'..., y/o haber optado por algo
aún más específico como ' agenda escolar de los padres'. Eso exigiría establecer una
prioridad: las más importantes deben aparecer siempre, incluyendo el título, mientras que
otras pueden emplearse en las dos descripciones o solo en la descripción larga.
También convendría refinarlo y no quedarnos con la primera versión que se nos ocurra. Las
palabras claves deben emplearse de una manera natural y no excesivamente repetitiva.
Deberíamos probar diversas versiones de la descripción y quedarnos con la que
creamos que mejor consigue atraer el interés del usuario y además puede dejar lo más claro
posible, tanto a él como al algoritmo automático de clasificación, de cuál es su función.
Desafortunadamente no sabemnos exactamente como funcionan esos algoritmos y es más
una cuestión de sentido común, que algo exacto. Eso sí, debemos evitar 'abusar' de las
keywords, porque seguramente el algoritmo nos penalizará, aparte de que para el usuario
sería una descripción sin sentido y de poca utilidad (por ejemplo si en la descripción solo
ponemos 'agenda escolar' repetida continuamente hasta agotar los caracteres).
Nota: este ejemplo es puramente teórico, y no se ha consultado Google Play ni
ningún otro servicio. Pueden esxistir apps con estos nombres o similares, pero no
tienen relación alguna con este ejemplo

Más contenido relacionado

PPTX
Iniciación a Android
PPT
Curso Introducción a android
PPT
Fundamentos del Desarrollo de Aplicaciones para Android
PPTX
Tema: Android Studio
PDF
Entornos-de-Desarrollo-Eclipse-y-Android-SDK
PPT
Tutorial Android 1
DOCX
Componentes necesarios de android docx
PDF
Conceptos y Generalidades de Android
Iniciación a Android
Curso Introducción a android
Fundamentos del Desarrollo de Aplicaciones para Android
Tema: Android Studio
Entornos-de-Desarrollo-Eclipse-y-Android-SDK
Tutorial Android 1
Componentes necesarios de android docx
Conceptos y Generalidades de Android

La actualidad más candente (20)

PDF
Exposición 20 aniversario linux
PDF
"Android de la A a la Z" -- Unidad 3
PDF
"Android de la A a la Z" -- Unidad 6
ODP
Android studio
PDF
android evolution
DOCX
"Android de la A a la Z" -- Unidad 2
PDF
Material rap1
DOCX
R esume libro el gran libro de android
PDF
Instalacion-y-Configuracion-de-Android-Studio-con-Genymotion
PPT
Curso desarrollo en android
DOCX
Proyecto final(2)
PDF
Generalidades-de-Android-Estudio
DOCX
Manual de Apps Basicas para Android
DOCX
ANdroid studio
PDF
"Android de la A a la Z" -- Unidad 8
PDF
"Android de la A a la Z" -- Unidad 4
PPT
Fundamentos desarrollo de Apps para Android
PDF
Exposición 20 aniversario linux
"Android de la A a la Z" -- Unidad 3
"Android de la A a la Z" -- Unidad 6
Android studio
android evolution
"Android de la A a la Z" -- Unidad 2
Material rap1
R esume libro el gran libro de android
Instalacion-y-Configuracion-de-Android-Studio-con-Genymotion
Curso desarrollo en android
Proyecto final(2)
Generalidades-de-Android-Estudio
Manual de Apps Basicas para Android
ANdroid studio
"Android de la A a la Z" -- Unidad 8
"Android de la A a la Z" -- Unidad 4
Fundamentos desarrollo de Apps para Android
Publicidad

Similar a Curso Android 2021 (20)

PDF
Breve introducción a Android Apps
PPTX
DOCX
Que es android studio
DOCX
Android.docx
DOCX
Android
PDF
Exposición 20 aniversario linux
PDF
Taller de prog. en android
DOCX
Lenguajes de Programación: Android
PPTX
App inventor
PPT
PDF
Introducción a la programación androide
PPT
Android QuickStart
PDF
Tarea de christopher enriquez
PDF
Tutorial Eclipse
PDF
Guía básica de programación en android
PDF
Manual Android
PDF
TUTORIAL ECLIPSE
PDF
PDF
12j sistemaandroid texto
Breve introducción a Android Apps
Que es android studio
Android.docx
Android
Exposición 20 aniversario linux
Taller de prog. en android
Lenguajes de Programación: Android
App inventor
Introducción a la programación androide
Android QuickStart
Tarea de christopher enriquez
Tutorial Eclipse
Guía básica de programación en android
Manual Android
TUTORIAL ECLIPSE
12j sistemaandroid texto
Publicidad

Más de elprofenava2002 (7)

PPTX
resumen-de-redes.pptx
PDF
diagnostico
PDF
matematicas
PDF
PPT
Principios poo
DOC
Ensambles ecuencia didactica 1_3
DOC
Ensambles ecuencia didactica 1_3
resumen-de-redes.pptx
diagnostico
matematicas
Principios poo
Ensambles ecuencia didactica 1_3
Ensambles ecuencia didactica 1_3

Curso Android 2021

  • 1. Desarrollo de Aplicaciones para Android (con Android Studio) Introducción y objetivos En este Módulo 0 introductorio, veremos:  Una visión general de lo que es Android  Las características más importantes de este sistema operativo. Máquinas virtuales Dalvik y ART  La tipología de dispositivos que actualmente lo utilizan  La cuota de mercado que tiene Android en el conjunto de sistemas operativos móviles  La fragmentación de las distintas versiones Android (su % de implementación/uso en los dispositivos actuales) El objetivo de este módulo es que obtengas una visión general de lo que es Android y sus principales características, así como conocer su grado de uso/implementación en el mercado actual de smartphones y dispositivos móviles en general. Dado que este tema tiene un carácter principalmente informativo y no planteamos ejercicios prácticos, lo hemos numerado como '0' para diferenciarlo del resto de temas donde ya empezamos a tratar de forma práctica el desarrollo en Android. Aunque es un módulo que puede considerarse opcional, te recomendamos leerlo para conocer mejor el contexto de este sistema operativo, y si quieres, realizar el test, para comprobar tus conocimientos de una manera informal. Última modificación: viernes, 2 de septiembre de 2016, 18:10 Qué es Android Android es un sistema operativo diseñado principalmente para trabajar sobre smartphones (teléfonos inteligentes), aunque hoy en día nos lo podemos encontrar también en tablets, relojes (smartwatches), netbooks, ordenadores, televisores, vehículos...Pero Android no es solamente un sistema operativo, también es un lenguaje de programación y un framework para desarrollo de aplicaciones. Al conjunto de todos estos elementos es a lo que llamamos Android. Inicialmente fue desarrollado por una pequeña empresa llamada Android Inc., fundada, entre otros, por Andy Rubin en 2003, la cual fue comprada por Google en el año 2005. Dos años más tarde, el 5 de noviembre de 2007, fue anunciada la distribución de Android junto con la fundación de la Open Handset Alliance, un conjunto de fabricantes y desarrolladores de hardware, software y telecomunicaciones dedicados a la promoción de estándares abiertos para dispositivos móviles. Google lanzó la mayor parte del código de Android bajo la licencia Apache, una licencia de software libre. Pero no fue hasta septiembre del año siguiente cuando salió el primer terminal
  • 2. con Android, el HTC Dream, que disponía de Android 1.0. Desde entonces han ido apareciendo diversas versiones hasta llegar a la versión 7.0 (Junio de 2016. Puedes ver un listado de versiones y fecha de aparición en el apartado final de este módulo). Tiene una gran comunidad de desarrolladores escribiendo aplicaciones de todo tipo, tanto gratis como de pago. Ya en 2014 se sobrepasó la cifra de 1.000.000 de aplicaciones activas en Google Play, la tienda de aplicaciones oficial de Android, superando al número que tenía la App Store de Apple para iOS. Los programas principalmente están escritos en el lenguaje de programación Java, aunque se pueden implementar partes de un programa en un lenguaje nativo, como C o C++ mediante la herramienta Android NDK. Las aplicaciones son compiladas por el Android SDK en formato .apk, instalables en cualquier dispositivo Android. Una vez instaladas, cada aplicación posee su propia seguridad:  El sistema operativo Android es un sistema Linux multiusuario en donde cada aplicación es un usuario diferente.  Por defecto, el sistema asigna a cada aplicación un identificador único de usuario, que es usado sólo por el sistema.  Cada proceso tiene su propia máquina virtual, luego el código de una aplicación se ejecuta aisladamente de las demás aplicaciones.  Por defecto, cada aplicación corre su propio proceso Linux. Android inicia el proceso cuando alguno de los componentes de la aplicación necesita ser ejecutado, después para el proceso cuando ya no se necesita más o cuando el sistema necesita recuperar memoria para otras aplicaciones. De este modo, el sistema Android implementa el principio del mínimo privilegio, es decir, cada aplicación por defecto sólo tiene acceso a los componentes que sean necesarios para poder funcionar correctamente. Esto genera un entorno muy seguro en el que una aplicación no podrá acceder a partes del sistema sin antes pedir permiso para ello. Sin embargo, hay modos mediante los cuales una aplicación puede compartir datos con otras y poder acceder a servicios del sistema:  Es posible disponer de dos aplicaciones que compartan el mismo identificador de usuario, por lo que será posible acceder a los archivos de cada uno de ellos. Para preservar los recursos del sistema, estas aplicaciones podrán ser ejecutadas bajo el mismo proceso Linux y compartir la misma máquina virtual (para ello deben ser firmadas con el mismo certificado).  Una aplicación puede pedir permiso para acceder a los datos del dispositivo, como pueden ser los contactos, los mensajes SMS, la tarjeta SD, la cámara, el Bluetooth, etc. Todos estos permisos han de ser aceptados por el usuario en el momento de su instalación.
  • 3. En este segundo tema, explicaremos cómo empezar a programar en Android, desde la instalación del entorno, pasando por la instalación del SDK y las Android Development Tools (en adelante ADT) hasta llegar a la creación y ejecución de un programa ejemplo, el Hola Mundo. Al término de este tema, el alumno será capaz de:  Instalar y configurar un entorno de desarrollo junto con las herramientas necesarias para empezar a programar en Android.  Identificar los distintos canales y tipos de versiones que están disponibles para Android Studio  Crear su primera aplicación en Android y la ejecución de la misma en un emulador. 1.2. Entorno de desarrollo Android Studio 1.2 Entorno de desarrollo Android Studio. Android Studio es un entorno de desarrollo integrado (IDE), desarrollado por Google a partir de IntelliJ IDEA (de la compañia JetBrains). A finales de 2014, Google lo convirtió en el IDE oficial para Android, sutituyendo al plugin ADT (Android Developer Tools) para el IDE Eclipse que venía siendo la herramienta recomendada y más utilizada hasta ese momento. Con la aparición de Android Studio, Google conseguía crear un entorno dedicado específicamente a la programación de aplicaciones para dispositivos Android, teniendo además un mayor control sobre su proceso y ritmo de desarrollo y la incorporación de nuevas funcionalidades. Android Studio utiliza una licencia de software libre Apache 2.0, está programado en Java y es multiplataforma. Android Studio se presentó en mayo de 2013 y la primera versión estable 1.o se liberó en diciembre de 2014, manteniéndose desde entonces un alto ritmo de actualizaciones (a fecha de Septiembre de 2016, ya están disponibles las versiones 2.X).
  • 4. Logos de Android Studio: original de 2013 (robot androide: izquierda) y logo actual (compás: derecha) Principales características que incluye Android Studio Vamos a enumerar algunas de las características más destacadas de este IDE (hay que tener en cuenta que la incorporación de nuevas funcionalidades es casi continua con las nuevas versiones que van apareciendo):  Soporte para programar aplicaciones no solo para teléfonos y tablets sino también para las otras plataformas Android como Android Wear (para dispositivos corporales
  • 5. o wearables como los relojes smartwatch), Auto (para vehículos), Glass (para gafas) y TV (televisión).  Instant Run que permite visualizar al instante los cambios que introduzcamos en el código y los recursos de la app en ejecución en un dispositivo o emulador, sin necesidad de compilar nuevamente.  Editor de código inteligente que ofrece refactorización y completado avanzado de código (presenta sugerencias en una lista desplegable mientras escribes)  Herramientas Lint: detecta código no compatible entre arquitecturas diferentes o código confuso que no es capaz de controlar el compilador, para detectar problemas de rendimiento, usabilidad y compatibilidad de versiones.  Utiliza ProGuard para optimizar y reducir el código del proyecto al exportar a APK (muy útil para dispositivos de gama baja con limitaciones de memoria interna).  Permite construir variantes y generación de múltiples APK. Podemos por tanto crear diferentes versiones de la misma aplicación, por ejemplo una versión de pago y otra gratuita, o para diferentes dispositivos o almacenes de datos.  Integración de la herramienta Gradle encargada de gestionar y automatizar la construcción de proyectos, como pueden ser las tareas de testing, compilación o empaquetado.  Construcción y gestión de proyectos basado en Maven (herramienta de software para la gestión y construcción de proyectos Java, similar a Apache ANT, pero su modelo es más simple ya que está basado en XML)  Soporte para NDK (Native Development Kit: herramientas para implementar código nativo escrito en C y C++)  Interfaz específica para el desarrollo en Android.  Editor de diseño que muestra una vista previa de los cambios realizados directamente en el archivo xml.  Vista previa en diferentes dispositivos y resoluciones.  Permite la importación de proyectos realizados en el entorno Eclipse, que utiliza ANT (a diferencia de Android Studio que utiliza Gradle) .  Posibilita el control de versiones accediendo a un repositorio desde el que poder descargar Mercurial, Git, Github o Subversion.  Alertas en tiempo real de errores sintácticos, compatibilidad o rendimiento antes de compilar la aplicación.  Integración con Google Cloud Platform, para el acceso a los diferentes servicios que proporciona Google en la nube. Requerimientos del sistema Te presentamos los requisitos hardware y software que necesita tu equipo para que Android Studio funcione adecuadamente. Destacamos la necesidad de disponer de suficiente memoria RAM (aconsejable 8 GB), sobre todo si pruebas con un emulador y no en dispositivo físico.
  • 6. Windows Mac OS Linux Microsoft Windows 7/8/10 (32 o 64 bit) Mac OS X 10.8.5 o superior, hasta la 10.11.4 (El Capitan) GNOME o entorno de escritorio KDE (probado en Ubuntu 12.04 Precise Pangolin) Mínimo de 2 GB de RAM, recomendado 8 GB de RAM 2 GB de espacio mínimo en disco (500 MB para IDE + 1,5 GB para SDK) Para emulador acelerado: sistema operativo 64 bits y procesador Intel con VT-x, EM64T y Executable Disable (XD) Bit Resolución mínima de pantalla de 1280 x 800 Java Development Kit (JDK) 7 o superior Nota: Para los sistemas Linux será necesaria la biblioteca de C GNU (glibc) 2.11 o posterior. Además para los sistemas Mac OS será necesario ejecutar Android Studio con Java Runtime Environment (JRE) 6 para la renderización optimizada de fuentes. Los requisitos generales que hemos indicado en la tabla pueden variar con nuevas versiones. Puedes consultar las últimas especificaciones al final de la página de descarga de Android Studio Android Studio vs Eclipse: si has trabajado con Eclipse en el desarrollo de Apps Android, puedes ver una comparación de este IDE con las primera versión estable de Android Studio en nuestra web Academia Android 1.3. Descarga e instalación de Android Studio
  • 7. La última versión de Android Studio disponible la puedes descargarse desde el siguiente enlace: https://developer.android.com/sdk/index.html. La versión para Windows aparece destacada según vemos en esta imagen (en el momento de consultarla seguramente te aparecerá una versión disponible más avanzada que la de esta imagen): pero podemos acceder también a las versiones para Linux o Mac al hacer scroll hacia abajo en esta página:
  • 8. Otras versiones de Android Studio: puedes descargar las diversas versiones estables que han ido apareciendo en el canal Stable, así como versiones en proceso de desarrollo y pruebas a través de los diferentes canales Canary, Dev, y Beta a los que puedes acceder a través del enlace: http://tools.android.com/download/studio
  • 9. Proceso de instalación Tras la descarga del instalador, bastará con realizar doble click sobre el archivo con extensión .exe descargado. A continuación, comenzará el proceso de instalación: Notas:  Debes tener instalado en tu equipo el JDK (Java Development Kit), en versión 7 ó superior. El proceso de instalación de Android Studio lo comprobará y si no lo detecta te ofrecerá descargarlo e instalarlo desde la web de Oracle. Aunque es muy probable que ya hayas trabajado con Java y lo tengas disponible y actualizado, te hemos preparado un video que tienes a continuación de este apartado donde puedes ver todo el proceso y cómo configurar las variables de entorno Java en Windows.  Cuando realices el proceso de instalación de Android Studio, éste puede variar ligeramente respecto a los pasos e imágenes que te mostramos a continuación dado los continuos cambios que introduce Google. En cualquier caso serán muy similares y fáciles de entender a partir de esta guía. 1. Inicialmente, mostrará una pantalla de bienvenida a la instalación de Android Studio, en la que sólo se deberá pulsar en "Next":
  • 10. 2. Posteriormente, solicitará que se indiquen los componentes que se desean instalar/desinstalar. Elegiremos la opción por defecto que instala tanto el SDK como el AVD. Una vez seleccionados los componentes, se continuará pulsando en "Next" :
  • 11. SDK: El Software Development Kit es como su nombre indica un kit o conjunto de herramientas con él podremos desarrollar aplicaciones Android para cualquiera de las versiones disponibles de este sistema. Cuando lo instalemos podremos seleccionar a través del entorno SDK Manager (al que accederemos a través de un botón en el menú de herramientas de Android Studio), la instalación y descarga de paquetes (Packages) de herramientas, APIs, fuentes, ejemplos, ... Por tanto las Apps Android las desarrollaremos en lenguaje Java con este kit. AVD: para probar nuestras aplicaciones, podemos crear máquinas virtuales que emulen las características de un teléfono Android, una tablet, o un dispositivo Android Wear o Android TV. El administrador de AVD (Android Virtual Devices), al que accederemos también a través de un botón en la barra de herramientas de Android Studio, nos permite crear y definir dichos dispositivos virtuales. Veremos que hay otras opciones como el emulador GenyMotion, además de poder probar directamente en nuestro dispositivo Android si lo tenemos. 3. En la siguiente ventana, se deberán aceptar los términos de licencia, seleccionando la opción "I Agree": 4. A continuación, se deberá indicar los directorios de instalación del IDE Android Studio y del SDK Android. En este caso, dejamos las opciones por defecto, aunqeu podemos elegir lógicamente otras. Será necesario un espacio en disco de al menos 500 MB para Android Studio y 3,2 GB para el SDK. Se pulsará en "Next" para continuar el proceso de instalación:
  • 12. 5. Tras seleccionar los directorios de instalación, mostrará una ventana indicando si se ha detectado que nuestro sistema puede iniciar un emulador de Android en modo de rendimiento acelerado. Además solicitará que se indique la cantidad máxima de memoria RAM disponible para el motor de virtualización asistido por hardware, que proporciona Intel(r) HAXM. Se pulsará en "Next" para continuar: Nota: veremos más sobre HAXM (Intel Hardware Accelerated Execution Manager) es el apartado de creación de un emulador
  • 13. 6. Otra opción de configuración durante el proceso de instalación, será la selección o creación de las carpetas que formen el menú de inicio de Android Studio, para el acceso directo al programa en cuestión. En el ejemplo se dejan los valores por defecto de la instalación:
  • 14. 7. Al pulsar en el botón "Install" de la ventana anterior, comenzará el proceso de instalación:
  • 15. 8. Una vez el proceso ha finalizado, se pulsará sobre "Next", indicando en la siguiente ventana que el proceso de instalación se ha completado. Además permitirá tanto el inicio del IDE Android Studio, como la importación de proyectos realizados con el plugin ADT de Android en Eclipse o en versiones anteriores de Android Studio. Se pulsará sobre "Finish" para terminar el proceso de instalación:
  • 16. 9. Al arrancar Android Studio por primera vez nos aparecerá la pantalla de asistente de configuración ("Setup Wizard") donde nos dará a elegir entre una configuración 'Standard' o 'Custom' (personalizada). Si elegimos la opción estándar completará la descarga e instalación de paquetes seleccionados en el proceso anterior y si elegimos la personalizada, aparecerán una serie de ventanas preguntándonos sobre diversas elecciones, tal como te mostramos en el segundo video que tienes sobre la instalación de Android Studio.
  • 17. Video: instalación JDK (Java Development Kit) En el caso de que no tengas el JDK (Java Development Kit) en tu equipo, el proceso de instalación de Android Studio te pedirá que lo instales ya que es imprescindible para el funcionamiento del entorno de desarrollo. En este video puedes ver cómo instalarlo y cómo configurar las variables de entorno para Java en tu equipo (se muestra el ejemplo con el sistema operativo Windows)
  • 18. 2.1. Introducción y objetivos En este tema veremos los distintos componentes software que podemos utilizar en Android y cómo construir una primera App con algunos de esos componentes (activity e intents). También describiremos el fichero AndroidManifest.xml, fundamental en cualquier aplicación Android. En este tema aprenderás:  Cuáles son los componentes básicos con lo que crear una App Android: Activities, Services, Intents, Content Provider y Broadcast Receivers.  Cómo implementar una Activity y su ciclo de vida.  La estructura y función del fichero AndroidManifest.xml.  Construir un archivo APK del proyecto desarrollado.  Cómo usar de un Intent para enviar información entre Activities y cómo crear intefaces de usuario básicas, a través de un proyecto ejemplo que crearemos. 2.2 Componentes de una Aplicación Android: Activities, Services, Intents, Content Provider y Broadcast Receivers Activities, Services, Intents, Content Provider y Broadcast Receivers Android facilita la creación de aplicaciones gracias al uso de un conjunto de componentes software reutilizables. Vamos a explicar los principales y cómo podemos implementarlos dentro de un proyecto Android:
  • 19. Activity Éste es el componente principal de la interfaz gráfica de una aplicación en Android. A cada Activity se le asigna una ventana en la cual se dibuja la interfaz de usuario, con la que el usuario podrá interaccionar para realizar las diversas acciones que hayamos contemplado en la aplicación. Para construir la interfaz gráfica, cómo veremos en el tema 3, tenemos los componentes denominados Views (vistas) con lo que dispondremos de numerosos controles básicos, como por ejemplo, botones, listas desplegables o cuadros de texto, pudiendo extender la funcionalidad de estos controles o crear otros personalizados. Por lo general, una aplicación está formada por diferentes Activities, que están más o menos ligadas entre sí. Cuando se suceden varias, éstas se van almacenando en una pila mediante el mecanismo de LIFO (Last In - First Out: la última que entra en la pila es la primera que sale) y cuando el usuario pulsa el botón atrás, se extrae la Activity actual de la pila y se reanuda la anterior Activity situada allí. Cada Activity que creemos, la tenemos que definir en el AndroidManifest.xml (explicamos este fichero en un siguiente apartado) con la etiqueta <activity>. Para iniciar una Activity, podemos utilizar dos métodos (como veremos más adelante):  Método Context.startActivity()  Método Context.startActivityForResult() , cuando queramos que se devuelva algún resultado. También mencionar que tenemos otros componentes que funcionan dentro del ámbito de una Activity, los Fragments, que amplían y enriquecen las posibilidades de interacción con el usuario. Service Los services (servicios) son componentes sin interfaz gráfica que se ejecutan en segundo plano. Son llamados a través de otro componente, como puede ser una Activity, y seguirán ejecutándose en segundo plano aunque la Activity haya finalizado o, incluso, aunque hayamos salido de la aplicación.
  • 20. Cada servicio que creemos lo tenemos que declarar en el AndroidManifest.xml mediante la etiqueta <service> . Para ser iniciados podemos usar dos métodos:  Método Context.startService()  Método Context.bindService() Intent Un Intent es el elemento básico de comunicación entre los componentes que estamos describiendo, es decir, mediante un Intent se podrá llamar a una Activity, iniciar un servicio, enviar un mensaje broadcast, iniciar otra aplicación, etc. Su uso más importante es para iniciar Activities, por lo que puede considerarse como la unión entre Activities. Más adelante veremos cómo hacer esto. Los objetos Intent están formados por un paquete de información. Contienen información de interés para el componente que la recibe, como la acción que será ejecutada y los datos necesarios, más la información de interés para el sistema Android, como la categoría del componente que manejará el Intent y las instrucciones de cómo lanzar la Activity. Principalmente pueden contener lo siguiente:  Nombre de componente: el nombre del componente que manejará el Intent. Es una combinación del nombre de la clase del componente y el nombre del paquete especificado en el AndroidManifest.xml de la aplicación donde reside el componente (por ejemplo, com.academiaandroid.holamundo.Activity). Esto es opcional. Si lo definimos, se creará una instancia de la clase designada. Si no es así, se usará otro tipo de información para localizar el objetivo deseado.  Acción: una cadena de texto que designa la acción a ser ejecutada. La clase Intent define una serie de ellas como pueden ser las siguientes, entre otras: o ACTION_CALL :Inicia una llamada telefónica. o ACTION_EDIT :Muestra datos para que el usuario pueda editarlos (como los datos de un contacto). o ACTION_MAIN :Indica la Activity principal de una aplicación, la que se ejecutará al iniciarse.
  • 21. Nosotros también podemos definir las nuestras propias para activar componentes en nuestra aplicación. Las que definamos, tienen que incluir el nombre del paquete como prefijo, por ejemplo: com.academiaandroid.holamundo.SHOW_COLOR . Estas acciones se podrán establecer mediante el método setAction() y obtenerlas a través de getAction() . Nota: en este mismo tema veremos un ejemplo completo del uso del componente Intent para lanzar y enviar parámetros a una segunda Activity. Content Provider Un Content Provider es un componente destinado a compartir datos entre aplicaciones. Dichos datos pueden ser almacenados en el sistema de archivos, en una base de datos SQLite o en cualquier otro lugar que sea accesible desde nuestra aplicación. Un ejemplo de Content Provider es el que utiliza Android para gestionar la información de un contacto, mediante el cual cualquier aplicación podrá acceder a estos datos haciendo una petición al método query() sobre la interfaz ContentResolver . Broadcast Receiver Un Broadcast Receiver es un componente que detecta y reacciona frente a mensajes globales del sistema, como puede ser batería baja, SMS recibido, llamada recibida, etc. Además de esto, una aplicación también puede iniciar un Broadcast Receiver (por ejemplo, para saber si se han descargado datos al dispositivo y poder ser usados por esa aplicación). Al igual que ocurría con los Services, un Broadcast Receiver tampoco muestra ninguna interfaz gráfica. Al igual que los servicios y Activities, los Broadcast Receiver también los tenemos que registrar, pero esta vez tenemos dos formas de hacerlo:  Método Context.registerReceiver()  declarándolos en el AndroidManifest.xml con la etiqueta <receiver>
  • 22. Si registramos un broadcast receiver en el onResume() de una Activity, se debe borrar en el onPause() de la misma Activity mediante el método Context.unregisterReceiver() . Nota: en el próximo apartado veremos el ciclo de vida de una Activity donde explicaremos los diferentes estados por los que puede pasar y los métodos asociados.. Por ejemplo, los dos que hemos citado en el párrafo anterior: método onPause(), para pasar a estado 'en pausa o interrumpida' y método onResume(), para reanudarla. Para iniciar un Broadcast Receiver podemos usar dos alternativas:  Método Context.sendBroadcast() , si queremos iniciar un broadcast 'desordenado' (sin esperar nada a cambio, sería un modo de comunicación hacia un lado)  Método Context.sendOrderedBroadcast() , si queremos que por el contrario sea 'ordenado' (lo que significa que los receptores de este broadcast pueden devolver información como respuesta a ello) 2.3. Activity: creación y ciclo de vida Tras presentar los componentes fundamentales de una Aplicación Android, vamos a ver cómo podemos implementarlos utilizando el IDE Android Studio y en concreto, nos centraremos en la creación de una Activy, de la que también describiremos su ciclo de vida posterior. Creación de una Activity En el siguiente diagrama, vemos como es el proceso de implementación de un nuevo componente dentro de un proyecto ya existente (pincha la imagen para ampliarla):
  • 23. Si utilizamos como ejemplo la implementación de una nueva Activity en un proyecto ya disponible, realizaríamos los siguientes pasos:  Como se puede apreciar en el diagrama de arriba, pulsaremos con el botón derecho del ratón sobre el packages del proyecto donde se encuentran las clases del mismo.  A continuación, seguimos la ruta New > Activity y seleccionamos la opción Blank Activity que permitirá crear una plantilla con un diseño básico en el proyecto (en las nuevas versiones de Android Studio elegiríamos Empty Activity, que sería la opción similar a ésta).  Si nos fijamos en la imagen de abajo, vemos la siguiente ventana que nos aparecerá, con las distintas opciones (están numeradas de acuerdo a como hemos marcado en la imagen): o 1: nombre de Activity o 2: nombre de layout o 3: el título que se mostrará en la parte superior de la Activity o 4: si se trata o no de la Activity que será lanzada al compilar el proyecto o 5: si hará uso de un Fragment o 6: permite establecer herencia de otras clases ya implementadas o 7: indicar el nombre del paquete al que pertenecerá o 8: visualizar el resultado de la interfaz de usuario (situado a la izquierda de las opciones de configuración).
  • 24. Por último pulsaremos sobre "Finish" para crear una nueva Activity en el proyecto. Ciclo de vida de una aplicación Android Como explicamos en la anterior publicación, una Activity es un componente principal de la interfaz gráfica de una aplicación en Android, y se asocia con una ventana donde se define la interfaz de usuario para interaccionar con la aplicación. Estas serán manejadas como una pila en el sistema, es decir, cuando una Activity se inicia, ésta se posiciona al principio de la pila, y pasará a ser la Activity que veamos en ese momento. Una Activity tiene esencialmente cuatro estados:  Activa: si la Activity está en primer plano (si la estamos viendo actualmente), se dice que está activa o ejecutándose.  En pausa: si la Activity ha perdido el foco, pero sigue siendo visible (por ejemplo, cuando se inicia otra Activity que no ocupa la pantalla entera), se dice que está en pausa o detenida. Una Activity detenida sigue permaneciendo en memoria pero puede ser 'matada' o interrumpida por el sistema en condiciones de baja memoria.
  • 25.  Parada: si la Activity deja de ser visible (por ejemplo, cuando se inicia otra Activity que ocupe la pantalla entera), se dice que está parada. Aun así sigue permaneciendo en memoria, aunque puede ser 'matada' por el sistema en condiciones de baja memoria.  Eliminada: si una Activity está pausada o parada, el sistema puede eliminarla de memoria matando el proceso o mandándole la señal de que finalice. Cuando vuelva a ser visible por el usuario, ésta debe ser completamente reiniciada. A nivel de código podríamos reflejarlo de la siguiente manera: public class Activity extends ApplicationContext { protected void onCreate(Bundle savedInstanceState); protected void onStart(); protected void onRestart(); protected void onResume(); protected void onPause(); protected void onStop(); protected void onDestroy(); } El siguiente diagrama describe de forma gráfica los distintos estados por los que puede pasar una Activity:
  • 26. Imagen de Android Developer, licencia Apache 2.0 2.4. Fichero AndroidManifest.xml Continuando con los primeros pasos para la creación de una Aplicación Android, vamos a describir el archivo AndroidManifest.xml, un fichero indispensable en un proyecto Android que cada aplicación deberá contener (con ese mismo nombre) en su directorio raíz.
  • 27. Este archivo contendrá información esencial acerca de la App, por lo que el sistema Android deberá acceder a él antes de compilar cualquier línea de código del proyecto. De manera resumida, cumple las siguientes funciones:  Establece el nombre del package de la aplicación, para identificar de manera única a la aplicación.  Permite definir los componentes de la aplicación, es decir, Activities, Services, Content Providers etc., estableciendo qué clases implementan cada componente.  Determina que Activity será lanzada inicialmente.  Declara el nivel mínimo de la API que Android requiere para la aplicación.  Se declaran los permisos que necesita la aplicación para realizar determinadas tareas, cómo el acceso a contactos del teléfono o realizar llamadas de teléfono, accediendo a zonas restringidas de la API e interactuando con otras aplicaciones (ampliamos un poco este punto más abajo), A continuación mostramos la estructura general del archivo AndroidManifest.xml, con los elementos que puede contener. Hemos incluido un breve comentario en cada uno para dar una primera idea de su función. <?xml version="1.0" encoding="utf-8"?> <manifest> //Elemento raíz del fichero. Debe contener un elemento <application> <uses-permission /> //Permisos que debe aceptar el usuario al instalar la App <permission /> //Permiso de seguridad para limitar acceso a un componente o funcionalidad específica <permission-tree /> //Nombre base para un árbol de permisos (ej: com.academiaand roid.proyecto.audio) <permission-group /> //Nombre para un grupo lógico de permisos afines <instrumentation /> //Permite monitorizar interacciones de la App con el sistema <uses-sdk /> //Compatibilidad de la App con una ó más versiones Android ( nivel de APIs soportadas) <uses-configuration /> //HW y SW específico que necesita la App (por ejemplo, un te clado físico) <uses-feature /> //HW o SW que utiliza la App (ej: bluetooth, cámara...) <supports-screens /> //Tamaños de pantallas soportadas por la App
  • 28. <compatible-screens /> //Configuraciones de pantallas compatibles con la App <supports-gl-texture /> //Formatos de compresión de textura GL soportados <application> //Declaración de la Aplicación <activity> //Declaración de Activity <intent-filter> //Especifica tipo de Intents a los que puede responder <action /> <category /> <data /> </intent-filter> <meta-data /> </activity> <activity-alias> //Alias para la Activity <intent-filter> . . . </intent-filter> <meta-data /> </activity-alias> <service> //Declaración de Servicio <intent-filter> . . . </intent-filter> <meta-data/> </service> <receiver> //Declaración de Broadcast Receiver <intent-filter> . . . </intent-filter> <meta-data /> </receiver>
  • 29. <provider> //Declaración de Content Provider <grant-uri-permission /> <meta-data /> <path-permission /> </provider> <uses-library /> //Especifica librería compartida que debe ser enlazada </application> </manifest> XML: este fichero AndroidManifest, al igual que veremos por ejemplo en los ficheros de diseño, utiliza el formato XML. De forma simplificada se identifica a XML como un lenguaje que estructura e identifica la información de un archivo en base a etiquetas. Es un lenguaje cuyo código suele ser fácil de leer, lo que nos permite entender más o menos la estructura y contenido del mismo, aún sin conocer todos los detalles del lenguaje. En realidad XML es un meta-lenguaje, es decir, unas especificaciones que nos permiten construir lenguajes de marcado basados en etiquetas. Por ejemplo, (X)HTML, que nos permite identificar las partes de una página web, encerrándolas entre unas etiquetas de apertura y cierre (título nivel 1: <h1>...</h1>, párrafo: <p>....</p>, enlace: <a href=....>...</a>, etc.). Si quieres saber más sobre XML, en este tutorial hablamos sobre ello. Al final del mismo tienes también enlaces a páginas donde lo explican, como ésta de la W3C. En la siguiente lista se enumeran todos los elementos que pueden aparecer dentro de un archivo AndroidManifest.xml. Hay que tener en cuenta que estos son los únicos permitidos y que no podemos crear nuestros propios elementos o atributos. Tienes una descripción detallada de cada uno de esos elementos en la web de Android Developers si quieres profundizar en ellos <action> <activity> <activity-alias> <application>
  • 30. <category> <data> <grant-uri-permission> <instrumentation> <intent-filter> <manifest> <meta-data> <permission> <permission-group> <permission-tree> <provider> <receiver> <service> <supports-screens> <uses-configuration> <uses-feature> <uses-library> <uses-permission> <uses-sdk> Dentro del proyecto que describiremos en este tema, veremos un ejemplo de archivo AndroidManifest.xml y comentaremos los elementos y atributos que incluye. Esos elementos y atributos implementados en el archivo XML, como pueden ser el nombre de aplicación, el nombre del paquete, la versión mínima de SDK soportada o la Activity que será lanzada, se generan de manera automática al crear el proyecto. Si implementamos algún componente posterior, se irá añadiendo igualmente a este fichero. Permisos en AndroidManifest Como comentamos al inicio, una de las funciones del archivo AndroidManifest.xml es indicar los permisos que tiene la App. Cada aplicación que se ejecuta en Android, lo hace desde un entorno limitado. Si desea acceder a recursos del sistema o de otra aplicación, necesitará solicitar permisos de manera explícita, y
  • 31. dependiendo del tipo de permiso, el sistema lo concederá de manera automática o solicitará al usuario la aprobación de dicha solicitud. Hasta la versión Android 6.0, la declaración de permisos de la App debía hacerse previamente en el AndroidManifest.xml, antes de su instalación y ejecución en el dispositivo. A partir de la versión Marshmallow, es posible declarar permisos de una aplicación en tiempo de ejecución, simplificando en gran medida el proceso de instalación de la aplicación. En las siguientes líneas se muestra varios ejemplos de permisos que es posible declarar: android.permission.CALL_EMERGENCY_NUMBERS android.permission.READ_OWNER_DATA android.permission.SET_WALLPAPER android.permission.DEVICE_POWER y finalmente la sintaxis completa de la implementación de un ejemplo concreto, en este caso el permiso para escribir en un almacenamiento externo, que se deberá añadir directamente al archivo AndroidManifest.xml dentro del elemento <manifest>: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="co m.academiaandroid.interfazusuario"> <application android:allowBackup="true" //si se tendrá en cuenta la aplicación al realizar/restaurar un backup android:icon="@mipmap/ic_launcher" //icono para lanzar la aplicación android:label="@string/app_name" //etiqueta para la App, leíble por el usua rio
  • 32. android:supportsRtl="true" //soporte a layouts "derecha a izquierda ( right-to-left) android:theme="@style/AppTheme"> //theme (estilo) para la aplicación <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <!-- Permiso declarado para escritura en almacenamiento externo del dispositivo --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> </manifest> En el apartado "Proyecto ejemplo" de este tema, cuando describimos su código, encontrarás una explicación a la notación "@id/nombreElemento" como la que utilizamos en android:icon="@mipmap/ic_launcher 2.5. Generación de APK y depuración de aplicaciones
  • 33. En este apartado veremos como generar un fichero apk con nuestra aplicación que podremos distribuir e instalar en distintos dispositivos. También aprenderemos a depurar nuestras aplicaciones en caso de que tengamos algún error que no seamos capaces de resolver. Fichero APK Para poder distribuir nuestra aplicación Android y que ésta pueda ser ejecutada, debemos generar un APK, que no es más que un archivo compilado ejecutable con extensión .apk Este formato (una variante que cumple el mismo objetivo en Android que el formato JAR (*) para Java) es básicamente un fichero comprimido ZIP que empaqueta los componentes del proyecto (Android Manifest, clases, recursos...) para que éstos puedan ser desplegados como aplicación y ser ejecutada en un emulador Android Nota (*) JAR: Java Archive; permite distribuir y ejecutar aplicaciones Java El fichero en sí lo podemos abrir para ver sus componentes con un programa de compresión de archivos como 7-Zip, WinRAR o similar. Generar APK Para generar el fichero a APK de nuestra aplicación tan sólo tenemos que dirigirnos al menú Build de Android Studio y seleccionar la opción Build APK Una vez generado, aparecerá en la parte superior derecha de la ventana de Android Studio un mensaje indicando que se ha generado el APK y un enlace para abrir una
  • 34. ventana del navegador con la ruta del fichero. También podemos encontrarlo dirigiéndonos a la carpeta de nuestro proyecto y navegando hasta la ruta "appbuildoutputsapk" , donde se irá actualizando cada vez que compilemos nuestra aplicación. Depuración de aplicaciones En cualquier desarrollo, siempre llega un punto en el que nuestra aplicación no funciona de la forma que esperamos o bien se cierra inesperadamente sin que sepamos por qué. En estos casos es importante que sepamos encontrar el error lo antes posible de forma que podamos seguir avanzando en el desarrollo. Ya vimos en el primer tema del curso la pestaña LogCat en la que van apareciendo los mensajes que lanza el sistema, incluyendo los errores. Sin embargo, hay otra herramienta muy potente y que nos puede ser gran utilidad si aprendemos a utilizarla: el depurador. El depurador nos permite detener la ejecución de una aplicación en un punto concreto y evaluar en ese momento el valor de las distintas variables y elementos de la aplicación. De este modo, podremos ver si alguno de ellos tiene un valor extraño que pueda estar provocando el error que buscamos. Lo primero que debemos hacer es añadir un punto de interrupción (breakpoint) en nuestro código fuente: este será el lugar donde se detendrá la ejecución del programa. Para añadirlo, haremos clic con el botón izquierdo del ratón en la parte izquierda de la linea de código que elijamos; veremos que aparece un circulo rojo, ésto nos indica que hemos añadido un punto de interrupción en esa linea de código. Podemos añadir tantos como deseemos. Para ejecutar nuestra aplicación en modo depuración, pulsaremos el icono que hay junto al de ejecución o utilizar la combinación de teclas Mayusculas+F9 A continuación, utilizaremos nuestra aplicación de forma normal. Cuando lleguemos al punto de interrupción ésta se detendrá, y la interfaz de Android Studio, cambiará mostrándonos el panel de
  • 35. depuración. El panel de depuración cuenta con varios elementos interesantes:  En primer lugar, en la parte superior, encontramos una serie de botones que nos permiten controlar la ejecución de nuestro código, saltando de linea en linea, entrando en las funciones para evaluarlas, etc.  También muy importante es el panel central denominado Variables, que muestra todas las variables que existen en ese punto del código, así como su valor. Podemos desplegarlas en el caso de que sean objetos para ver cada uno de sus atributos. Estos valores irán actualizándose según nos movamos por el código.  Por último, a la derecha, encontramos un último panel, también muy útil, denominado Watches. En él, podemos añadir cualquier variable o expresión, y se evaluará su valor en ese momento. De este modo, podemos por ejemplo adelantarnos, ejecutando un código antes de que el programa llegue a ese punto, para obtener más información de cara a encontrar posibles errores.
  • 36. 2.6. Proyecto ejemplo con dos Activities y un Intent Siguiendo con nuestros primeros pasos en la creación de una Aplicación Android con el IDE Android Studio, vamos desarrollar un proyecto muy básico, al estilo del típico 'Hola mundo' aunque con alguna funcionalidad adicional. En esta App ejemplo, en vez de utilizar una sola activity que presente dicho mensaje, permitiremos al usuario introducir un texto cualquiera, en un campo EditText de la primera activity,y pulsando un botón (control tipo Button) podrá enviar dicho mensaje como parámetro a una segunda activity, utilizando el componente Intent . Esta sencilla aplicación, que describiremos también en un video posterior, estaría formada por las dos pantallas básicas que mostramos a continuación:
  • 38. Elementos de la aplicación Vamos a enumerar los elementos necesarios para el desarrollo de este proyecto que denominado "HolaMundo":  Clase MainActivity , que herede de la clase base Activity , y que definirá la lógica del parámetro que se enviará a la siguiente pantalla.  Clase MainActivity2 , que herede de la clase base Activity , encargada de mostrar el texto introducido en la pantalla principal.  Layout main_activity.xml , formado por un control EditText , que permitirá al usuario introducir texto, y un control Button para enviar dicho texto a la siguiente Activity.  Layout main_activity2.xml , formado por un control TextView para mostrar el texto introducido por el usuario.
  • 39. Estructura del proyecto En la siguiente imagen, se puede apreciar cómo quedaría la estructura de elementos que componen el proyecto que vamos a describir, y que hemos desarrollado con la versión 1.5.1 de Android Studio: Descripción del código fuente Vamos a explicar de forma detallada el código que interviene en el envío de información entre dos activities. Puedes descargar el código completo del proyecto en el apartado siguiente del curso. Nota: aunque lo explicaremos en más detalle en el próximo tema, al tratar del diseño de interfaces de usuarios, comentar brevemente que un layout define la estructura visual de una interfaz de usuario (UI), como puede ser la UI para una Activity o Widget de aplicación. En Android los definimos en ficheros XML (igual formato que el que hemos visto en el fichero AndroidManifest.xml, donde describimos los elementos y sus propiedades delimitándolos mediante etiquetas).
  • 40. El objetivo principal de este proyecto ejemplo es la creación y uso de las Activities y el componente Intent, por lo que aunque introduciremos algunos elementos del interfaz de usuario (ficheros de layout, componentes como un campo de texto o un botón) no nos detendremos en explicarlos, dejándolo para el siguiente tema. Una vez hayas visto dicho módulo, puedes volver para revisar de nuevo este proyecto y de esta forma comprender mejor la parte del interfaz de usuario. . HolaMundoappsrcmainjavacomacademiaandroidholamundoMainAc tivity.class Activity que presenta la particularidad de controlar la pulsación del botón definido a nivel de layout, y que enviará el texto introducido a la siguiente pantalla: import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { Se declaran dos variables de tipo EditText y Button a nivel de clase: private EditText edNombre; private Button btnEnviar; El método onCreate() será llamado cuando se inicie la Activity , por lo que todo lo situado en su interior se inicializará al llamar a dicha Activity : @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
  • 41. En la siguiente línea se establecerá la referencia a qué layout (interfaz de usuario) se asocia a esta Activity : setContentView(R.layout.main_activity); Se asignan las referencias a los controles EditText y Button , definidos a nivel de layout, con sus respectivas variables: edNombre = (EditText)findViewById(R.id.edNombre); btnEnviar = (Button)findViewById(R.id.btnEnviar); Nota: con el método findViewById() referenciamos objetos con un determinado identificativo (id) que le hayamos asignado. Ver nota un poco más abajo sobre la identificación de elementos y el fichero R.java. Se invoca al método setOnClickListener() , encargado de controlar la pulsación de la vista asociada al botón: btnEnviar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Veremos la detección de eventos en más detalle en el tema próximo Previamente a la instanciación de la clase Intent , será necesario comprobar que el campo EditText no esté vacío: if(!edNombre.getText().toString().equals("")) {
  • 42. A continuación, se instancia la clase Intent , pasándole como parámetros de entrada el contexto (en este caso la Activity actual) y la Activity de destino: Intent intent = new Intent(MainActivity.this,MainActivity2.class) ; Se invoca al método putExtra() , que almacenará el valor introducido en el campo de texto por clave/valor (clave->"nombre" / valor -> edNombre.getText().toString() ), para finalmente llamar al método startActivity() que recibe como parámetro la instancia creada, y que lanzará la Activity establecida como segundo parámetro: intent.putExtra("nombre",edNombre.getText().toString()); startActivity(intent); }else { En el supuesto de no introducir ningún valor en la caja de texto, se mostrará un mensaje emergente del tipo "Debe indicar los datos requeridos": Toast.makeText(MainActivity.this, "Debe indicar los datos requeridos" , Toast.LENGTH_LONG).show(); } } }); } } Toast: son las notificaciones más sencillas que podemos usar en Android. Consisten en mensajes de texto que se muestran en la pantalla durante un tiempo y desaparecen automáticamente transcurrido dicho periodo. Para crear un mensaje de estos, usaremos la clase Toast. Esta clase dispone de un método estático que nos facilitará la creación de un mensaje, éste es makeText() . Este método recibe como parámetros el contexto de la activity, el mensaje a mostrar y la duración del periodo de tiempo que permanecerá visible (admite dos valores: Toast.LENGTH_SHORT ó Toast.LENGTH_LONG, según queramos que sea un tiempo corto o largo, respectivamente). Una vez creado el texto, ya solo queda mostrarlo al usuario, para ello llamamos al método show() de la clase Toast. HolaMundoappsrcmainjavacomacademiaandroidholamundoMainAc tivity2.class
  • 43. Activity encargada de recibir el parámetro enviado por la pantalla anterior. Como se puede apreciar, cada clase utilizada en la Activity deberá ser importada previamente para poder acceder a sus métodos y propiedades: import android.app.Activity; import android.os.Bundle; import android.widget.TextView; Clase MainActivity2 , que hereda de la clase base Activity , asociada a una ventana de la aplicación: public class MainActivity2 extends Activity { Se declaran dos variables de tipo Bundle y TextView a nivel de clase: private Bundle bundle; private TextView tvSaludo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity2); A continuación, se asigna la referencia del control TextView definido a nivel de layout, con la variable de tipo TextView : tvSaludo = (TextView)findViewById(R.id.tvSaludo); Posteriormente, se asocia a la variable de tipo Bundle , los datos recibidos de la Activity anterior: bundle = getIntent().getExtras(); String saludo = bundle.getString("nombre");
  • 44. Finalmente, se invocará al método append() de la variable de tipo TextView , para mostrar el texto por pantalla: tvSaludo.append(" " + saludo + "!!!!"); } } HolaMundoappsrcmainreslayoutmain_activity.xml Layout main_activity.xml que define un control EditText (campo de texto editable) donde el usuario podrá introducir texto, y un control Button , que permitirá al usuario interaccionar con la aplicación enviando información a la siguiente Activity: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/nombre" android:id="@+id/tvNombre" android:layout_alignBottom="@+id/edNombre" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <EditText android:layout_width="match_parent"
  • 45. android:layout_height="wrap_content" android:id="@+id/edNombre" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/tvNombre" android:layout_marginLeft="76dp" android:layout_marginStart="76dp" android:inputType="text" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/enviar" android:id="@+id/btnEnviar" android:layout_below="@+id/tvNombre" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginTop="34dp" /> </RelativeLayout> Identificación: habrás visto que empleamos en estos ficheros la notación '@' y '@+id'. Se trata de un atributo muy importante, android:id, que debemos tener presente siempre, tanto para los layouts como para los elementos gráficos o cadenas de texto que queramos referenciar. Mediante este atributo, podremos identificar a cada elemento para luego acceder a ellos desde el código o para posicionarlos de manera relativa como veremos en el próximo tema o modificar los textos que aparecen en ellos. Es por tanto muy recomendable asignarles siempre un identificador (id). Para asignarles un id nuevo, usaremos la siguiente sintaxis: android:id=”@+id/nombreElemento” , en la que hemos creado un nuevo id llamado nombreElemento. Si en cambio queremos referirnos a un id ya creado, el carácter "+” sobra, quedando @id/nombreElemento . Todos los id que creemos, se añaden automáticamente a un fichero llamado R.java (no debemos editarlo nunca, se autogenera solo), por lo que para acceder a un id tenemos que hacer referencia a dicha clase mediante R.id.nombre_id, como vimos por ejemplo al
  • 46. asignar las referencias a los controles de campo de texto: edNombre = (EditText)findViewById(R.id.edNombre); o del botón: btnEnviar = (Button)findViewById(R.id.btnEnviar); HolaMundoappsrcmainreslayoutmain_activity2.xml Layout main_activity2.xml que define un control TextView (vista de texto) que recogerá el valor introducido por el usuario en la pantalla principal: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="@string/saludo" android:id="@+id/tvSaludo" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> </RelativeLayout> HolaMundoappsrcmainAndroidManifest.xml Archivo AndroidManifest.xml, que define los aspectos generales del proyecto, y dónde se diferencian las siguientes partes: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  • 47. package="com.academiaandroid.holamundo"> <application En las siguientes líneas se definen si se permiten las copias de seguridad, el icono que se mostrará en el launcher del dispositivo, el nombre de la aplicación, si soporta la escritura de derecha a izquierda y el tema de la aplicación: android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> Se implementa la Activity inicial, indicando en su diferentes atributos el nombre de la clase y de la ventana, y el tema a utilizar: <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> Permite definir que Activity será lanzada cuando se inicie la aplicación: <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> Se define una segunda Activity también con los atributos de nombre de la ventana y tema; <activity android:name=".MainActivity2"
  • 48. android:label="@string/title_activity_main2" android:theme="@style/AppTheme.NoActionBar"> </activity> </application> </manifest> 3.1. Introducción y objetivos En este tema vamos a tratar la creación de interfaces de usuario. (También nos referiremos a ellos como UI ó User interfaces). A lo largo de sus apartados describiremos los principales controles para el diseño y construcción de interfaces de usuario, veremos cómo referenciarlos a nivel de código, para finalizar creando nuestra propia interfaz de usuario desde las clases Java implementadas. Los objetivos de aprendizaje de este módulo serán:  Conocer e implementar controles básicos para el diseño de interfaces de usuario.  Saber referenciar los controles definidos a nivel visual con el código de la aplicación.  Comprender la estructura global para la construcción de interfaces sólidas.  Poder implementar acciones que permitan al usuario interaccionar con la aplicación. 3.2. Panel de diseño de UI de Android Studio. Controles básicos En este apartado nos encargaremos de describir los controles básicos disponibles dentro del diseñador de interfaces de usuario que proporciona Android Studio al seleccionar un layout de nuestro proyecto. Layout: es el esquema de distribución de los elementos dentro un diseño (es un término que podría traducir por 'plano' o 'disposición'). En él se sustentan los diferentes elementos de la interfaz de usuario, definiéndose la distribución, posición y dimensiones de dichos elementos. En Android tenemos diversas opciones de layout disponibles para construir
  • 49. nuestras UI: diseño tabular, lineal, de rejilla ó cuadrícula (grid),... Veremos todo ésto en más detalle a lo largo de este tema. Como se puede apreciar en la siguiente imagen, tras seleccionar un layout del proyecto, se mostraría la siguiente ventana, denominada "Palette", con los diferentes layouts y controles que podrán añadirse a la interfaz de usuario: Nota: esta ventana puedes ampliarla, como cualquier otra en Android Studio deslizando su linea delimitadora, o eligiendo en la configuración (icono de rueda dentada, arriba a la derecha) otro modo de presentación: flotante,...
  • 50. Sin entrar a describir las opciones de Layouts, Expert y Custom (de mayor complejidad), se podrán observar controles bien delimitados en función de sus características. Para poder añadir cualquiera de los elementos de la imagen anterior, bastará con seleccionar el control elegido de la ventana "Palette" e indicar en qué posición del layout se desea establecer: Controles de entrada Nos detendremos en aquellos controles que nos proporcionan mayor funcionalidad para la interacción con el usuario, como es el caso de los controles de entrada, y que podemos definir como componentes interactivos en la interfaz de usuario de la aplicación, como vemos en esta imagen:
  • 51. Android ofrece una amplia variedad de controles que se pueden utilizar en la interfaz de usuario, tales como botones, campos de texto, barras de búsqueda, casillas de verificación, botones de zoom, botones de conmutación, y muchos más. Button Un Button consiste en representación de texto o un icono (o ambas cosas) que se comunica cuando el usuario lo toca, produciendo una acción sobre la aplicación. Dependiendo de si desea un botón con texto, un icono, o ambos, puedes crear el diseño del botón de tres maneras: Con el texto, usando la clase Button: <Button android:layout_width = "wrap_content" //ancho del botón android:layout_height = "wrap_content" //altura del botón android:text = "@string/button_text" //texto del botón ... /> XML: verás que los ficheros que definen los componentes y los layouts están en formato XML. Si tienes dudas sobre este formato, consulta la nota sobre XML que incluíamos en el apartado 2.4 del fichero AndroidManifest Atributos: los atributos de anchura y altura ( android:layout_width y android:layout_height) tienen en este caso el valor 'wrap_content' que les indica que tomen la dimensión de su contenido. Puedes consultar lo que significa cualquier atributo que aparezca en estos ficheros XML (notación: " android:nombreAtributo”) en la referencia oficial de la clase R.attr. Hay mucha información (en inglés) y puede ser a veces complicado
  • 52. localizarlo, aunque puedes utilizar una búsqueda en la página con Ctrl+F y el nombre del atributo (sin el prefijo 'android:') Con un icono, utilizando la clase ImageButton <ImageButton android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:src = "@drawable/button_icon" //fuente (source) donde está la imagen del i cono ... /> Con texto y un icono, utilizando la clase Button con el atributo android:drawableLeft = "@drawable/button_icon" : <Button android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "@string/button_text" android:drawableLeft = "@drawable/button_icon" ... /> Text Field Un Text Field o campo de texto permite al usuario escribir texto en su aplicación. Puede ser una sola línea o varias líneas. Al tocar un campo de texto, se colocará el cursor mostrando automáticamente el teclado. Además de escribir, un text field permite otras actividades, como la selección de texto (cortar, copiar, pegar) y consulta de información a través de auto-completado. Puedes añadir un Text Field a un layout mediante el control EditText, a través de su elemento <EditText> para el diseño XML o mediante su objeto EditText a nivel de código.
  • 53. Ejemplo de EditText para introducir un correo electrónico: <EditText android:id = "@+id/email_address" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:hint = "@string/email_hint" android:inputType = "textEmailAddress" /> En este caso, vemos el valor 'fill-parent' que indica que tome la dimensión del elemento padre, es decir, en el que esté incluido este Text Field. Checkbox Un CheckBox permite al usuario seleccionar una o más opciones de un conjunto. Por lo general, se debe presentar cada opción de CheckBox en una lista vertical. Al heredar indirectamente de un TextView, se le puede asignar cualquiera de sus atributos. Ejemplo de un CheckBox a través del archivo XML:
  • 54. <? Xml version = "1.0" encoding = "utf-8" ?> <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > <CheckBox android:id = "@+id/checkbox_meat" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "@string/meat" android:onClick = "onCheckboxClicked" /> </LinearLayout> Radio Button Los RadioButtons permiten al usuario seleccionar una opción de un conjunto. Este control será de gran utilidad cuando se deseen establecer varias opciones de selección pero sólo será posible mantener seleccionada una de ellas de forma obligatoria. Al heredar indirectamente de un TextView, se le puede asignar cualquiera de sus atributos. Ejemplo de dos RadioButtons agrupados en un RadioGroup: <?xml version="1.0" encoding="utf-8"?> <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical">
  • 55. <RadioButton android:id="@+id/radio_pirates" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pirates" android:onClick="onRadioButtonClicked"/> <RadioButton android:id="@+id/radio_ninjas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/ninjas" android:onClick="onRadioButtonClicked"/> </RadioGroup> Toggle Button Un Toggle Button permite al usuario cambiar un ajuste entre dos estados. En la imagen de abajo tienes un ejemplo: Es posible añadir un Toogle Button a su diseño con el objeto ToggleButton. Android 4.0 (API de nivel 14) introduce otro tipo de botón llamado Switch (objeto), que proporciona un control deslizante. Vemos un ejemplo en la siguiente imagen: Si necesitamos cambiar el estado de un botón, es posible utilizar los métodos CompoundButton.setChecked() o CompoundButton.toggle() . Ejemplo de diseño de un Toogle Button: <ToggleButton android:id="@+id/toggle_button" android:layout_width="wrap_content" android:layout_height="wrap_content"
  • 56. android:checked="true" android:textOff="@string/text_off" android:textOn="@string/text_on" /> Spinner Un Spinner proporciona una manera rápida de seleccionar un valor de un conjunto. En su estado por defecto, un Spinner muestra su valor seleccionado en ese momento. Al tocar el Spinner muestra un menú desplegable con todos los demás valores disponibles, de los cuales el usuario puede seleccionar uno nuevo. Se puede agregar un Spinner a un layout con el objeto Spinner, y a través del elemento en su diseño XML. <Spinner android:id="@+id/planets_spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" />
  • 57. Picker Control para que el usuario escoja una fecha para su uso dentro del proyecto. Cada picker proporciona controles para la selección de cada parte del tiempo (horas, minutos, AM / PM) o fecha (mes, día, año). El uso de estos recolectores garantiza que los usuarios pueden elegir una hora o fecha que sea válida, el formato correcto, y se ajusta a la configuración regional del usuario. TextView Además de los controles de entrada que se han expuesto con anterioridad, es conveniente describir también el control TextView. Este control se usa para mostrar texto al usuario. Se le pueden asignar diferentes atributos (aparte de las ya conocidas como android:layout_width y android:layout_height para definir la anchura y altura) como pueden ser:  Tamaño de fuente: android:textSize (recordad usad la medida sp en este caso)  Color de fuente: android:textColor  Un fondo personalizado: android:background  etc.. Para definir un texto se usa el atributo: android:text : <TextView android:id="@+id/text_view"
  • 58. android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/some_text" /> Si queremos cambiar este texto desde código, tenemos que hacerlo de la siguiente manera: TextView textView = (TextView) findViewById(R.id.text_view); textView.setText("Cambio de texto TextView por esta frase."); Se puede ver que hemos usado el método findViewById() que ya presentamos en el proyecto ejemplo del anterior tema . Mediante este método referenciamos el objeto TextView creado en la clase Java con el id del control que hemos definido en el XML. Todos los id que creemos, se añaden automáticamente al fichero R.java, por lo que para acceder a un id tenemos que hacer referencia a dicha clase mediante R.id.nombre_id . Y si lo que queremos es acceder al texto que contiene, haremos lo siguiente: String texto = textView.getText().toString(); Nota: imágenes de controles de Android Developer con licencia Creative Commons Attribution 2.5. En el apartado 'recursos adicionales' , tienes un documento recopilatorio de controles comunes de esa misma web. 3.3. Views y Layouts En este apartado describiremos los diseños o layouts más utilizados para una interfaz de usuario en una Aplicación Android. También explicaremos cómo crearlos, incluyendo algunos elementos, como campos de texto editables y botones, con un sencillo ejemplo práctico. Para diseñar interfaces de usuario en Android utilizamos una capa (llamada layout), descrita mediante un fichero XML, sobre la que se dispondrán los diferentes elementos gráficos que componen dicho interfaz. Todos estos componentes heredan directa o indirectamente de la clase View. Veamos la definición de los términos View y ViewGroup, necesarios para comprender el funcionamiento de la interfaz gráfica en Android:  View (o Vista). Esta clase es básica para la creación de todos los componentes usados en la interfaz. Una View ocupa un área rectangular en la pantalla y es el responsable de dibujar los componentes y manejar
  • 59. los eventos que definamos sobre ellos, o dicho de una forma más simple, dibuja los componentes en la pantalla con los que el usuario puede interaccionar. Es la clase base para los widgets, que son Views 'preconstruidas' que vienen incluidas en la plataforma Android, como los botones, campos de textos, check boxes, radio buttons, etc.  ViewGroup (o Grupo de Vista). Hereda directamente de View y se usa para, como su nombre indica, contener y controlar la lista de Views y de otros ViewGroups. Es la clase base para los Layouts, mediante los cuales podemos diseñar una estructura para un conjunto de Views. El fichero XML que generamos (por ejemplo activity_main.xml) se ubica en la carpeta res/layout, y se carga(*) a través del método setContentView() en el método onCreate() de la activity, como veremos en un ejemplo práctico que desarrollaremos en una publicación posterior. Nota(*): a esta acción del método setContentView también se le suele denominar 'inflar' una vista (view). Más detalle en estas explicaciones algo más avanzadas (en inglés). Tenemos dos grandes ventajas al utilizar un fichero XML externo para declarar la UI:  Nos permite separar mejor la presentación de nuestra Aplicación Android del código que controla su comportamiento. Esto nos facilita realizar cambios o adaptaciones de dicha interfaz sin necesidad de modificar el código y recompilar de nuevo, pudiendo crear layouts XML por ejemplo para distintas orientaciones o tamaños de pantalla.  Es más fácil visualizar y entender la estructura del layout en un fichero XML que podemos leer sin mucha dificultad. Esto nos facilita también las tareas de depuración. En cualquier caso, también es posible construir la interfaz de usuario utilizando únicamente código. Lo veremos también en ese proyecto ejemplo que desarrollaremos más adelante, creando dos versiones del mismo interfaz, uno usando fichero XML y otro solo basado en código.. Antes de empezar a describir distintos tipos de layouts y algunos de los elementos que podremos agregarle (TextView, EditText, Button) utilizándolos en un ejemplo de interfaz que realizaremos en cada uno de esos layouts, vamos a mencionar dos aspectos importantes: Identificación Ya explicamos en el proyecto ejemplo del tema anterior que hay un atributo muy importante, android:id, que debemos tener presente siempre, tanto para los Layouts como para los elementos gráficos. Mediante este atributo, podremos identificar a cada elemento para luego acceder a ellos desde el código o para posicionarlos de
  • 60. manera relativa como veremos en el RelativeLayout. Es por tanto muy recomendable asignarles siempre un identificador (id). Para asignarles un id nuevo, usaremos la siguiente sintaxis: android:id=”@+id/botonaceptar” , en la que hemos creado un nuevo id llamado botonaceptar. Si en cambio queremos referirnos a un id ya creado, el carácter "+” sobra, quedando @id/boton_aceptar Unidades de medidas Otra consideración a tener muy en cuenta es que, al existir tanta diversidad de dispositivos Android, es conveniente usar siempre medidas relativas al tamaño de pantalla de cada uno. Esto lo podemos hacer usando:  La medida dip (density-independent pixel ó dp, que al caso es la misma), recomendada para especificar el tamaño de los views en nuestro layout (siendo 160dp el equivalente a una pulgada (2,54 cm) de pantalla física)  La medida sp (scaled-independent pixel), similar a dp y recomendada para definir tamaños de fuentes. Layout Los Layouts son los elementos sobre los cuales se sustentan los diferentes componentes de la interfaz de usuario, y controlan la distribución, la posición y las dimensiones de dichos componentes. Es decir, un layout define la estructura o diseño del UI. Para poder implementar cualquiera de estos elementos para la distribución visual de la aplicación, bastará con seleccionarla en la ventana "Palette", y añadirlo al árbol de componentes en la ventana "Design". A continuación describiremos diferentes tipos de Layouts muy comunes, con un ejemplo simple de diseño basado en cada uno. FrameLayout Es el más simple de todos. En él, todos los elementos se alinean teniendo en cuenta la esquina superior izquierda de la pantalla, no pudiendo ser ubicados en otro lugar, por lo que se colocarían unos encima de otros tapando completa o parcialmente a los demás, a menos que el nuevo elemento sea transparente. Por esta razón, se usa normalmente para mostrar un único elemento, ya que puede resultar difícil organizar la posición de los elementos, o bien una serie animada de imágenes donde cada una se va posicionando sobre la anterior. Los elementos incluidos en este layout han de tener los
  • 61. atributos android:layout_width y android:layout_height , que podrán tomar los valores:  match_parent (fill_parent) si lo que se quiere es que se tome la dimensión completa del padre  wrap_content, si se desea que tome la dimensión de su contenido. A partir de la versión 8 de la API de Android, el valor fill_parent fue renombrado a match_parent, por lo que aún nos podemos encontrar con uno u otro. Se permiten ambos, aunque se recomienda match_parent. Si queremos posicionar los elementos de otra forma, deberíamos de "jugar” con los atributos android:layout_gravity (especifica cómo la vista hijo (child view) debe posicionarse en su contenedor) y con las destinadas a controlar los márgenes y alineaciones, como android:layout_marginTop , android:layout_marginLeft , android:layout_alignParentLe ft , etc... Veamos un ejemplo de cómo quedaría una interfaz con FrameLayout:
  • 62. y del fichero XML que lo describe, donde vemos cómo se definen los diferentes componentes: TextView ("Datos del curso"), tres EditText ("Nombre", "Duración", "Curso") y un Button (botón "Enviar"): Este fichero XML es generado automáticamente por Android Studio al utilizar su editor visual de creación de interfaces.Si alguna vez has creado páginas Web con un editor WYSIWYG tipo KompoZer o DreamWeaver, es algo similar: compones gráficamente la página y se genera el código HTML acorde a esos elementos y disposición. <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  • 63. android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuario.Main2Activity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Datos del curso:" android:id="@+id/textView" android:textStyle="bold" android:layout_row="0" android:layout_alignParentLeft="true" android:layout_marginLeft="0dp" android:layout_alignParentTop="true" android:layout_marginTop="0dp" /> <EditText android:layout_width="159dp" android:layout_height="wrap_content" android:id="@+id/editText" android:hint="Nombre" android:layout_row="1" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_gravity="left|center_vertical" />
  • 65. android:layout_height="wrap_content" android:text="Enviar" android:id="@+id/button" android:layout_row="4" android:layout_alignParentBottom="true" android:layout_alignRight="@+id/editText3" android:layout_alignEnd="@+id/editText3" android:layout_marginBottom="45dp" android:layout_gravity="right|bottom" /> </FrameLayout> LinearLayout Este layout alinea los elementos en una única dirección, que puede ser vertical u horizontal, dependiendo del valor que le demos al atributo android:orientation . Todos los elementos aparecerán uno detrás de otro, sin solaparse entre ellos, como ocurría con el FrameLayout. El LinearLayout respeta los márgenes entre los elementos hijos y su gravedad dentro de la pantalla (ésta puede ser a la derecha, a la izquierda o en el centro). En este layout, al igual que en el anterior, los elementos hijos deben establecer sus atributos android:layout_height y android:layout_width para determinar sus dimensiones dentro del layout, aunque en este caso dispondremos de otro atributo llamado android:layout_weight . Este atributo permite que un elemento se expanda para llenar cualquier espacio que quede libre. Por defecto este valor es 0, es decir, no se expande. Pongamos un ejemplo. Si agregamos dos cuadros de texto, según los valores que pongamos a este atributo, tendremos:  Si a uno se le da el atributo de android:layout_weight=”1” , sucede que entre los dos cuadros de texto se ocupa toda la pantalla, uno de ellos permanecerá en su tamaño normal y al que le hemos asignado el atributo android:layout_weight ocupará el resto de la pantalla.  Si le hubiéramos asignado a los dos este atributo igual a 1, cada uno ocuparía la mitad de la pantalla.
  • 66.  Si le hubiéramos dado a uno el valor 2 y al otro le hubiéramos dado el valor 1, entre los dos ocuparían también toda la pantalla pero uno de ellos tendrá el doble de altura/anchura que el otro. El layout genérico creado con un LinearLayout tendría este diseño: Ahora vamos a realizar el mismo ejemplo que hicimos en el layout anterior (TableLayout) en este caso con un LinearLayout con orientación horizontal:
  • 67. y el fichero XML que lo describe: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin"
  • 68. android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuario.Main2Activity" android:orientation="horizontal" android:gravity="top"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Datos del curso:" android:id="@+id/textView" android:textStyle="bold" android:layout_row="1" android:layout_alignParentLeft="true" android:layout_marginLeft="0dp" android:layout_alignParentTop="true" android:layout_marginTop="0dp" android:layout_column="0" /> <EditText android:layout_width="100dp" android:layout_height="wrap_content" android:id="@+id/editText" android:hint="Nombre" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_column="0" android:layout_row="2" />
  • 70. android:text="Enviar" android:id="@+id/button" android:layout_row="23" android:layout_alignParentBottom="true" android:layout_toRightOf="@+id/editText" android:layout_toEndOf="@+id/editText" android:layout_column="0" /> </LinearLayout> TableLayout En este layout, los elementos hijos se distribuyen de forma tabular, como si de una tabla se tratara, definiendo las filas y columnas necesarias, y la posición de cada elemento dentro de la tabla. Para definir una fila, se usa el objeto TableRow, y dentro de éste se van agregando los elementos que compondrá la fila, sin necesidad de definir un objeto columna. De este modo, la tabla vendrá definida por tantas filas como objetos TableRow hayamos insertado, y tantas columnas como elementos que hayamos insertado en cada TableRow. Vemos un diseño genérico, con la disposición de los elementos en este formato de tabla:
  • 71. Ahora veamos el ejemplo que estamos utilizando en los otros layouts, con controles ya implementados en un LayoutTable: El fichero XML que describiría este ejemplo sería: <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"
  • 72. android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuario.Main2Activity" android:gravity="top"> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Datos del curso:" android:id="@+id/textView" android:textStyle="bold" android:layout_row="1" android:layout_alignParentLeft="true" android:layout_marginLeft="0dp" android:layout_alignParentTop="true" android:layout_marginTop="0dp" android:layout_column="0" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent">
  • 75. android:layout_alignParentBottom="true" android:layout_toRightOf="@+id/editText" android:layout_toEndOf="@+id/editText" android:layout_column="0" /> </TableRow> </TableLayout> RelativeLayout Este layout permite que los elementos se dispongan en la pantalla de forma relativa al elemento padre o a cualquier otro elemento agregado al layout, por lo tanto, podríamos hacer cosas como alinear dos elementos a la derecha, o crear uno debajo del otro, centrarlos en la pantalla, a la izquierda, etc. Veamos también un ejemplo de uso de este layout, usando los mismos elementos que en los casos anteriores.
  • 76. y el fichero XML correspondiente:
  • 77. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuario.Main2Activity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Datos del curso:" android:id="@+id/textView" android:textStyle="bold" android:layout_row="0" android:layout_alignParentLeft="true" android:layout_marginLeft="0dp" android:layout_alignParentTop="true" android:layout_marginTop="0dp" /> <EditText android:layout_width="159dp" android:layout_height="wrap_content" android:id="@+id/editText" android:hint="Nombre"
  • 78. android:layout_row="1" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_gravity="left|center_vertical" /> <EditText android:layout_width="165dp" android:layout_height="wrap_content" android:inputType="number" android:ems="10" android:id="@+id/editText2" android:hint="Duración" android:layout_row="2" android:layout_below="@+id/editText" android:layout_alignLeft="@+id/editText" android:layout_alignStart="@+id/editText" android:layout_gravity="center" /> <EditText android:layout_width="157dp" android:layout_height="wrap_content" android:inputType="textMultiLine" android:ems="10" android:id="@+id/editText3" android:hint="Temario" android:layout_row="3" android:layout_below="@+id/editText2" android:layout_alignLeft="@+id/editText2" android:layout_alignStart="@+id/editText2"
  • 79. android:layout_gravity="right|center_vertical" /> <Button android:layout_width="141dp" android:layout_height="wrap_content" android:text="Enviar" android:id="@+id/button" android:layout_row="4" android:layout_marginBottom="45dp" android:layout_gravity="right|bottom" android:layout_alignParentBottom="true" android:layout_toRightOf="@+id/editText" android:layout_toEndOf="@+id/editText" /> </RelativeLayout> GridLayout Layout que define un diseño situando a sus hijos en una forma de rejilla rectangular. Dicho grid o rejilla se compone de un conjunto de líneas que separan el área de visualización de las celdas. Las líneas de cuadrícula son referenciadas por índices. Un grid con N columnas tiene n + 1 índices del grid que van de 0 a N, ambos inclusive. En el siguiente ejemplo, puedes comprobar cómo quedaría esta forma de distribución de los controles:
  • 80. <?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuario.Main2Activity">
  • 81. <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Datos del curso:" android:id="@+id/textView" android:textStyle="bold" android:layout_row="1" android:layout_alignParentLeft="true" android:layout_marginLeft="0dp" android:layout_alignParentTop="true" android:layout_marginTop="0dp" android:layout_column="0" /> <EditText android:layout_width="159dp" android:layout_height="wrap_content" android:id="@+id/editText" android:hint="Nombre" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_gravity="left|center_vertical" android:layout_column="0" android:layout_row="2" /> <EditText android:layout_width="165dp" android:layout_height="wrap_content" android:inputType="number"
  • 82. android:ems="10" android:id="@+id/editText2" android:hint="Duración" android:layout_below="@+id/editText" android:layout_alignLeft="@+id/editText" android:layout_alignStart="@+id/editText" android:layout_gravity="left|center" android:layout_column="0" android:layout_row="3" /> <EditText android:layout_width="165dp" android:layout_height="wrap_content" android:inputType="textMultiLine" android:ems="10" android:id="@+id/editText3" android:hint="Temario" android:layout_below="@+id/editText2" android:layout_alignLeft="@+id/editText2" android:layout_alignStart="@+id/editText2" android:layout_gravity="left|center_vertical" android:layout_column="0" android:layout_row="4" /> <Button android:layout_width="141dp" android:layout_height="wrap_content" android:text="Enviar" android:id="@+id/button"
  • 83. android:layout_row="23" android:layout_marginBottom="45dp" android:layout_gravity="left|bottom" android:layout_alignParentBottom="true" android:layout_toRightOf="@+id/editText" android:layout_toEndOf="@+id/editText" android:layout_column="0" /> </GridLayout> Layouts para contenido dinámico Cuando el contenido que mostramos en el layout no esta predeterminado y se genera dinámicamente, por ejemplo como resultado de una consulta a una base de datos, podemos utilizar un adaptador que hace de intermediario entre el layout y el contenido, insertando éste último en formas de vistas en el layout. Vemos dos ViewGroups que utilizan esta técnica que nos aparecen en el Panel de Diseño de Android Studio en la sección 'Containers' (contenedores): ListView Un ListView es un ViewGroup que muestra una lista de elementos desplazables. Los elementos o items de la lista se insertan automáticamente en ella utilizando un adaptador que extrae el contenido de una fuente tal como una matriz o una consulta a una base de datos y convierte cada item en una vista que se coloca en la lista.
  • 84. GridView Un GridView es un ViewGroup que muestra los elementos en una rejilla de dos dimensiones desplazable. Los elementos de cada cuadrícula se insertan automáticamente usando un ListAdapter . Avanzado: Para los que quieran profundizar en este tema, más allá del curso, en nuestra web de Academia Android desarrollamos en unas series de publicaciones dedicada a controles de selección en una UI, un proyecto ejemplo de implementación de un ListView y un GridView, extrayendo datos de una base de datos y la creación de una ListView personalizada
  • 85. En esa misma web, dispones también de una introducción a Material Design, las especificaciones de diseño que lanzó Google a partir de Android 5.0 Lollipop. Son recomendaciones y pautas para crear Apps con un aspecto visual más consistente y unificado, tratando de mejorar la experiencia de usuario. Créditos: diagramas de layouts de Android Developer con licencia Creative Commons Attribution 2.5 .4 Detección de eventos en la interfaz de usuario Tras describir cómo crear distintos tipos de layouts (diseños) para una interfaz de usuario en una Aplicación Android, veremos cómo hacer posible la interacción del usuario con los elementos de esa interfaz(botones, campos de texto,...) utilizando la pantalla táctil o las teclas de navegación. Dentro de las posibilidades que proporciona Android para controlar los eventos de interacción del usuario con la interfaz gráfica, veremos aquellos encargados de detectar cuando se produce una pulsación sobre un objeto View, como por ejemplo un Button (botón). Un detector de eventos podemos definirlo como una interfaz de la clase View, que contiene un método callback o de devolución de llamada. Dicho método será llamado cuando la vista donde se ha registrado el oyente (listener) es desencadenada por la interacción del usuario con el elemento perteneciente a la interfaz. Nota: en el anterior apartado ya vimos que una View (vista) ocupa un área rectangular en la pantalla y es la responsable de dibujar los componentes y manejar los eventos que definamos sobre la interfaz de usuario. En la siguiente lista se describen los métodos que detectarán los eventos producidos por el usuario: onClick() Implementado con la interfaz View.OnClickListener . Este método será llamado cuando el usuario toca el elemento en una interfaz táctil o se centra en dicho elemento cuando lo selecciona con las teclas de navegación y pulsa la opción de entrar. onLongClick() Implementado con la interfaz View.OnLongClickListener . Este método será llamado cuando el usuario toca el elemento manteniéndolo pulsado en una interfaz táctil o se centra en dicho elemento cuando lo selecciona con las teclas de navegación y pulsa la opción de entrar dejándolo pulsado. onFocusChange()
  • 86. Implementado con la interfaz View.OnFocusChangeListener . Este método será llamado cuando el usuario se posicione sobre el elemento. onKey() Implementado con la interfaz View.OnKeyListener .Este método será llamado cuando el usuario se posiciona sobre el elemento pulsando o soltando una tecla del dispositivo. onTouch() Implementado con la interfaz View.OnTouchListener . Este método será llamado cuando el usuario realice cualquier acción relacionada con la pulsación, dejar de pulsar o gestos sobre la pantalla táctil del dispositivo. onCreateContextMenu() Implementado con la interfaz View.OnCreateContextMenuListener . Este método será llamado cuando el usuario mediante una pulsación prolongada, defina la visualización de un menú contextual. Construcción de un detector de entradas Vamos a ver un sencillo ejemplo práctico, mostrando tres posibilidades de implementación del evento onCLick() . En el ejemplo, cuando el usuario toca-pulsa el botón, se lanza un mensaje por pantalla informando de este hecho: Método setOnClickListener() , pasándole una instancia de ClickListener : public class MainActivity extends Activity { private Button btnOnClick; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); btnOnClick = (Button)findViewById(R.id.btnOnClick); btnOnClick.setOnClickListener(new View.OnClickListener() {
  • 87. @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Ha pulsado el botón 'Even to onClick()'.", Toast.LENGTH_SHORT).show(); } }); } } Implementando la interfaz OnClickListener como parte de la Activity, y el método onClick(View v) . Al implementar la interfaz View.OnClickListener , mostrará un error, y bastará con seleccionar con el cursor dicha interfaz y con la combinación Alt + Enter, nos mostrará una ventana modal con la opción "Implement methods" que añadirá automáticamente el método onClick() : public class MainActivity extends Activity implements View.OnClickListener { private Button btnOnClick; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); btnOnClick = (Button)findViewById(R.id.btnOnClick); } @Override public void onClick(View v) {
  • 88. Toast.makeText(MainActivity.this, "Ha pulsado el botón 'Evento onCli ck()'.", Toast.LENGTH_SHORT).show(); } } Definiendo el evento onClick() en dicha propiedad a nivel de layout (a nivel de código, se puede observar cómo se define un método llamado lanzarEvento() ,que recibe como parámetro de entrada una objeto de tipo View , y que debe coincidir con el método declarado en la propiedad onClick ): public class MainActivity extends Activity { private Button btnOnClick; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); btnOnClick = (Button)findViewById(R.id.btnOnClick); } public void lanzarEvento(View v) { Toast.makeText(MainActivity.this, "Ha pulsado el botón 'Evento onClick()'.", Toas t.LENGTH_SHORT).show(); } } Dentro del layout se define un método llamado lanzarEvento en la propiedad onClick. Este método deberá implementarse en la Activity que mostrará esta pantalla:
  • 89. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"
  • 90. tools:context="com.academiaandroid.interfazusuario.MainActivity" android:id="@+id/rlPrincipal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Evento onClick()" android:id="@+id/btnOnClick" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="61dp" <!-- Propiedad donde se define el evento --> android:onClick="lanzarEvento" /> </RelativeLayout> Proyecto: creación de interfaz de usuario básico (versión XML y versión código) Vamos a mostrar a través de un ejercicio práctico, cómo construir elementos de la interfaz de usuario. Se tratará de una aplicación Android muy simple que presentará un control de entrada Button que al ser pulsado, mostrará un mensaje en la pantalla. Haremos dos versiones de este sencillo ejemplo, cuyo código podrás descargar al final de este tutorial:  Proyecto que denominaremos "InterfazUsuario" donde implementamos los controles de forma programática, es decir, se construyen dichos elementos en tiempo de ejecución (cuando la App se ejecuta en el dispositivo).  Proyecto que denominaremos "InterfazUsuarioXML" donde definiremos los controles a nivel de layout.
  • 91. Descripción y estructura del proyecto InterfazUsuario La aplicación será muy simple. Constará de una sola pantalla con el botón y el mensaje que aparecerá al pulsarlo, como vemos aquí: Los elementos necesarios para el desarrollo de este son:
  • 92.  Clase MainActivity , que herede de la clase base Activity , y que definirá la lógica de creación de instancias y diseño programático de las propiedades de la interfaz de usuario.  Layout activity_main.xml , formado por un layout de tipo RelativeLayout , que servirá como base para el resto de elementos que vayan construyéndose en tiempo de ejecución. En la siguiente imagen, se podrá apreciar cómo quedaría finalmente la estructura de elementos que intervienen en el proyecto (vista Android en el IDE Android Studio):
  • 93. Descripción del código fuente proyecto "InterfazUsuario" Una vez presentado brevemente el proyecto, vamos a explicar el código que contiene: InterfazUsuarioappsrcmainjavacomacademiaandroidinterfazusuarioMainActivity.class Activity que mostrará un control de tipo Button, creado en tiempo de ejecución, y que permitirá al usuario interaccionar con la aplicación al pulsar dicho botón: package com.academiaandroid.interfazusuario; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.Gravity; import android.view.View; import android.widget.Button; import android.widget.RelativeLayout; import android.widget.TextView; public class MainActivity extends Activity { Se declara tres variables de tipo TextView , Button y RelativeLayout a nivel de clase: private TextView tvHolaMundo; private Button btnSaludo; private RelativeLayout rlGeneral; El método onCreate() será llamado cuando se inicie la Activity , por lo que todo lo situado en su interior se inicializará al llamar a dicha Activity : @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
  • 94. En las siguientes líneas se crean las instancias de los objetos que serán inicializados al ejecutar la aplicación (reciben como parámetro de entrada el contexto de la aplicación). En este caso se trata del layout base de la Activity , y el control Button que aparecerá inicialmente: rlGeneral = new RelativeLayout(getApplicationContext()); btnSaludo = new Button(getApplicationContext()); El objeto btnSaludo invocará al método setText() para establecer el texto que mostrará el botón: btnSaludo.setText("Pulsa aquí"); Finalmente se añade el control Button al layout definido, para establecer dicho layout como base de la interfazde la aplicación: rlGeneral.addView(btnSaludo); setContentView(rlGeneral); A continuación, y todavía dentro del método onCreate() , se invoca al método setOnClickListener() del objeto btnSaludo ,encargado de controlar la pulsación del botón: btnSaludo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Dentro de este evento, se crea una instancia de TextView , para en las siguientes líneas invocar al método setTextColor() encargado de establecer el color del texto, y además establecer los parámetros para definir la posición del objeto tvHolaMundo dentro del layout. Para este último aspecto se crea una instancia de LayoutParams , que recibirá como argumentos para dicha instancia, el ancho y alto del layout definido: tvHolaMundo = new TextView(getApplicationContext()); tvHolaMundo.setTextColor(Color.BLACK); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutP arams( RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.Layou tParams.WRAP_CONTENT);
  • 95. En las siguientes líneas se establece el margen con respecto a la parte izquierda, superior, derecha e inferior de la pantalla, además de asignar los parámetros del layout y asignarle el texto "Hola Academia Android!!!" al invocar al método setText() : layoutParams.setMargins(5, 200, 150, 0); tvHolaMundo.setLayoutParams(layoutParams); tvHolaMundo.setText("Hola Academia Android!!!"); Por último se añade al layout implementado, para finalmente cerrar el método setOnClickListener, onCreate() y la clase MainActivity: rlGeneral.addView(tvHolaMundo); } }); } } InterfazUsuarioappsrcmainreslayoutactivity_main.xml Layout activity_main.xml que al definir los elementos de forma programática, sólo estaría formado por un RelativeLayout : <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuario.MainActivity" android:id="@+id/rlPrincipal"> </RelativeLayout>
  • 96. Descripción del código fuente proyecto "InterfazUsuarioXML" Si por el contrario, deseamos crear una aplicación similar a la anterior, enlazando los controles definidos en la interfaz de usuario, con las variables definidas en la clase, bastaría con realizar los siguientes pasos: A nivel de layout añadir dos controles, uno de tipo Button , y otro de tipo TextView . Para ello sólo bastará con seleccionar el layout creado por defecto al construir un proyecto con una Activity vacía, y que podremos encontrar dentro de la ruta InterfazUsuarioXMLappsrcmainreslayoutactivity_main.xml . Una vez estemos situados sobre dicho fichero XML, en la vista diseño, seleccionar los controles comentados anteriormente con un click, e indicaremos en qué posición queremos colocarlo en la interfaz de usuario. Tanto a nivel visual, como desde el punto de vista XML, quedaría de la siguiente forma:
  • 97. Como se puede apreciar en la imagen anterior, aunque se ha definido un control TextView (árbol de componentes), este no mostrará contenido debido a que la propiedad "text" se deja vacía, para posteriormente desde la clase MainActivity indicar que texto deseamos visualizar. InterfazUsuarioXMLappsrcmainreslayoutactivity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"
  • 98. android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.interfazusuarioxml.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Pulsa aquí" android:id="@+id/btnSaludo" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:id="@+id/tvHolaMundo" android:layout_below="@+id/btnSaludo" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> </RelativeLayout> A nivel de clase, se crearán dos variables de tipo Button y TextView : package com.academiaandroid.interfazusuarioxml; import android.app.Activity; import android.os.Bundle;
  • 99. import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private TextView tvHolaMundo; private Button btnSaludo; Para finalmente, dentro del método onCreate() , definir el resto de lógica del contenido de la vista y referencias de variables con sus recursos a nivel de layout. Como se puede apreciar, a diferencia del ejemplo anterior, el método setContentView() establece la referencia con el layout definido en los recursos de la aplicación, además de también referenciar las variables de tipo TextView y Button con los identificadores (propiedad id del control a nivel de layout). Esta tarea se realizará mediante el método findViewById() , que recibirá el identificador único asignado a ese control: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvHolaMundo = (TextView)findViewById(R.id.tvHolaMundo); btnSaludo = (Button)findViewById(R.id.btnSaludo); btnSaludo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tvHolaMundo.setText("Hola Academia Android!!!"); } });
  • 100. } } El resultado final con la pantalla de la App ejemplo sería muy similar a la otra versión: 4.1. Introducción y objetivos
  • 101. Siguiendo con los fundamentos para crear aplicaciones Android vamos a tratar en este tema la ejecución de tareas en segundo plano (background) en Android. Los objetivos que vamos a cubrir en este módulo son:  Entender la importancia de los hilos o subprocesos en un sistema operativo.  Conocer la lógica de jerarquías de procesos para aplicaciones Android.  Conocer las principales características de las clases AsyncTask, Handler, Thread y Runnable que nos permiten implementar tareas en segundo plano.  Saber cuando se recomienda el uso de AsyncTask o el uso de Threads.  Ver con un proyecto un ejemplo práctico de uso e implementación de tareas en background. 4.2. Hilo principal (main thread) Android es un sistema operativo multitarea que permite la ejecución de varias tareas simultáneamente. Esta característica que a simple vista nos puede parecer algo básico, facilita que en muchas ocasiones las aplicaciones actualicen información sin afectar a la respuesta y manejo del dispositivo donde se ejecutan. Para proporcionar esa funcionalidad, los procesos que se ejecutan han de poder descomponerse en hilos (threads). Un hilo de ejecución o subproceso es la unidad de procesamiento más pequeña que un sistema operativo puede manejar. Al desarrollar para Android, debemos tener muy presente la experiencia final del usuario que va a utilizar las aplicaciones que creamos. Toda tarea que necesite de recursos costosos del sistema deberá realizarse en un hilo secundario para evitar que bloquee el hilo principal de la aplicación, y afecte al usuario durante la ejecución de la misma.
  • 102. Por defecto, todos los componentes de la misma aplicación se ejecutan en el mismo proceso y es por eso que cuando hablamos del hilo principal o main thread, nos referimos al hilo de ejecución donde se ejecutan los componentes, servicios, actividades, etc. de una aplicación Android. Debido a la filosofía de Android respecto al consumo de recursos, el sistema se encarga de monitorizar el hilo principal y cualquier operación que supere los 5 segundos dará lugar a un mensaje de "Application Not Responding", permitiendo al usuario esperar o forzar el cierre de la aplicación. Android trata de mantener un proceso de aplicación durante el tiempo que sea necesario, pero necesita liberar recursos de memoria para procesos nuevos o de mayor importancia. Es aquí donde se delimita cada proceso en una "jerarquía de importancia", basado en los componentes que se ejecutan en el proceso y el estado de los mismos. Hay cinco niveles en la jerarquía de importancia. La siguiente lista muestra los diferentes tipos de procesos en orden de importancia: Procesos en primer plano: Proceso requerido para lo que el usuario está haciendo actualmente. Un proceso se considera que está en el primer plano si se dan cualquiera de las siguientes condiciones:  Activity que interactúa con el usuario (el método onResume() de la Activity ha sido llamado).  Cuando la Activity con la que interactúa el usuario aloja un Servicio ( Service ).  Cuando un Servicio ha llamado al método startForeground() , y por lo tanto se ejecuta en primer plano.  Cuando aloja un Servicio que será llamado durante el ciclo de vida de la aplicación ( onCreate() , onStart() u onDestroy() ).  Cuando aloja un BroadcastReceiver que está ejecutando el método onReceive() . Procesos visibles: Este tipo de procesos no define ningún componente en primer plano. Un proceso se considera visible:  Si se define una Activity que no está en primer plano pero es visible para el usuario (llamada al método onPause() del ciclo de vida de la aplicación).  Si se aloja un Servicio destinado a ser invocado en primer plano o a una actividad visible. Procesos de servicio: Aquellos procesos que se ejecutan en un Servicio (iniciados con StartService() ) y no pasan a las dos categorías superiores.
  • 103. Procesos en segundo plano: Proceso que se mantiene en una Activity en segundo plano, y que por lo tanto no es visible para el usuario (ocurre cuando se llama al método onStop() del ciclo de vida de la aplicación). Procesos vacíos: Se trata de procesos que no están presentes en los componentes de la aplicación. Android clasifica a un proceso en el nivel más alto que puede, en base a la importancia de los componentes activos en dicho proceso. Si por ejemplo un proceso recibe un servicio y una actividad visible, el proceso está clasificado como un proceso visible y no como un proceso de servicio. Créditos: parte de estos contenidos están basados en la documentación oficial de Android Developers que están publicados bajo licencia Creative Commons Attribution 2.5. Imagen de Cburnett publicada con licencia CC-BY-SA-3.0, via Wikimedia 4.3. Multitarea en Android con clases AsyncTask, Thread, Handler y Runnable En este apartado vamos a conocer las principales características de las clases AsyncTask, Handler, Thread y Runnable que nos permiten implementar tareas en segundo plano en una Aplicación Android. Al final, encontrarás también un cuadro comparativo donde vemos las situaciones donde se recomienda el uso de AsyncTask o de Threads. Como explicamos en el apartado anterior, cualquier componente de Android, como puede ser una Activity, se ejecuta en el hilo principal o main thread (UIThread). Si bien es cierto, que para operaciones rápidas no se encontrará ningún problema, es probable que necesitemos realizar procesos más costosos, y por lo tanto el hilo principal, encargado de mostrar la interfaz de usuario, quedaría bloqueado, con la consiguiente lentitud de cara al usuario. Es aquí donde interviene el sistema operativo Android, monitorizando todos los procesos que están en ejecución, y forzando a salir de la aplicación a aquellos que superen los 5 segundos. Para evitar este tipo de situaciones, Android proporciona una serie de clases, que permiten trabajar en segundo plano, para aquellas operaciones que necesiten un mayor tiempo para ser procesadas. Vamos a describirlas a continuación:
  • 104. AsyncTask Clase que permite comunicarse con el subproceso del hilo de interfaz de usuario o hilo principal. Para ello realiza operaciones en segundo plano, mostrando los resultados en subprocesos de la interfazde usuario. Características principales de la clase AsyncTask:  Proporciona un mayor control y orden en la ejecución de nuestros procesos en segundo plano.  Marco de trabajo para operaciones no muy costosas.  Las tareas se ejecutan en un sólo hilo, para evitar errores derivados de ejecuciones en paralelo.  Tarea asíncrona definida en 4 pasos: ( OnPreExecute() , doInBackground(Params...) , OnProgressUpdate(Progress...) y onP ostExecute(Result...)  Se añadió a partir de la versión Honeycomb (API nivel 11, versión Android 3.0). Aquí, puedes consultar la documentación oficial de la clase AsyncTask
  • 105. public void onClick(View v) { new DownloadImageTask().execute("http://example.com/image.png"); } private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { /** The system calls this to perform work in a worker thread and * delivers it the parameters given to AsyncTask.execute() */ protected Bitmap doInBackground(String... urls) { return loadImageFromNetwork(urls[0]); } /** The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */ protected void onPostExecute(Bitmap result) {
  • 106. mImageView.setImageBitmap(result); } } Implementación de AsynTask A nivel de implementación, se deberá heredar de la clase AsyncTask, donde se definen tres tipos genéricos: public class TareaAsyncTask extends AsyncTask<params, progress, result>{  Params: Tipo de parámetro que se recibirá como entrada para la tarea en el método doInBackground(Params).  Progress: Parámetros para actualizar el hilo principal o UIThread.  Result: Es el resultado devuelto por el procesamiento en segundo plano. Además de los tipos genéricos comentados anteriormente, será necesario sobreescribir los siguientes métodos para procesar y devolver la información tratada en segundo plano:  OnPreExecute() : Método llamado antes de iniciar el procesamiento en segundo plano.  doInBackground(Params...) : En este método se define el código que se ejecutará en segundo plano. Recibe como parámetros los declarados al llamar al método execute(Params).  OnProgressUpdate(Progress...) : Este método es llamado por publishProgress(), dentro de doInBackground(Params) (su uso es muy común para por ejemplo actualizar el porcentaje de un componente ProgressBar).  onPostExecute(Result...) : Este método es llamado tras finalizar doInBackground(Params). Recibe como parámetro el resultado devuelto por doInBackground(Params).  OnCancelled() : Se ejecutará cuando se cancele la ejecución de la tarea antes de su finalización normal. Thread
  • 107. Clase que proporciona su propia unidad concurrente de ejecución, y se puede definir como la unidad de procesamiento más pequeña que puede ser planificada por un sistema operativo. Una de sus principales características es permitir a una aplicación realizar varias tareas de manera simultánea. Define sus propios argumentos, variables y pila de llamada a métodos. Formas de ejecutar un hilo  Heredando (extends) de la clase base Thread y creando una instancia de dicha clase.  Implementando (implements) la interfaz Runnable, y creando una instancia de la clase que implementa dicha interfaz. Esta opción es muy útil cuando no es posible heredar de la clase base Thread. Nota: Ambas formas deben realizar la llamada al método start(), para procesar el código situado en el método run(). Características principales de la clase Thread:  Ejecución de tareas en paralelo o de manera concurrente.  Los hilos de ejecución comparten el espacio de memoria.  El conjunto de hilos en ejecución que comparten los mismos recursos es conocido como un proceso.  Cualquier modificación de un dato en memoria, por parte de un hilo, permite el acceso al dato modificado para el resto de hilos de manera inmediata.  Cada hilo presenta de manera propia el contador de programa, la pila de ejecución (o pila de llamadas, que consiste en una estructura dinámica de datos, en las que el último proceso en entrar será el primero en salir, o lo que es lo mismo, el último proceso se ejecutará primero) y el estado de la CPU.  Un proceso seguirá en ejecución si al menos uno de sus hilos de ejecución sigue activo. Si un proceso finaliza, todos sus hilos de ejecución también lo harán.  Añadida a partir de la API nivel 1, puedes encontrar aquí la documentación oficial de la clase Thread
  • 108. Implementación de Thread Se instancia la clase Thread, posteriormente se implementa el método run() , dónde se definirá el código a ejecutar cuando la instancia creada llame al método start() . Thread hilo1 = new Thread(new Runnable() { @Override public void run() { //Código a ejecutar } });
  • 109. hilo1.start(); Handler Es aquella que permite manejar y procesar mensajes, proporcionando un mecanismo para su envío (a modo de puente) entre threads o hilos, y así poder enviar mensajes desde nuestro hilo secundario al UIThread o hilo principal. Características principales de la clase Handler:  Permiten poner en cola una acción que se realiza en un subproceso distinto al suyo.  Cada instancia de la clase Handler está asociada a un sólo hilo y a la cola de mensajes de este.  Comunicación del hilo secundario con el hilo principal o UIThread a través de un controlador.  Proporciona varios métodos para poner en cola un mensaje en la parte delantera o enviar al final de la cola después de un determinado tiempo ( sendMessageAtFrontOfQueue(Message msg) y sendMessageAtTime(Message msg, long uptimeMillis) )  Añadida a partir de la API nivel 1, puedes consultar aquí la documentación oficial de la clase Handler
  • 110. Implementación de Handler Se instancia la clase Handler, para posteriormente llamar al método sendMessage() , encargado de avisar al UIThread para realizar las tareas de repintado incluidas en el método handleMessage(Message msg) . private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { } }; [...] handler.sendMessage(handler.obtainMessage()); [...] Runnable Interfaz que representa un comando que puede ser ejecutado. Es muy común su uso para la ejecución de código en un hilo diferente. Dicha interfaz implementa el método run() , que será llamado cuando un hilo es iniciado y creado dentro de una clase que implemente la interfaz Runnable . Implementación de Runnable Bastará con implementar la interfaz Runnable, y añadir el método run() (tras implementar la interfaz Runnable, nos indicará un error, y sólo deberemos posicionarnos sobre él y pulsar
  • 111. las teclas Alt + Enter y seleccionar la opción "Implement Methods", seleccionando el método a implementar, en nuestro caso el método run() ): public class Hilo implements Runnable { @Override public void run() { //Código a ejecutar al lanzar hilo. } } Aquí puedes consultar la documentación oficial de la clase Runnable AsyncTask vs Thread Para finalizar esta presentación de las clases que nos permiten implementar tareas en segundo plano en Android, vamos a comprender las situaciones en las que se recomienda el uso de la clase AsyncTask o la clase Thread, dependiendo de las necesidades del proyecto: Uso de AsynTask Uso de Threads  En operaciones de red que no requieran la descarga de grandes cantidades de datos.  Tareas sobre disco que no tomen más de algunos segundos.  En tareas cuyo resultado del procesamiento en segundo plano vaya a ser publicado en el subproceso del hilo de la interfaz de usuario.  No es necesario el uso de Handler.  En operaciones de red, ya sea de carga o descarga, con una moderada o alta cantidad de datos.  En tareas de gran consumo de CPU que deban ejecutarse en segundo plano.  En tareas que sea necesario controlar el consumo de CPU por parte del hilo gráfico a GUI (graphical user interface).  En tareas que deseemos controlar la prioridad de ejecución (cola de procesamiento).
  • 112.  No interacciona con el hilo de interfaz de usuario, siempre y cuando, el ciclo de vida de la aplicación no esté destinada a ejecutarse en segundo plano. 4.4. Proyecto ejemplo: tareas en segundo plano en Aplicación Android Vamos a ver un ejemplo práctico de implementación de tareas background en Android, con un proyecto en el que gestionaremos varios hilos en segundo plano mediante el uso de la clase AsyncTask. La aplicación que vamos a describir paso a paso, se encargará de simular tres barras de progreso , actualizando tanto el aspecto visual de la barra como el porcentaje asociado a la misma. Cada barra estará controlada por un hilo secundario en el que se modificarán los tiempo de duración para comprobar que dichos procesos no bloquean el hilo principal de la aplicación. Puedes descargar todo el código del proyecto en el siguiente apartado del curso. Descripción de la Aplicación Aunque mostraremos la aplicación en funcionamiento en un próximo video, para hacernos una idea podemos ver la pantalla principal de la app en la imagen de abajo. Como se aprecia, mostrará un botón junto con tres barras de progreso. Al ser pulsado dicho botón ("Tareas Segundo Plano"), se mostrará el proceso de avance de los diferentes componentes visuales:
  • 113. A continuación, enumeramos los elementos necesarios para el desarrollo del proyecto que vamos a denominar "TareasSegundoPlano":  Clase MainActivity , que herede de la clase base Activity , y cuya principal característica será la de lanzar las tareas que se ejecutarán en segundo plano, mostrando el progreso de las mismas.  Clase PorcentajeDos , que herede de la clase AsyncTask , y que gestionará una barra de progreso en segundo plano, actualizando el porcentaje cada 200 milésimas (1/5 segundo).
  • 114.  Clase PorcentajeCinco , que herede de la clase AsyncTask , y que gestionará una barra de progreso en segundo plano, actualizando el porcentaje cada 500 milésimas (1/2 segundo).  Clase PorcentajeDiez , que herede de la clase AsyncTask , y que gestionará una barra de progreso en segundo plano, actualizando el porcentaje cada 1000 milésimas (1 segundo).  Layout activity_main.xml , formado por un layout de tipo RelativeLayout , y que a su vez contiene un TableLayout , que dispondrá en diferentes filas tanto el botón como las barras de progreso implementadas. Versiones utilizadas: para realizar este proyecto se ha utilizado la versión de Android Studio 2.1.2 y la Versión SDK de compilación: API 23 para Android 6.0 Marshmallow. Estructura del proyecto Siguiendo con la lógica general de presentación del proyecto, en la siguiente imagen se visualizará la estructura de elementos que intervienen, todo desde la vista Android:
  • 115. Descripción del código fuente Continuando con la descripción del proyecto, en las siguientes líneas explicamos el código de las clases y fichero de layout que componen el mismo. TareasSegundoPlanoappsrcmainjavacomacademiaandroidtareass egundoplanoMainActivity.class Activity que mostrará un control de tipo Button y tres controles de tipo ProgressBar (control que indicará de manera gráfica el progreso de una tarea), que comenzarán su progreso una vez el usuario pulse el botón definido:
  • 116. package com.academiaandroid.tareassegundoplano; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends Activity { Se declara una variable de tipo Button a nivel de clase: private Button btnTareaSegundoPlano; Posteriormente, dentro del método onCreate() ,se asigna a la variable de tipo Button , el identificador único del control definido a nivel de layout, mediante el método findViewById() : @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnTareaSegundoPlano = (Button)findViewById(R.id.btnTareaSegundoPlano); [...] Finalmente, y todavía dentro del método onCreate() , se invoca al método setOnClickListener() del objeto btnTareaSegundoPlano , encargado de controlar la pulsación del botón y crear una instancia de la clase PorcentajeDos() .Procesará una de las tareas en segundo plano y recibe como argumento de entrada el contexto de la aplicación. Además como se puede apreciar, invoca al método execute() ,para la realización de la tarea: [...]
  • 117. btnTareaSegundoPlano.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new PorcentajeDos(MainActivity.this).execute("Carga Finalizada X2 "); } }); } } TareasSegundoPlanoappsrcmainjavacomacademiaandroidtareass egundoplanoPorcentajeDos.class Clase encargada de gestionar el porcentaje de una barra de progreso, en segundo plano, actualizando dicho componente cada 200 milésimas. Esta clase heredará de la clase base Asynctask<String, Integer, String> que como se comenta en apartados anteriores, define tres tipos genéricos, que en este ejemplo se trata de:  String: parámetro que se recibirá como entrada para la tarea en el método doInBackground(Params), y que mostrará el texto "Carga Finalizada X2"  Integer: parámetro que actualizará el hilo principal mediante el avance de la barra de progreso  String: que será el resultado devuelto por el procesamiento en segundo plano, en este caso el texto pasado como parámetro desde el método execute() : public class PorcentajeDos extends AsyncTask<String, Integer, String> { Se declaran a nivel de clase una variable de tipo MainActivity (establecerá el contexto de la aplicación para mostrar los diferentes mensajes por pantalla), una variable de tipo ProgressBar (permitirá actualizar la barra de progreso), y una variable de tipo TextView (actualizará el porcentaje actual): private MainActivity context; private ProgressBar progressBarDos;
  • 118. private TextView tvDos; Se define un constructor para establecer el contexto de la Activity de la aplicación: public PorcentajeDos(MainActivity context) { this.context = context; } El siguiente método será invocado al lanzar el hilo, mostrando el mensaje de "Progreso X2": @Override protected void onPreExecute() { super.onPreExecute(); Toast.makeText(context, "Progreso X2", Toast.LENGTH_LONG).show(); } El método doInBackground() , procesará el parámetro de entrada (en nuestro caso sólo será un mensaje que se muestre al finalizar la tarea) y actualizará el progreso del componente ProgressBar. Una de las particularidades del código situado dentro de este método, consiste en invocar al método sleep() de la clase Thread , para realizar una pausa de 200 milésimas en cada iteración (así se simula correctamente el funcionamiento de una barra de progreso): @Override protected String doInBackground(String... params) { Se establecen 100 iteraciones, por lo tanto se actualizará ese número de iteraciones el hilo principal de la aplicación: for(int i = 0; i <= 100; i++) { try {
  • 119. Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } publishProgress(i); } return String.valueOf(params[0]); } Este método asigna a la variable de tipo TextView su identificador único (control definido en el layout de la Activity principal). Como se puede apreciar, se invoca al método findViewById() desde el contexto de la aplicación definido en el constructor de esta clase. Finalmente se actualizará el valor de la variable TextView por cada ciclo del método doInBackground() : @Override protected void onProgressUpdate (Integer... valores) { super.onProgressUpdate(valores); progressBarDos = (ProgressBar)context.findViewById(R.id.progressBarDos); progressBarDos.setProgress(valores[0]); tvDos = (TextView)context.findViewById(R.id.tvDos); tvDos.setText(valores[0] + "%"); } El siguiente método tiene la particularidad de instanciar la clase PorcentajeCinco , para ejecutar dicha tarea en segundo plano: @Override protected void onPostExecute(String s) {
  • 120. super.onPostExecute(s); Toast.makeText(context, s,Toast.LENGTH_LONG).show(); new PorcentajeCinco(context).execute("Carga Finalizada X5"); } } Nota: Se utiliza la clase PorcentajeDos como ejemplo para describir el código fuente, ya que el resto de clases (PorcentajeCinco y PorcentajeDiez) tiene una estructura similar, salvo en el texto que se mostrará al lanzar y finalizar el hilo, como la frecuencia de actualización de la barra de progreso (parámetro del método sleep() dentro de doInBackground() ). TareasSegundoPlanoappsrcmainreslayoutactivity_main.xml Layout activity_main.xml que estará formado por un TableLayout , que establece la disposición de los elementos ordenados en filas, en las que se definen un control de tipo Button , y tres controles de tipo ProgressBar para las diferentes tareas que serán lanzadas por el usuario: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.tareassegundoplano.MainActivity"> <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="50dp">
  • 121. <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tarea Segundo Plano" android:id="@+id/btnTareaSegundoPlano" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/progressBarDos" android:layout_toRightOf="@+id/progressBarCinco" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <TextView
  • 123. <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/progressBarDiez" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:id="@+id/tvDiez" android:layout_column="2" /> </TableRow> </TableLayout> </RelativeLayout> 5.1. Introducción y objetivos En este tema estudiaremos las distintas formas de almacenar información de forma permanente en nuestras aplicaciones. Además veremos cómo integrar en nuestras aplicaciones elementos multimedia como el audio y el vídeo. Una vez finalizado el módulo seremos capaces de:  Almacenar datos sencillos a través de las configuraciones de usuario  Crear bases de datos SQLite, así como insertar, modificar y consultar datos de las mismas en nuestra aplicación.  Conocer las posibilidades de acceso a otros sistemas de bases de datos mas complejos.  Integrar en nuestras aplicaciones audios y vídeos. 5.2 Gestionar preferencias de usuario
  • 124. La clase SharedPreferences La forma más sencilla de almacenar datos en nuestras aplicaciones es recurrir a la clase SharedPreferences. Esta nos permite guardar y consultar posteriormente datos en forma de clave-valor, de modo que la clave será el nombre que demos al dato que queremos almacenar y el valor estará representado por alguno de los tipos de datos básicos: boolean, float, int, long y string. Las preferencias se almacenan en uno o varios ficheros que pueden ser privados o públicos para que otras aplicaciones puedan acceder a nuestras preferencias de usuario. Acceder a las preferencias de usuario Podemos crear y acceder a nuestros ficheros de preferencias de dos formas: Usando el método getSharedPreferences() Éste se usa si necesitamos diferentes ficheros de preferencias identificados por un nombre, que pasaremos como primer parámetro. Como segundo parámetro pasaremos el modo de acceso, que indicará si el fichero de preferencias es privado a nuestra aplicación, o si por el contrario otras aplicaciones podrán acceder a él. Tendremos varias posibilidades distintas para especificar el modo:  MODE_PRIVATE. Privado a nuestra aplicación. En la mayoria de los casos será el único modo que necesitemos.  MODE_WORLD_READABLE. Cualquier aplicación puede acceder al fichero de preferencias pero sólo en modo lectura. (Obsoleto desde la API 17).  MODE_WORLD_WRITABLE. Cualquier aplicación puede acceder al fichero en modo lectura y escritura. (Obsoleto desde la API 17).  MODE_MULTI_PROCESS. Permite comprobar si se han producido cambios en el fichero de preferencias, incluso aunque éste este abierto.  MODE_APPEND. Permite añadir nuevas preferencias en un fichero existente.  MODE_ENABLE_WRITE_AHEAD_LOGGING. Se utiliza para labores de depuración. Usando el método getPreferences() Éste se usa si sólo necesitamos un fichero de preferencias para una Activity. Únicamente recibe un parámetro, que será el modo de acceso a este fichero, el nombre vendrá implícito y será el nombre de la Activity. Añadir datos Para escribir datos usando la clase SharedPreferences lo haríamos de la siguiente manera:
  • 125. Obtenemos las preferencias usando por ejemplo el método getSharedPreferences() , a continuación obtenemos el objeto Editor mediante el método edit() , este objeto será el que nos permita modificarlas. SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE); SharedPreferences.Editor editor = propiedades.edit(); En este caso hemos utilizado el método para un único fichero de preferencias y el modo de acceso privado a la aplicación. Para añadir datos, podemos usar métodos tales como putBoolean() para almacenar un valor booleano, putString() para almacenar un String, putInt() para almacenar un entero, etc. Veamos cómo almacenar por ejemplo una cadena de texto y un entero: editor.putString("name", "Digital Learning"); editor.putInt("idCurso", 3); Para guardar los datos debemos hacer un commit del siguiente modo: editor.commit(); Recuperar datos Para recuperar los datos almacenados obtenemos de nuevo las preferencias del mismo modo que vimos antes. SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE); Sobre este objeto ya podremos obtener los valores directamente así: String name= preferences.getString("name", ""); int id = preferences.getInt("idCurso", -1); Vemos que los métodos getString y getInt reciben dos parámetros, uno es la clave del dato almacenado, y otro es un valor por defecto por si no se encuentra el dato representado por la clave dada. Crear una PreferenceActivity Normalmente necesitaremos que sea el usuario quien introduzca los valores de las preferencias de la aplicación, para ello podemos crear una interfaz en la que recoger los datos.
  • 126. Existe un tipo de Activity especial para este fin llamada PreferenceActivity, que nos permitirá crear de forma sencilla una interfaz en la que podremos añadir preferencias de distintos tipos para que el usuario defina sus valores. Para crear nuestra PreferenceActivity seguiremos los siguientes pasos: En primer lugar crearemos un fichero preferences.xml dentro de la carpeta res/xml con el siguiente contenido: <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <EditTextPreference android:title="Nombre" android:key="username" android:summary="Introduce tu nombre de usuario"></EditTextPreference> <CheckBoxPreference android:title="Buscar actualizaciones" android:defaultValue="false" android:summary="Marca si quieres que se busquen actualizaciones automáticamente" android:key="applicationUpdates" /> <ListPreference android:title="Interfaz" android:summary="Selecciona el tipo de interfaz de la aplicación" android:key="interfaz" android:defaultValue="1" android:entries="@array/listKeys" android:entryValues="@array/listValues" /> </PreferenceScreen> Podemos observar como se definen los 3 principales tipos de preferencias:  EditTextPreference  CheckBoxPreference  ListPreference Las dos primeras nos permiten crear campos de entrada de texto y CheckBox respectivamente, mientras que la tercera nos mostrara una lista desplegable cuyos valores seleccionables deben ser definidos en dos arrays: listKeys para el texto mostrado y listValues para el valor que se asignara a la variable. Para definir los dos arrays mencionados en el apartado anterior crearemos un fichero llamado array.xml dentro de la carpeta res/values con el siguiente contenido:
  • 127. <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="listKeys"> <item>Por defecto</item> <item>Clara</item> <item>Oscura</item> </string-array> <string-array name="listValues"> <item>1</item> <item>2</item> <item>3</item> </string-array> </resources> Este fichero tiene la misma utilidad que los mencionados en los primeros temas (strings, styles, etc) pero en esta ocasión servirá para almacenar listados de elementos que puedan ser consultados en cualquier parte de la aplicación. Ahora necesitamos crear la Activity que mostrará los datos. Para ello, creamos una nueva clase vacía en la misma carpeta de nuestra actividad principal que contendrá el siguiente código: package com.academiaandroid.demopreferences; import android.os.Bundle; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; public class PrefActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) {
  • 128. super.onCreate(savedInstanceState); getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPrefe renceFragment()).commit(); } public static class MyPreferenceFragment extends PreferenceFragment { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } } } En la última línea de código vemos cómo el método addPreferencesFromResource() carga el contenido del XML creado en el primer paso. Por último modificaremos el código de nuestra actividad principal para que lance la ventana de preferencias al iniciar la aplicación: package com.academiaandroid.demopreferences; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override
  • 129. protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Lanzamos la ventana de Preferencias Intent i = new Intent(this, PrefActivity.class); startActivity(i); } } Si ejecutamos la aplicación nos aparecerá una venta como esta:
  • 131. Para consultar los valores de las preferencias en cualquier parte la aplicación utilizaremos el siguiente código: SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()) ; String username = prefs.getString("username", "NA"); boolean applicationUpdates = prefs.getBoolean("applicationUpdates",false); String interfaz = prefs.getString("interfaz","1"); Muy similar al que vimos al principio de este apartado con la diferencia del método necesario para obtener el fichero de preferencias, que podemos ver en la primera linea de código. Última modificación: miércoles, 28 de septiembre de 2016, 19:59 5.2 Gestionar preferencias de usuario La clase SharedPreferences La forma más sencilla de almacenar datos en nuestras aplicaciones es recurrir a la clase SharedPreferences. Esta nos permite guardar y consultar posteriormente datos en forma de clave-valor, de modo que la clave será el nombre que demos al dato que queremos almacenar y el valor estará representado por alguno de los tipos de datos básicos: boolean, float, int, long y string. Las preferencias se almacenan en uno o varios ficheros que pueden ser privados o públicos para que otras aplicaciones puedan acceder a nuestras preferencias de usuario. Acceder a las preferencias de usuario Podemos crear y acceder a nuestros ficheros de preferencias de dos formas: Usando el método getSharedPreferences() Éste se usa si necesitamos diferentes ficheros de preferencias identificados por un nombre, que pasaremos como primer parámetro. Como segundo parámetro pasaremos el modo de
  • 132. acceso, que indicará si el fichero de preferencias es privado a nuestra aplicación, o si por el contrario otras aplicaciones podrán acceder a él. Tendremos varias posibilidades distintas para especificar el modo:  MODE_PRIVATE. Privado a nuestra aplicación. En la mayoria de los casos será el único modo que necesitemos.  MODE_WORLD_READABLE. Cualquier aplicación puede acceder al fichero de preferencias pero sólo en modo lectura. (Obsoleto desde la API 17).  MODE_WORLD_WRITABLE. Cualquier aplicación puede acceder al fichero en modo lectura y escritura. (Obsoleto desde la API 17).  MODE_MULTI_PROCESS. Permite comprobar si se han producido cambios en el fichero de preferencias, incluso aunque éste este abierto.  MODE_APPEND. Permite añadir nuevas preferencias en un fichero existente.  MODE_ENABLE_WRITE_AHEAD_LOGGING. Se utiliza para labores de depuración. Usando el método getPreferences() Éste se usa si sólo necesitamos un fichero de preferencias para una Activity. Únicamente recibe un parámetro, que será el modo de acceso a este fichero, el nombre vendrá implícito y será el nombre de la Activity. Añadir datos Para escribir datos usando la clase SharedPreferences lo haríamos de la siguiente manera: Obtenemos las preferencias usando por ejemplo el método getSharedPreferences() , a continuación obtenemos el objeto Editor mediante el método edit() , este objeto será el que nos permita modificarlas. SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE); SharedPreferences.Editor editor = propiedades.edit(); En este caso hemos utilizado el método para un único fichero de preferencias y el modo de acceso privado a la aplicación. Para añadir datos, podemos usar métodos tales como putBoolean() para almacenar un valor booleano, putString() para almacenar un String, putInt() para almacenar un entero, etc. Veamos cómo almacenar por ejemplo una cadena de texto y un entero: editor.putString("name", "Digital Learning"); editor.putInt("idCurso", 3); Para guardar los datos debemos hacer un commit del siguiente modo:
  • 133. editor.commit(); Recuperar datos Para recuperar los datos almacenados obtenemos de nuevo las preferencias del mismo modo que vimos antes. SharedPreferences propiedades = getPreferences(Context.MODE_PRIVATE); Sobre este objeto ya podremos obtener los valores directamente así: String name= preferences.getString("name", ""); int id = preferences.getInt("idCurso", -1); Vemos que los métodos getString y getInt reciben dos parámetros, uno es la clave del dato almacenado, y otro es un valor por defecto por si no se encuentra el dato representado por la clave dada. Crear una PreferenceActivity Normalmente necesitaremos que sea el usuario quien introduzca los valores de las preferencias de la aplicación, para ello podemos crear una interfaz en la que recoger los datos. Existe un tipo de Activity especial para este fin llamada PreferenceActivity, que nos permitirá crear de forma sencilla una interfaz en la que podremos añadir preferencias de distintos tipos para que el usuario defina sus valores. Para crear nuestra PreferenceActivity seguiremos los siguientes pasos: En primer lugar crearemos un fichero preferences.xml dentro de la carpeta res/xml con el siguiente contenido: <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <EditTextPreference android:title="Nombre" android:key="username" android:summary="Introduce tu nombre de usuario"></EditTextPreference> <CheckBoxPreference android:title="Buscar actualizaciones" android:defaultValue="false"
  • 134. android:summary="Marca si quieres que se busquen actualizaciones automáticamente" android:key="applicationUpdates" /> <ListPreference android:title="Interfaz" android:summary="Selecciona el tipo de interfaz de la aplicación" android:key="interfaz" android:defaultValue="1" android:entries="@array/listKeys" android:entryValues="@array/listValues" /> </PreferenceScreen> Podemos observar como se definen los 3 principales tipos de preferencias:  EditTextPreference  CheckBoxPreference  ListPreference Las dos primeras nos permiten crear campos de entrada de texto y CheckBox respectivamente, mientras que la tercera nos mostrara una lista desplegable cuyos valores seleccionables deben ser definidos en dos arrays: listKeys para el texto mostrado y listValues para el valor que se asignara a la variable. Para definir los dos arrays mencionados en el apartado anterior crearemos un fichero llamado array.xml dentro de la carpeta res/values con el siguiente contenido: <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="listKeys"> <item>Por defecto</item> <item>Clara</item> <item>Oscura</item> </string-array> <string-array name="listValues"> <item>1</item> <item>2</item>
  • 135. <item>3</item> </string-array> </resources> Este fichero tiene la misma utilidad que los mencionados en los primeros temas (strings, styles, etc) pero en esta ocasión servirá para almacenar listados de elementos que puedan ser consultados en cualquier parte de la aplicación. Ahora necesitamos crear la Activity que mostrará los datos. Para ello, creamos una nueva clase vacía en la misma carpeta de nuestra actividad principal que contendrá el siguiente código: package com.academiaandroid.demopreferences; import android.os.Bundle; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; public class PrefActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPrefe renceFragment()).commit(); } public static class MyPreferenceFragment extends PreferenceFragment { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState);
  • 136. addPreferencesFromResource(R.xml.preferences); } } } En la última línea de código vemos cómo el método addPreferencesFromResource() carga el contenido del XML creado en el primer paso. Por último modificaremos el código de nuestra actividad principal para que lance la ventana de preferencias al iniciar la aplicación: package com.academiaandroid.demopreferences; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Lanzamos la ventana de Preferencias Intent i = new Intent(this, PrefActivity.class); startActivity(i); } } Si ejecutamos la aplicación nos aparecerá una venta como esta:
  • 138. Para consultar los valores de las preferencias en cualquier parte la aplicación utilizaremos el siguiente código: SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()) ; String username = prefs.getString("username", "NA"); boolean applicationUpdates = prefs.getBoolean("applicationUpdates",false); String interfaz = prefs.getString("interfaz","1"); Muy similar al que vimos al principio de este apartado con la diferencia del método necesario para obtener el fichero de preferencias, que podemos ver en la primera linea de código. Última modificación: miércoles, 28 de septiembre de 2016, 19:59 7.3. Crear una cuenta de desarrollador En este apartado vamos a ver como crear una cuenta de desarrollador de Google Play, requisito necesario si queremos subir nuestras aplicaciones a la tienda de Google. Registro de datos El primer requisito es disponer de una cuenta de correo de Google. En caso de que no tengamos una podemos crearla en la siguiente dirección: https://accounts.google.com/SignUp?hl=es Estando identificados con nuestra cuenta nos dirigiremos a la web de Android Developers: https://developer.android.com/index.html Y pulsamos en el botón que se encuentra en la parte superior derecha de la misma, que nos llevará a la consola de desarrollo.
  • 139. En la siguiente ventana nos indicará la cuenta con la que estamos identificados, que será la que quedará asociada a nuestra cuenta de desarrollador; si es correcta, sólo tendremos que aceptar las condiciones del acuerdo de distribución de Google Play.
  • 140. Pago de la cuota de desarrollador La cuenta de desarrollador tiene un coste de 25 dolares; este pago es único y lo realizamos al darnos de alta. Actualmente, no es necesario realizar ninguna renovación periódica ni pago adicional para subir nuestras aplicaciones. Una vez aceptado el acuerdo de distribución hacemos click en el botón de completar el pago y nos aparecerá un popup como el que se muestra en la siguiente captura.
  • 141. Completaremos nuestros datos personales y dirección pulsaremos Continuar accediendo al siguiente paso. Aquí introduciremos los datos de la tarjeta con la que vayamos a pagar y finalizaremos el proceso pulsando en el botón Pagar
  • 142. A continuación se nos solicitarán nuestros datos de desarrollador, nombre, dirección de correo electrónico para notificaciones, sitio web y número de teléfono. Finalmente pulsaremos en el botón Completar Registro y con esto habremos finalizado el proceso de registro. Acceder a la consola de desarrolladores Para acceder a nuestra consola de desarrollo nos dirigiremos a la siguiente dirección: https://play.google.com/apps/publish/ En nuestro primer acceso se nos desplegará la pestaña de notificaciones en la que podremos acceder a distintas guías en las que se explican algunas funciones y características de la consola de desarrollo.
  • 143. 7.4. APK: generación de ejecutable de App Android y firma digital Si queremos publicar nuestras aplicaciones, estas deben ir firmadas digitalmente, quedando de esta manera asociadas de forma única a una clave de desarrollador que estará en nuestro poder. Esta clave puede ser única para todas nuestras aplicaciones o independiente para cada una de ellas (o para un grupo); lo único que debemos tener claro es que una vez publicada una aplicación, tan solo podremos actualizarla si va firmada con la misma clave. Si por cualquier motivo perdiéramos nuestra clave, no podríamos subir nuevas versiones de la misma, debiendo eliminar la aplicación publicada y crear una nueva si quisiéramos modificarla. Por esto, es importante que una vez generada una clave y firmada un aplicación con ella, la guardemos en un lugar seguro y creemos copias de seguridad de la misma. Firma de una aplicación Vamos a ver el proceso para realizar la firma de nuestra aplicación. Si además queremos publicar la aplicación en la Play Store de Google, debemos firmar digitalmente el APK generado. Describiremos el proceso para realizar ambos pasos:
  • 144. Vamos pues a describir el proceso para realizar ambos pasos: En primer lugar, para obtener el archivo compilado, se deberá seleccionar la opción "Build Variants" (ruta View > Tool Windows), y cambiar el estado del módulo a "release". A continuación se volverá a reconstruir el proyecto desde la ruta Build > Rebuild Project. En el supuesto de no tener almacenada una firma digital, se deberá crear una nueva a través de la ruta Build > Generate Signed APK..., en la nueva ventana se pulsará sobre el botón "Create new...", y será necesario completar los datos de la ventana denominada "New Key Store":
  • 145. Al pulsar en "OK", mostrará de nuevo la ventana "Generate Signed APK Wizard", con los datos de la nueva clave almacenada. Tras pulsar en "Next", se indicará el directorio dónde se almacenará el APK del proyecto, y a continuación se
  • 146. pulsará sobre el botón "Finish", mostrando finalmente un mensaje de que se ha generado correctamente: 7.5 Publicar en Play Store En este apartado veremos cómo subir nuestra aplicación a la tienda de Google una vez finalizado el desarrollo de la misma. Necesitaremos firmar nuestra aplicación, completar los distintos apartados de la ficha de aplicación y el cuestionario sobre los contenidos de la misma y finalmente, subir el apk de nuestra aplicación para que ésta esté disponible para la descarga.
  • 147. Firma de Aplicación Lo primero que haremos será firmar nuestra aplicación siguiendo los pasos que vimos en el apartado correspondiente. Nos dirigiremos al menú Build y seleccionaremos la opción: Generate Signed APK. Seleccionaremos nuestro almacén de firmas o crearemos uno nuevo en el caso de que no lo hayamos hecho aún y pulsaremos en Next.
  • 148. Seleccionaremos el directorio de salida y elegiremos el modo de compilación Release y finalmente pulsamos en Finish para completar el proceso. Nos aparecerá un mensaje indicando que el proceso ha terminado y podremos abrir la ubicación del fichero.
  • 149. Hay que tener en cuenta que si hemos utilizado Apis de Google que requieran su propia firma, como el caso de Google Maps, debemos haberlas incluido antes de generar el APK. Ficha de Aplicación Para publicar nuestra aplicación nos dirigiremos a la pagina de desarrolladores de Android y pulsaremos en Developer Console.
  • 150. Entre las opciones que aparecerán debemos pulsar el botón Publicar una aplicacion....
  • 151. Nos aparecerá una ventana emergente pidiéndonos los datos básicos de nuestra aplicación, el idioma y el nombre, que no puede superar los 50 caracteres. Una vez introducidos pasaremos a preparar la ficha de Play Store
  • 152. Completaremos los datos obligatorios: en primer lugar las descripciones breve y completa de la aplicación.
  • 153. Posteriormente las capturas de pantalla (screenshots), icono e imagen destacada, en caso de que queramos podemos incluir también una imagen o vídeo promocional.
  • 154. Por último completamos las distintas categorizaciones de nuestra aplicación y nuestros datos de desarrollador y política de privacidad si disponemos de ella.
  • 155. Con estos datos completados podemos guardar nuestra ficha de aplicación.
  • 156. El icono verde nos indica que todos los datos obligatorios están rellenos y por tanto la ficha esta lista para ser publicada.
  • 157. Subir Apk Una vez completada la ficha procederemos a subir el APK que generamos anteriormente, para ello nos dirigimos al menú APK.
  • 158. Nos aparecen 3 pestañas, nosotros sólo nos preocuparemos de la de Producción, pulsamos en el botón Subir APK a producción
  • 159. Nos aparecerá una ventana en la que podemos seleccionar o arrastrar nuestro APK. Una vez lo hagamos comenzará automáticamente la subida que llevará unos segundos dependiendo de nuestra conexión y del tamaño del fichero.
  • 160. Cuando concluya la subida nos aparecerá en el listado de versiones con el estado borrador en producción, ya que aun no está publicada.
  • 161. Podemos hacer clic en la versión para ver la información asociada, número y código de versión, texto con los cambios de la versión, permisos requeridos, etc.
  • 162. Ya tenemos nuestra aplicación subida, sólo nos quedan unos pocos pasos antes de poder publicarla. Política de Precios El siguiente paso será completar nuestra política de precios, nos dirigiremos al menú correspondiente.
  • 163. En nuestro caso indicaremos que la aplicación será gratuita para todos los países.
  • 164. Y que no contiene anuncios.
  • 165. En último lugar indicaremos el consentimiento con las directrices y leyes de exportación.
  • 166. Por supuesto, es recomendable leer toda la información que aparece en cada apartado para conocer lo que estamos aceptando. En caso de que queramos que nuestra aplicación sea de pago, tendremos que seguir una serie de pasos adicionales que están indicados en la documentación de la Consola de Desarrolladores. Una vez completado guardamos el borrador con la información introducida. Cuestionario de contenidos El último paso sera completar el formulario para aplicar la clasificación de contenido a nuestra app.
  • 167. Una vez en el apartado correspondiente pulsaremos en el botón Seguir para iniciar el cuestionario.
  • 168. Primero seleccionaremos el tipo de aplicación y a continuación comenzará el cuestionario.
  • 169. En él se nos preguntará por los contenidos y funciones que afecten a la privacidad de los usuarios para aplicar las distintas clasificaciones existentes. Es importante asegurarnos de completar este formulario de forma correcta ya que podría ser motivo de retirada de nuestra aplicación, si se mostraran contenidos inapropiados para nuestra calificación, por ejemplo, contenidos violentos sin haberlo indicado.
  • 170. Una vez completado pulsamos en el botón calcular clasificación.
  • 171. Se nos mostrarán las calificaciones de nuestra aplicación en las distintas zonas del mundo y si estamos de acuerdo las aplicaremos pulsando en el botón correspondiente.
  • 172. Una vez hecho ésto habremos completado todos los pasos mínimos requeridos para poder publicar nuestra aplicación. En la parte superior derecha de la pantalla nos aparecerá activo el botón correspondiente, y una vez lo pulsemos, nos aparecerá un mensaje indicando que el proceso se esta realizando y que en varias horas la aplicación estará disponible en la Play Store.
  • 173. Normalmente en un máximo de 5 horas, menos en la mayoría de los casos la aplicación estará disponible en la tienda de aplicaciones. 7.6. ASO (App Store Optimization) En este último apartado conoceremos las medidas que podemos seguir para que las aplicaciones que subamos a la tienda tengan más posibilidades de ser encontradas por los usuarios, entre el sinfín de aplicaciones que existen actualmente en la Play Store. Si bien se trata de conceptos más cercanos al marketing que al propio desarrollo, hoy en día es muy común que los propios desarrolladores tengan que gestionar todos los aspectos adicionales una vez lanzada la aplicación, especialmente si se trata de equipos muy pequeños o incluso de una única persona. Aunque Lo ideal es contar con personas cualificadas que puedan dedicarse a este tipo de tareas, los conceptos principales son fáciles de entender y algunos podemos ponerlos en práctica nosotros mismos sin una inversión excesiva de tiempo, así que es bueno tener unas nociones sobre este área. Para qué sirve el ASO Como su propio nombre indica el ASO (App Store Optimization) es un conjunto de medidas o prácticas destinadas a mejorar el posicionamiento de nuestra
  • 174. aplicación en la tienda de aplicaciones (ésto es aplicable también para aplicaciones iOS en la Apple Store), o lo que es lo mismo, a aumentar las posibilidades de que los usuarios encuentren y utilicen nuestra aplicación. Algunos lo llaman el "SEO para aplicaciones móviles". SEO es un conjunto de técnicas y recomendaciones para que las páginas web salgan mejor posicionadas en los resultados de búsqueda de buscadores como Google (sobre todo) o Bing. El ASO suele englobar tres tipos de acciones:  Optimizar elementos que influyan en los resultados de búsqueda de las tiendas de Apps.  Optimizar factores que afecten a las listas o rankings de esas tiendas.  Optimizar aspectos que mejoren las conversiones en descargas e instalaciones Describiremos estos elementos o factores un poco más abajo. Poner en práctica las recomendaciones ASO nos es muy útil, tanto si distribuimos una aplicación gratuita que queramos que llegue al máximo número de usuarios, como si queremos obtener ingresos con ella mediante venta directa, algun modelo fremium o mediante impresiones de publicidad que mostremos en la aplicación. Principales medidas o acciones A continuación vamos a enumerar algunas de las principales medidas que podemos llevar a cabo para mejorar nuestra posición en la Play Store, y en el subapartado siguiente, entraremos más en detalle para el que esté interesado:  Posicionamiento en búsquedas: una gran parte de los usuarios descubren las aplicaciones a través del buscador de la tienda, por ello debemos intentar que nuestra aplicación aparezca en las posición más destacada posible en los resultados de las búsquedas. Lo más importante para lograrlo es elegir las palabras clave o keywords con las que queremos aparecer y optimizar los textos al definir la aplicación en la tienda, utilizando dichos términos. Siempre debemos tener en cuenta que en las palabras clave más comunes habrá más competencia y también que siempre deben estar relacionados con nuestra aplicación o apareceremos en búsquedas que no se convertirán en descargas. Hablaremos un poco más en detalle de la elección y utilización de las palabras claves abajo.  Elección de categoría: otra forma muy común que tiene los usuarios de buscar aplicaciones es acudir directamente a los rankings de aplicaciones más populares o descargadas en cada categoría. Elegir bien la categoría
  • 175. de nuestra aplicación es importante ya que si conseguimos colocarnos entre las destacadas conseguiremos muchas descargas de usuarios de este tipo. Al igual que con las palabras clave debemos decidir si elegir las categorías más comunes, con más visitas pero con mucha competencia u otras en las que será mas fácil posicionarnos pero a cambio llegaremos a menos usuarios.  Valoraciones y comentarios: Tan importante como conseguir instalaciones es que la reputación de nuestra aplicación sea la mejor posible, y ésta se mide mediante la nota y los comentarios de los usuarios. Por lógica deberían estar en relación a la calidad de nuestra aplicación, pero la calidad no es una medida tan objetiva y siempre habrá usuarios que valoren funciones o características que no hemos implementado por no considerarlas prioritarias. Debemos responder a las opiniones criticas de forma razonada, manteniendo un tono correcto, aunque sean muy negativas e ignorando las provocaciones típicas de 'trolls'. Aprovechemoslos comentarios para corregir errores o aplicar mejoras sugeridas, en la medida de nuestras posibilidades. Las respuestas que demos y el nivel de mejora y actualización de la aplicación que podamos ir ofreciendo, va a influir también en la valoración de los usuarios.  Enlaces externos: Los usuarios no llegarán a nuestra aplicación sólo desde la tienda, también es necesario que puedan encontrarnos en los principales canales de la red. Para ello es muy recomendable disponer de una página web de nuestra aplicación bien posicionada en los buscadores (aplicando técnicas SEO, que mencionamos antes brevemente) así como de cuentas activas en las principales redes sociales (Twitter, Facebook, Instagram, etc). Conocer y utilizar correctamente el lenguaje propio de cada canal es vital para llegar al máximo numero de usuarios. También podemos plantearnos alojar nuestra aplicación en tiendas alternativas, en Android existen multitud de ellas.  Promoción: Por último podemos plantearnos campañas de publicidad para nuestra aplicación que complementen o refuercen el resto de medidas. En ocasiones una campaña de anuncios bien diseñada nos conseguirá un aumento puntual del volumen de instalaciones de la aplicación, subiendo su posicionamiento en los rankings y mejorando el resultado del resto de estrategias. Suelen ser recomendable utilizar las redes de publicidad especializadas en formatosy segmento móvil, aparte de anuncios en buscadores web o redes sociales, tanto por ser canales online muy afines, como por el control que podemoshacer del presupuesto y sus resultados (visitas y descargas conseguidas). Todas estas medidas nos ayudarán a conseguir instalaciones pero hay tres aspectos que no debemos olvidar:  La calidad y originalidad de nuestra aplicación es primordial para conseguir la recomendación de los usuarios. Hoy en día, el famoso 'boca a
  • 176. boca', con el uso tan extendido de blogs, foros o redes sociales es uno de los mejores medios para difundir nuestra aplicación.  Debemos tener en mente qué necesidades cubre nuestra app y a qué segmento de usuarios puede interesarle. Si definimos bien esa utilidad y el tipo de usuario potencial de la aplicación, podremos imaginarnos mejor cómo la buscarán en la tienda o en la propia web. Vemos un ejemplo sencillo al final de este apartado.  Aplicar algunas recomendaciones ASO nos puede ayudar, pero éstas son mucho más efectivas si se desarrollan de forma continuada a lo largo del tiempo, midiendo, analizando los resultados, y modificando y adaptando según este seguimiento de resultados que hacemos. Elementos/factores ASO En este subarpartado vamos a ampliar algunos puntos antes expuestos, para aquellos que tengan interés en este tema. No nos extenderemos en exceso, ya que éste no es un curso sobre ASO o marketing digital. Esperamos publicar próximamente algunos artículos en Academia Android para aquellos que quieran saber más sobre este apartado. Los elementos o factores ASO los podríamos dividir en dos grupos, on-metadata y off-metada. Explicamos qué significan y cuáles son. Elementos ASO on-metadata Son los elementos que podemos controlar directamente ya que son metadatos o información relacionada con la App que definimos nosotros. Dentro de este grupo tendríamos los metadatos que influyen en los resultados de búsquedas en Google Play (en App Store es similar, aunque hay algunos que varían o difieren respecto a éstos) y que asociamos a la Aplicación:  Título de la aplicación: 30 caracteres  Descripción: 4000 caracteres, aunque solo se muestran las primeras lineas al usuario que tiene que pinchar si quiere ver más. Es por tanto una descripción larga de lo que hace la aplicación, para qué sirve, que características destacadas tiene, información sobre ella que queremos resaltar, etc  Descripción breve: 80 caracteres. Como indica su nombre, debemos condensar lo fundamental que caracteriza nuestra aplicación  Categoría: debemos ubicar nuestra App en alguna de las categorías o temáticas que nos proporciona la tienda De forma esquemática y resumida, en este grupo de 'campos', una buena optimización consiste principalmente en:
  • 177.  Selección cuidadosa de palabras clave, pensando en si nos interesa competir en aquellas que tiene mucha popularidad y competencia o en más específicas y menos populares. .Deberíamos también analizar la 'competencia' (que palabras clave emplean las apps similares a la nuestra) o por qué términos buscan los usuarios.Citaremos abajo algunas herramientas que ayudan en esta labor.  Para el uso de estas keywords, deberemos tener en cuenta, entre otros, los límites de caracteres de cada 'campo', el evitar la repetición excesiva o infringir copyrights para no tener penalizaciones , o la localización (traducción/adaptación a distintos idiomas si nos dirigimos a mercados internacionales)  El nombre/título de la App debería ser significativo, diferenciador y atractivo para el usuario, incluyendo las palabras claves más significativas  Debemos redactar una descripción clara de la App, que 'venda' y sea informativa (las primeras líneas, recordemos, son fundamentales, porque son las que se ven por defecto), destacando por ejemplo lo qué ofrece al usuario o su valor diferencial. Debemos utilizar las palabras clave que hemos seleccionado de una forma natural en la redacción.  La elección de categoría es muy importante, con varios factores a tener en cuenta: idoneidad, por qué categoría buscarían los usuarios una App como la nuestra y competencia (quizás haya categorías menos populares donde puede encajar nuestra App y aumentar nuestras posibilidades de estar más altos en el ranking). Habría un segundo conjunto que no influyen en el posicionamiento directamente sino más en el grado de conversión de visitas a descarga e instalaciones. Se trata principalmente de elementos que por su diseño e impacto visual puedan llamar la atención del usuario:  Icono  Screenshots, es decir, capturas de pantalla de la aplicación  Video demostrativo o promocionalde la aplicación  Datos del desarrollador y actualizaciones de la aplicación No nos detendremos en ellos, solo indicar que aunque los tres primeros parezcan elementos accesorios, son muchas veces determinantes para que el usuario elija entre las opciones que se le presentan en las búsquedas. En cuanto al cuarto, está claro que ofrece más 'confianza' un perfil más completo y un historial de actualizaciones activo (una app que se dejó de actualizar hace 3 años, no es un buen reclamo para un usuario). Elementos ASO off-metadata Son elementos o factores en los que quizás podemos influir algo, pero están fuera de nuestro control, como son:
  • 178.  Número de descargas  Valoración: el rating que consigue la aplicación según la puntúan o votan los usuarios  Comentarios: el numero y contenido de los comentarios (*reviews*) que realizan los usuarios  La velocidad de las descargas: en cuánto tiempo se ha conseguido el total de descargas. Por ejemplo, si no es un volumen muy alto, pero ha sido en poco tiempo y de forma reciente, parece indicar que es una app nueva que ha ganado popularidad en cuanto se está conociendo, lo que atrae aún más a los usuarios. Selección y empleo de palabras clave Vamos a poner un ejemplo muy simplificado, pero que nos puede ayudar a visualizar algunas cuestiones que hemos expuesto anteriormente. Imaginemos que desarrollamos una aplicación que facilita la gestión de información relacionada con el el curso académico de cualquier colegio: fiestas, fechas de exámenes, reuniones (tutoría, asociación de padres), actividades extraescolares,...Lo primero que debemos tener en mente es a quiénes la dirigimos y qué finalidad o necesidades cubre. En este caso vamos a suponer que facilita a los padres de los alumnos la gestión de los eventos y el recordatorio de información relacionada con la actividad escolar de sus hijos. Con estas premisas, ¿cómo creemos que ese tipo de usuario puede buscar una aplicación como la nuestra? Ahí empieza una investigación que puede partir de un análisis propio , donde pensemos en listas de palabras relacionadas con el contexto de la aplicación: colegio, escuela, exámenes, tutorías..., y donde podemos utilizar diccionarios o thesaurus de sinónimos para sugerirnos más términos. El siguiente paso podría ser un análisis en Google Play de aplicaciones similares a la nuestra viendo que nombres y descripciones emplean. Podríamos incluso ir más allá y utilizar herramientas online especializadas como ésta, pero es algo que ya exige más experiencia y/o un coste de uso, y no vamos a entrar en ello. Por otro lado, tras realizar ese análisis, debemos valorar si las palabras clave que mejor nos encajan, son las más adecuadas en cuanto a popularidad y la competencia que podemos encontrar. Por ejemplo, la palabra clave 'agenda' seguramente tenga muchas búsquedas, pero nuestras posibilidades de salir alto en los resultados serán seguramente más bajas y además no especifica del todo lo que hace nuestra aplicación. En cambio con 'agenda escolar' podríamos estar mejor situados y corresponder más con la utilidad que el usuario estaba buscando (las palabras claves pueden considerarlas compuestas de varios términos, haciendo que aparezcan seguidos o muy juntos en los campos de (meta)información de la aplicación). ¿Cómo definimos a los algoritmos de indexación de los buscadores cuáles son nuestras palabras claves? Realmente no lo hacemos de forma explícita, sino utilizándolas en los campos de metadatos on-page que presentamos antes (los buscadores suelen también 'entender' y asociar variaciones de esas palabras:singular/plural....). Si queremos
  • 179. posicionarnos por 'agenda escolar' podemos llamar a nuestra aplicación "La agenda escolar" y redactar en las descripciones algo así: "Si quiere gestionar la agenda escolar del colegio de sus hijos, esta es su aplicación. En ella puede recordar la agenda de reuniones escolares (tutorías, asambleas de padres de alumnos), registrar los contactos de profesores, llevar la agenda de actividades extra-escolares......)." Ésto será más apropiado que llamar a nuestra aplicación "Mi agenda" ó "Gestión de las actividades del colegio" y redactar una descripción donde no incidimos es esas palabras claves, como por ejemplo: "Esta aplicación está principalmente pensada para gestionar reuniones, actividades o almacenar contactos de temas relacionados con el colegio de nuestros hijos...". En cualquier caso, ya decimos que este es un ejemplo simplificado, porque puede interesarnos también posicionarnos por palabras claves como 'agenda del colegio', 'actividades escolares', 'gestión del curso', 'fechas de exámenes'..., y/o haber optado por algo aún más específico como ' agenda escolar de los padres'. Eso exigiría establecer una prioridad: las más importantes deben aparecer siempre, incluyendo el título, mientras que otras pueden emplearse en las dos descripciones o solo en la descripción larga. También convendría refinarlo y no quedarnos con la primera versión que se nos ocurra. Las palabras claves deben emplearse de una manera natural y no excesivamente repetitiva. Deberíamos probar diversas versiones de la descripción y quedarnos con la que creamos que mejor consigue atraer el interés del usuario y además puede dejar lo más claro posible, tanto a él como al algoritmo automático de clasificación, de cuál es su función. Desafortunadamente no sabemnos exactamente como funcionan esos algoritmos y es más una cuestión de sentido común, que algo exacto. Eso sí, debemos evitar 'abusar' de las keywords, porque seguramente el algoritmo nos penalizará, aparte de que para el usuario sería una descripción sin sentido y de poca utilidad (por ejemplo si en la descripción solo ponemos 'agenda escolar' repetida continuamente hasta agotar los caracteres). Nota: este ejemplo es puramente teórico, y no se ha consultado Google Play ni ningún otro servicio. Pueden esxistir apps con estos nombres o similares, pero no tienen relación alguna con este ejemplo