Documente Academic
Documente Profesional
Documente Cultură
NDICE
1.1
INTRODUCCIN .............................................................. 3
1.1.1 Qu es Android .................................................................3
1.1.2 Proyecto libre (Open Source) ..........................................3
1.1.3 Su historia ..........................................................................3
1.1.4 Inconvenientes de Android..............................................4
1.2
QU ES ECLIPSE ............................................................. 5
1.2.1 El Consorcio Eclipse ........................................................5
1.2.2 Instalacin de Java Developmente Kit (JDK)................6
1.2.3 Instalacin de Eclipse ......................................................7
1.2.4 Instalacin de las libreras de Android...........................9
1.2.5 Aadir versiones y componentes de Android ............19
1.2.6 Definicin del dispositivo virtual de Android ..............25
Introduccin
1.1
INTRODUCCIN
1.1.1 Qu es Android
Android es un sistema operativo, inicialmente diseado para telfonos mviles como
los sistemas operativos iOS (Apple), Symbian (Nokia) y Blackberry OS.
En la actualidad, este sistema operativo se instala no slo en mviles, sino tambin en
mltiples dispositivos, como tabletas, GPS, televisores, discos duros multimedia, mini
ordenadores, etctera. Incluso se ha instalado en microondas y lavadoras.
Est basado en Linux, que es un ncleo de sistema operativo libre, gratuito y
multiplataforma.
Este sistema operativo permite programar aplicaciones empleando una variacin de
Java llamada Dalvik, y proporciona todas las interfaces necesarias para desarrollar fcilmente
aplicaciones que acceden a las funciones del telfono (como el GPS, las llamadas, la agenda,
etctera) utilizando el lenguaje de programacin Java.
Su sencillez principalmente, junto a la existencia de herramientas de programacin
gratuitas, es la causa de que existan cientos de miles de aplicaciones disponibles, que
extienden la funcionalidad de los dispositivos y mejoran la experiencia del usuario.
1.1.3 Su historia
Android era un sistema operativo para mviles prcticamente desconocido hasta que
en 2005 lo compr Google.
En noviembre de 2007 se cre la Open Handset Alliance, que agrup a muchos
fabricantes de telfonos mviles, procesadores y Google. Este ao se lanz la primera versin
de Android, junto con el SDK (del ingls, Software Development Kit, que significa Kit del
desarrollo de software) para que los programadores empezaran a crear sus aplicaciones
para este sistema operativo.
El despegue del sistema operativo fue lento porque se lanz antes el sistema operativo
que el primer terminal mvil, aunque rpidamente se ha colocado como el sistema operativo
de mviles ms vendido del mundo.
En febrero de 2011 se anunci la versin 3.0 de Android, cuyo nombre en clave es
Honeycomb, que est optimizada para tabletas en lugar de para telfonos mviles.
Versiones disponibles:
Las versiones de Android reciben nombre de postres en ingls. En cada versin el
postre elegido empieza por una letra distinta siguiendo un orden alfabtico:
C:
D:
E:
F:
G:
H:
I:
J:
Introduccin
1.2
QU ES ECLIPSE
Introduccin
Nota: en el caso de Linux o Mac, es posible tambin instalar Java usando los
programas habituales del sistema operativo que permiten la actualizacin de paquetes.
Nota: si vas a instalar Eclipse y las libreras de Android en Linux, lee las notas que se
encuentran en Preguntas y Respuestas de esta Introduccin en la mesa del curso.
Hay que tener en cuenta que debemos descargar la versin 32 bits o 64 bits en funcin
del sistema operativo de que dispongamos.
En el caso de Windows podemos ver el tipo de sistema operativo haciendo clic con el
botn derecho del ratn en el icono "Equipo" o Mi PC del Escritorio y haciendo clic de nuevo
en "Propiedades":
$ uname -m
x86_64
En el caso de Apple Mac, utiliza el Perfil de Sistema para determinar si ests utilizando
un kernel de 64 bits.
1. En el men Apple (
"Ms informacin":
Introduccin
10
Introduccin
Si no podemos seleccionar "jre6" debemos usar el botn "Add" para aadir las
libreras del JRE 6. Por ejemplo, en Windows, se pueden encontrar en el directorio:
"C:\Program Files\Java\jre6".
11
Para finalizar, en esta ventana hay que seleccionar la versin de Java utilizada para
compilar los proyectos de Android. Para ello hacemos clic en Java->Compiler y elegimos
1.6 en el campo Compiler compliance settings:
12
Introduccin
Importante: Es necesario disponer de conexin a Internet para poder continuar con los
siguientes pasos y poder descargar las libreras necesarias.
13
14
Introduccin
15
16
Introduccin
para
descomprimir
el
archivo
del
SDK
es
18
Introduccin
19
20
Introduccin
Nota: la revisin de las versiones de Android puede ser superior cuando al alumno o
alumna instale el SDK.
Una vez hemos pulsado el botn Install 6 packages, aparece esta ventana y
seleccionamos la opcin Accept All y, despus, hacemos clic en Install:
Ahora vamos a ver la estructura que tiene el SDK de Android. Para ello, abrimos el
explorador en el directorio C:\cursos_Mentor\Android\android-sdk-windows o en el
directorio donde lo hayamos descomprimido. La siguiente tabla describe los subdiretorios que
contiene esta carpeta:
22
Introduccin
NOMBRE
CARPETA
DESCRIPCIN
add-ons/
Contiene los paquetes add-on del SDK de Android que permiten desarrollar
aplicaciones usando libreras externas disponibles para algunos dispositivos
o terminales.
docs/
platformtools/
platforms/
samples/
tools/
SDK
Readme.txt
Archivo que explica cmo realizar la configuracin inicial del SDK de Android.
SDK
Manager.exe
23
24
Introduccin
25
26
Introduccin
Importante: En el curso hemos creado un dispositivo virtual que no guarda el estado porque
puede producir problemas de ejecucin con Eclipse. En todo caso, el alumno o alumna puede
usar la opcin Edit del AVD cuando crea necesario que los ltimos cambios sean
almacenados para la siguiente sesin de trabajo
27
28
INTRODUCCIN AL ENTORNO
ANDROID
NDICE
1.1
1.2
1.3
1.4
1.5
1.1
1.1.1 Introduccin
En esta Unidad vamos a explicar las caractersticas y la arquitectura de Android.
Adems, describiremos el entorno de desarrollo Eclipse y crearemos nuestro primer
proyecto Android.
Tambin, detallaremos los ficheros bsicos que componen un proyecto Android.
Finalmente, usaremos Paneles de diseo (Layout) y Componentes (View) para
disear la interfaz de usuario en ejemplos de aplicaciones de Android.
Diseado para
dispositivo
pequeos
Almacenamiento
Conectividad
Mensajera
Navegador web
Soporte de Java
Soporte para
streaming
(distribucin en
Internet)
Entorno de
desarrollo
Market
(Mercado de
aplicaciones)
Multi-tctil
Bluetooth
Videollamada
Multitarea
Caractersticas
basadas en voz
32
a todas las
33
Android usa Java como lenguaje base para el desarrollo de las aplicaciones. Por lo tanto,
hace uso de los Paquetes Java (Package en ingls). Estos paquetes son contenedores de
clases que permiten agrupar las distintas partes de un programa cuya funcionalidad tienen
elementos comunes.
El uso de paquetes proporciona las siguientes ventajas:
34
Reutilizacin de cdigo
para crear los ficheros bsicos de un proyecto Android. Fjate en qu la orden anterior es una
nica lnea que debes ejecutar en la lnea de comandos de tu sistema operativo.
C:\>cd C:\cursos_Mentor\Android\proyectos
C:\cursos_Mentor\Android\proyectos> android create project --package
es.mentor.unidad1.eje1.bienvenido --activity Bienvenido --target android-10
bienvenido
--path
35
Ahora no vamos a examinar en detalle los ficheros que hemos creado y que conjuntamente
forman el proyecto Android. En el siguiente apartado de esta Unidad los detallaremos con un
ejemplo real en Eclipse.
36
1.2
Actividades (Activities): una actividad representa una pantalla nica con una interfaz
de usuario. Por ejemplo, una aplicacin de correo electrnico puede tener una
actividad que muestra una lista de correo electrnico nuevo, otra actividad que
compone un correo y otra actividad que lee los mensajes. Aunque las actividades
trabajan conjuntamente para dar la sensacin de una nica aplicacin, cada una de
ellas es independiente de las otras. Por lo tanto, otra aplicacin externa diferente
podra iniciar cualquiera de estas actividades (si la aplicacin de correo electrnico lo
permite). Por ejemplo, una aplicacin que gestiona los contactos podra iniciar la
actividad que compone nuevos mensajes de correo indicando como destinatario del
mensaje al contacto seleccionado en la primera aplicacin.
Una actividad se implementa a partir de la clase Java Activity. Ms adelante veremos
cmo se usa.
Puedes pensar en una actividad de Android como si fuera una ventana en una
aplicacin de escritorio o una pgina HTML en una aplicacin Web. Android est
diseado para cargar muchas actividades pequeas, por lo que se permite al usuario
abrir nuevas actividades y pulsar el botn Atrs para ir a un estado anterior, al igual
que se hace en un navegador web.
Servicios (Services): un servicio es un componente que se ejecuta en segundo plano
y que realiza operaciones cada cierto tiempo. Un servicio no proporciona una interfaz
grfica al usuario. Por ejemplo, un servicio puede reproducir msica en segundo plano
mientras el usuario est en otra aplicacin, o puede obtener informacin de Internet sin
la interaccin del usuario. Otros componentes, como una actividad, pueden iniciar un
servicio e interactuar con l si es necesario.
Un servicio se implementa a partir de la clase Java Service. Ms adelante veremos
cmo se usa.
Proveedores de contenidos (Content providers): un proveedor de contenidos
maneja el conjunto de datos compartido de la aplicacin. Puede almacenar
informacin en el sistema de archivos, en una base de datos SQLite, en Internet o en
cualquier otro lugar de almacenamiento permanente al que la aplicacin tenga acceso.
A travs del proveedor de contenidos, otras aplicaciones pueden consultar e incluso
modificar los datos (si el proveedor de contenidos lo permite). Por ejemplo, Android
proporciona un proveedor de contenidos que gestiona la informacin de los contactos
del telfono. Por lo tanto, cualquier aplicacin, con los permisos adecuados, puede
hacer
una
consulta
al
proveedor
de
contenido
de
los
contactos
Los proveedores de contenidos se utilizan tambin para escribir y leer datos que son
privados de la aplicacin y no se comparten. Por ejemplo, una aplicacin de Notas
puede utilizar un proveedor de contenidos para guardar las notas.
Un proveedor de contenidos se implementa a partir de la clase ContentProvider y
debe implementar un conjunto estndar de mtodos (API) que permiten a otras
aplicaciones interaccionar con l. Ms adelante veremos cmo se usa.
Receptores de mensajes (Broadcast receivers): un receptor de mensajes responde
a mensajes difundidos (broadcast) a todos los elementos del sistema. Por ejemplo, un
mensaje puede anunciar que la pantalla se ha apagado, la batera est descargada o
que se ha capturado una foto. Las aplicaciones tambin pueden emitir este tipo de
mensajes para, por ejemplo, indicar a otras aplicaciones que ciertos datos ya han sido
descargados en el dispositivo y estn disponibles para ser utilizados. Aunque estos
receptores de mensajes no muestran informacin en la interfaz del usuario, s que
pueden crear una notificacin en la barra de estado (la barra que aparece arriba en
Android) para alertar al usuario cuando se produce este tipo de mensajes.
Un receptor de mensajes se implementa a partir de la clase BroadcastReceiver y
cada mensaje emitido es un objeto del tipo Intent (Intencin). Ms adelante veremos
cmo se usa.
Componentes de la pantalla de inicio (Widgets): estos componentes visuales se
usan principalmente en la Pantalla de inicio (HomeScreen) de Android para mostrar
informacin que se actualiza peridicamente como, por ejemplo, un reloj, la previsin
del tiempo, etctera. Al tratarse de programacin avanzada no los estudiaremos en
este curso de iniciacin a Android.
Otros componentes de Android son las Carpetas animadas (Live Folders) y los
Fondos de pantalla animados (Live Wallpapers) en la Pantalla de Inicio. Las
carpetas animadas permiten a Android mostrar informacin en la pantalla inicial sin
necesidad de lanzar la aplicacin correspondiente. Igualmente, al tratarse de
programacin avanzada, no los estudiaremos en este curso de iniciacin a Android.
Un aspecto nico del diseo del sistema Android es que cualquier aplicacin puede iniciar un
componente de otra aplicacin. Por ejemplo, si es necesario para la aplicacin abierta
capturar una imagen con la cmara de fotos, seguramente ya exista otra aplicacin que hace
eso y que la aplicacin inicial puede reutilizar en lugar de desarrollar el cdigo necesario para
capturar la foto. nicamente hay que iniciar la actividad de la aplicacin de la cmara de fotos
y capturar la imagen. La sensacin del usuario es como si la cmara formara parte de la
aplicacin inicial.
Cuando el sistema arranca un componente, ste inicia un proceso (si no est ya en
ejecucin) para que la aplicacin cree las instancias de las clases necesarias del componente.
39
Por ejemplo, si una aplicacin inicia la actividad de la aplicacin de la cmara que hace fotos,
la actividad se ejecuta en el proceso que pertenece a la aplicacin de la cmara, no en el
proceso de la aplicacin original que ha hecho la llamada a la otra aplicacin. Por lo tanto, a
diferencia de otros sistemas operativos, las aplicaciones de Android no tienen un punto de
entrada nico (no hay funcin main()).
Debido a que el sistema ejecuta cada aplicacin en un proceso independiente con
permisos restringidos, sta no puede activar directamente un componente de otra aplicacin,
sino que es el sistema operativo Android el encargado de hacerlo. Por lo tanto, para activar un
componente de otra aplicacin es necesario enviar un mensaje al sistema que especifica su
intencin (clase Intent) de iniciar un componente en particular. Por lo tanto, el sistema
operativo es el encargado de activar el componente solicitado.
1.3
40
1.3.1.1
Editores
Editor
1.3.1.2
Vistas
Adems del Editor, existe un segundo tipo de ventanas secundarias, que se llaman
Vistas.
Las Vistas son ventanas auxiliares para mostrar informacin, introducir datos, etctera.
Las Vistas se usan con mltiples propsitos, desde navegar por un rbol de directorios, hasta
mostrar el contenido de una consulta SQL.
41
Vistas
Si deseamos cambiar las Vistas, se puede usar la opcin Show View en el men de la
pestaa Window.
42
1.3.1.3
Adems de la barra de herramientas principal (imagen anterior), cada Vista puede tener
su propia barra de herramientas secundaria.
1.3.1.4
Perspectivas
43
Si el alumno tiene dudas sobre el uso avanzado de Eclipse, en Internet existen muchos
tutoriales que indican cmo utilizarlo.
Adems, es posible usar el men "Help" o la tecla [F1] para solicitar ayuda.
Desgraciadamente, a da de hoy, esta ayuda slo se encuentra en ingls.
Importante: para importar en Eclipse el cdigo fuente de los ejemplos del curso hay que
usar la opcin del men principal: File -> Import.
44
Despus, hay que marcar Existing Proyects into Workspace en la ventana emergente y
pulsar en el botn Next:
los
ficheros
con
el
cdigo
fuente
de
los
ejemplos:
45
Nota: en esta Unidad 1 puedes encontrar el vdeo Cmo cargar los ejemplos en Eclipse,
que muestra cmo se importan los ficheros con el cdigo fuente de los proyectos que son los
ejemplos del curso.
46
1.3.2.1
47
Pulsamos el botn Finish para crear los ficheros del proyecto.
A continuacin, describimos los apartados que genera un proyecto Android:
Build Target: indica la versin del Android SDK que vamos a usar para compilar
la aplicacin. Por ejemplo, si seleccionas Android 2.3, la aplicacin se compilar
para funcionar en esta versin de Android y las siguientes. La versin
seleccionada aqu no tiene que coincidir con la versin del Emulador de Android
(AVD), ya que las aplicaciones de Android estn diseadas de manera que se
48
Importante: El nombre del paquete debe ser nico en relacin con todos los paquetes
instalados en Android. Por esta razn, es importante utilizar el estndar de dominio para
nombrar los paquetes de las aplicaciones. En el ejemplo anterior se utiliza el nombre de
paquete "es.mentor". A la hora de desarrollar tus propias aplicaciones y distribuirlas en el
Android Market (Mercado de aplicaciones Android) debes utilizar nombres propios de
paquetes.
En ningn caso debes utilizar el nombre es.mentor para distribuir aplicaciones en el Android
Market, pues slo es vlido para los ejemplos del curso.
1.3.2.2
Nombre de la actividad
1.3.2.3
Para ver los ficheros del proyecto Android creados por Eclipse, en la barra lateral
Package Explorer, desplegamos las entradas haciendo clic en los ficheros marcados con
flechas rojas de los diferentes paquetes:
49
/res/drawable-X/: contiene las imgenes de la aplicacin. Se divide en /drawableldpi, /drawable-mdpi y /drawable-hdpi para utilizar diferentes recursos dependiendo
de la resolucin del dispositivo.
50
Carpeta /gen/
Rene una serie de elementos de cdigo generados automticamente al compilar el
proyecto. Cada vez que compilamos el proyecto, Android genera una serie de ficheros fuente
Java dirigidos al control de recursos de la aplicacin.
El archivo ms importante es el que se puede observar en la imagen anterior, el fichero
R.java que define la clase Java denominada R.
Esta clase R contiene un conjunto de constantes con los ID de todos los recursos de la
aplicacin incluidos en la carpeta /res/, de forma que el programador pueda acceder
fcilmente a estos recursos desde el cdigo fuente a travs de esta clase. As, por ejemplo, la
constante R.drawable.icon define el ID de la imagen icon.png contenida en la
carpeta /res/drawable/. Veamos como ejemplo la clase R creada por defecto para el
proyecto nuevo:
Importante: Esta clase la crea automticamente Android por lo que no debemos modificarla.
51
Carpeta /assets/
Alberga el resto de ficheros auxiliares necesarios para que aplicacin funcione, como
los ficheros de configuracin, de datos, etctera.
La diferencia entre los recursos incluidos en la carpeta /res/raw/ y los incluidos en la
carpeta /assets/ es que para los primeros se generar un ID en la clase R y se deber acceder
a ellos usando un mtodo de esta clase. Sin embargo, para los segundos no se generarn un
ID y se puede acceder a ellos por su ruta como a cualquier otro fichero del sistema.
Aplicaremos unos u otros segn las necesidades de nuestra aplicacin.
Carpeta /bin/
Es el directorio donde se guarda la aplicacin una vez se ha compilado.
Carpeta /libs/
Es el directorio donde se almacenan las libreras de tipo JAR que amplan las
funcionalidades de la aplicacin.
Fichero AndroidManifest.xml:
Contiene la definicin en formato XML de las caractersticas principales de la aplicacin,
como, por ejemplo, su identificacin (nombre, versin, icono, etctera), sus componentes
(Actividades, Mensajes, Servicios, etctera) o los permisos necesarios para su ejecucin.
Veremos ms adelante otros detalles de este fichero.
Importante: Haciendo doble clic sobre estos ficheros podemos abrirlos en el Editor de
Eclipse. Es importante que el alumno se familiarice con este entorno de desarrollo y pruebe
las distintas opciones del mismo.
52
1.3.2.4
Una vez hemos creado el proyecto, vamos a explicar cmo ejecutamos esta aplicacin
de prueba con Eclipse y el emulador de Android (AVD: Android Virtual Device).
Para ello, hacemos clic en el botn "Ejecutar" de la barra de herramientas principal
o en la opcin "Run" de men Run. Tambin disponemos del atajo del teclado
[Ctrl+F11]
53
Eclipse inicia el emulador de Android AVD en el ordenador que ests utilizando, para
que puedas probar el proyecto que has desarrollado. Ten en cuenta que el dispositivo
virtual tarda un rato en cargar cada vez que lo inicias. Hay que tener un poco de paciencia
hasta que parezca la ventana de inicio.
54
Cuando accedemos por primera vez al emulador, aparece la pantalla de bienvenida con
el terminal bloqueado:
Para desbloquear la pantalla hay que arrastrar el icono "candado" con el ratn hacia la
derecha.
Una vez desbloqueado el AVD, podemos ver el aspecto de la aplicacin instalada:
55
Importante: En general, cada vez que modifiquemos el cdigo fuente y deseemos probar de
nuevo nuestro proyecto no es necesario parar el emulador de aplicaciones y arrancarlo de
nuevo; simplemente hacemos clic de nuevo en el botn Run y Eclipse compilar, reinstalar
y ejecutar la aplicacin modificada.
Una vez hayamos acabado de probar nuestro proyecto, es necesario parar el emulador de
Android.
Nota: En esta Unidad 1 puedes encontrar el vdeo Cmo ejecutar un proyecto Android, que
muestra cmo usar Eclipse para compilar y ejecutar los proyectos que son los ejemplos del
curso.
1.3.2.5
57
58
Para movernos en esta pantalla, podemos usar el ratn como si fuera el dedo de tu
mano. Es decir, para ver los iconos que estn abajo hay que hacer clic en la pantalla y, sin
soltar el botn del ratn, arrastrar la ventana hacia arriba:
Haciendo clic con el ratn sobre el icono de una de las aplicaciones, el emulador la
ejecutar.
A continuacin, vamos a modificar el idioma del sistema operativo. Para ello, haciendo
clic en el icono Settings aparece la siguiente pantalla:
Arrastrar hacia
con el ratn
abajo
59
Desplazando con el ratn hacia arriba esta ventana hacemos clic en Language &
keyboard:
60
Para acabar, desplazamos de nuevo la pantalla hacia arriba hasta que veamos el idioma
en el que deseamos configurar Android:
Arrastrar hacia
con el ratn
abajo
61
Si usamos el botn Volver atrs, veremos que el idioma del sistema operativo ha
cambiado en la Pantalla Inicial (Home Screen):
62
1.4
A continuacin, vamos a explicar cmo crear un proyecto sencillo usando Eclipse y las
libreras Android.
Vamos a partir del proyecto de ejemplo que hemos creado en el punto anterior.
El primer proyecto Android consiste en una pantalla muy sencilla que muestra un
mensaje de bienvenida.
En la barra lateral Package Explorer de Eclipse, desplegamos las entradas haciendo
clic en las flechas de los diferentes paquetes.
63
package es.mentor.unidad1.eje1.bienvenido;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
65
Nota:
Al ejecutar varias veces una aplicacin desde Eclipse puede ocurrir que aparezcan los
siguientes mensajes de error en la consola:
66
67
Atributo
Descripcin
xmlns:android
android:id
Define el largo que debe ocupar la Vista. En este caso, indicamos que
android:layout_width el TextView debe ocupar toda la pantalla con "fill_parent.
android:layout_height
android:text
68
Usando en esta ventana el botn Add podemos aadir visualmente los diferentes
tipos de recursos de Android.
Para crear la primera aplicacin hemos usado componentes (Widgets o Vistas) usuales
de Android. En el siguiente apartado de teora explicaremos en detalle el tipo de componentes
disponibles por defecto y cmo usarlos para disear las pantallas que servirn de interfaz
grfica al usuario.
Fichero AndroidManifest.xml: contiene la definicin en formato XML de las
caractersticas principales de la aplicacin, como su identificacin (nombre, versin, icono,
etctera), sus componentes (Actividades, Mensajes, Servicios, etctera) o los permisos
necesarios para su ejecucin. Ms adelante veremos otros detalles de este fichero.
En este fichero hay que declarar la Actividad para que Android tenga acceso a la misma.
Si abres el archive manifest, vers que existe el siguiente elemento <activity>:
69
<?xmlversion="1.0"encoding="utf8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
...
<activityandroid:name=".BienvenidoActivity"
android:label="@string/app_name">
...
</manifest>
1.5
70
71
fill_parent para que el componente hijo tenga la dimensin del layout que lo
contiene.
Ejemplo
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText android:id="@+id/TextoNombre"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
72
horizontal.
De igual forma que en un FrameLayout, se pueden establecer las propiedades
android:layout_width
android:layout_height.
Adems,
existe
la
propiedad
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<EditText android:id="@+id/TextoDato1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1" />
<EditText android:id="@+id/TextoDato2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2" />
</LinearLayout>
73
ndices
de
las
columnas
separados
por
comas,
por
ejemplo:
Ejemplo
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<TextView android:text="Celda 1.1">
<TextView android:text="Celda 1.2">
</TableRow>
<TableRow>
74
Desde Eclipse puedes abrir el proyecto Ejemplo 2 (Panel tabla) de la Unidad 1. Estudia
el cdigo fuente y ejectalo para mostrar en el emulador el resultado del programa anterior,
en el que hemos utilizado el Layout TableLayout.
android:layout_above: arriba.
android:layout_below: debajo.
android:layout_toLeftOf: a la izquierda de.
android:layout_toRightOf: a la derecha de.
android:layout_alignLeft: alinear a la izquierda.
android:layout_alignRight: alinear a la derecha.
android:layout_alignTop: alinear arriba.
android:layout_alignBottom: alinear abajo.
android:layout_alignBaseline: alinear en la base.
centro.
Ejemplo
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText android:id="@+id/TextoNombre"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button android:id="@+id/BtnAceptar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/TextoNombre"
android:layout_alignParentRight="true" />
</RelativeLayout>
76
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/imagen" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Imagen" />
</FrameLayout>
En este ejemplo, mostramos una imagen que ocupa todo el rea de la pantalla usando
el atributo android:scaleType="center" y una etiqueta superpuesta en la parte inferior de la
pantalla con el atributo android:layout_gravity="center_horizontal|bottom".
77
Componentes Bsicos
Como hemos comentado anteriormente, los interfaces de las aplicaciones de usuario en
Android se construyen usando componentes o Vistas que estn contenidas en paneles de
diseo (layout). Los componentes permiten al usuario interaccionar con la aplicacin. Los
paneles ordenan la posicin de estos elementos en la interfaz del usuario.
A continuacin, vamos a mostrar los componentes bsicos.
Botones
Los botones se usan para que el usuario interacte con la aplicacin Web:
El SDK de Android proporciona tres tipos de botones: el botn clsico (Button), el de
tipo on/off (ToggleButton) y el que puede albergar una imagen (ImageButton).
definimos un botn con el texto Haz clic aqu asignando la propiedad android:text.
<Button android:text="Haz clic aqu"
android:id="@+id/boton" android:layout_height="wrap_content"
android:layout_width="135dp">
</Button>
Adems,
podemos
utilizar
otras
propiedades,
como
el
color
de
fondo
estados: pulsado (ON) o no_pulsado (OFF). En este caso, en lugar de definir un nico
texto, podemos establecer dos en funcin del estado asignando las propiedades
android:textOn
android:textoOff,
respectivamente.
Veamos
un
continuacin:
<ToggleButton android:id="@+id/toggleButton"
android:text="ToggleButton" android:layout_width="88dp"
android:textOn="Encendido"
android:textOff="Apagado"
android:layout_height="match_parent">
78
ejemplo
</ToggleButton>
</ImageButton>
definir
la
lgica
de
este
evento
hay
que
definir
un
nuevo
objeto
En el caso del botn de tipo ToggleButton suele ser ms til conocer el estado en el
que est el botn tras ser pulsado. Para esto, se usa el mtodo isChecked(). En el siguiente
ejemplo se comprueba el estado del botn despus de ser pulsado y se realizan diferentes
acciones segn su resultado:
79
Etiqueta (TextView)
android:layout_height="wrap_content" />
<TextView android:id="@+id/texto2" android:text="Fuente Serif"
android:layout_width="wrap_content"
80
android:layout_height="wrap_content"
android:textSize="25dp"
android:typeface="serif" />
<TextView android:id="@+id/texto3" android:text="Negrita"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold" />
<TextView android:id="@+id/texto4" android:text="Cursiva"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40dp"
android:textColor="#FF0000"
android:textStyle="italic" />
Adems, podemos modificar estas propiedades desde nuestro cdigo Java usando los
mtodos getText() para recuperar el texto de una etiqueta, setText() para actualizar el texto y
setBackgroundColor() para cambiar el color de fondo. Por ejemplo, as:
// Buscamos la etiqueta con el id texto1
final TextView lblEtiqueta = (TextView)findViewById(R.id.texto1);
String texto = lblEtiqueta.getText().toString();
texto += " abc";
lblEtiqueta.setText(texto);
Imagen (ImageView)
otras, como las destinadas a establecer el tamao mximo que puede ocupar la imagen:
android:maxWidth y android:maxHeight. Fjate en el cdigo del siguiente ejemplo:
<ImageView android:id="@+id/ImgFoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon" />
android:layout_width="match_parent"
android:layout_height="wrap_content">
Tambin es posible recuperar y establecer este texto mediante los mtodos getText() y
setText(nuevoTexto) respectivamente:
82
texto = txtTexto.getText().toString();
txtTexto.setText("Esto es un texto");
83
android:layout_height="wrap_content">
<CheckBox android:id="@+id/check1" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Android" />
android:layout_height="wrap_content"
android:text="Confirmar Seleccin"
android:layout_gravity="center_vertical" />
boolean isChecked)
84
{
if (isChecked) {
txtTexto.setText("Checkbox "+ buttonView.getText() +
" marcado!");
}
else {
txtTexto.setText("Checkbox "+ buttonView.getText() +
" desmarcado!");
}
}
};
android:layout_height="fill_parent">
<RadioButton android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
85
Una vez definida la interfaz, podemos manipular los componentes desde el cdigo java
haciendo uso de los diferentes mtodos del componente RadioGroup como, por ejemplo:
En cuanto a los eventos iniciados por este componente, como los CheckBox, el ms
til es el que informa de los cambios en el elemento seleccionado onCheckedChange. Fjate
en el siguiente ejemplo:
86
87
en
una
carpeta
personal.
Recomendamos
usar
el
directorio
88
Para comprobar que una aplicacin funciona, hay que hacer clic en la opcin "Run"
de men "Run" de Eclipse (Atajo del teclado [Ctrl+F11]); despus, arrancar el
Emulador (AVD) de Android para ver el resultado de su ejecucin.
Un Dispositivo Virtual de Android (en ingls, AVD, Android Virtual Device) emula
un terminal instalado con Android en el que podemos probar las aplicaciones
desarrolladas.
Todas las sentencias de Android (Java) deben acabar con ;.
Las sentencias o instrucciones compuestas contienen varias sentencias simples y
deben estar incluidas entre los signos { y }. Generalmente, una sentencia
compuesta est integrada por sentencias simples de un bucle o de la declaracin
de una funcin que deben ejecutarse como un bloque.
Para poder seguir mejor el flujo de un programa y ver ms intuitivamente su
cdigo, conviene indentar (adentrar unos espacios) las sentencias que estn
incluidas dentro de una estructura. En Eclipse podemos usar el atajo de teclado
[CTRL+I] para hacerlo automticamente.
Los comentarios ayudan mucho a comprender un programa. Los que slo
ocupan una lnea deben ir precedidos de los signos //. Si el texto ocupa ms de una
lnea, hay que incluirlo entre los signos /* y */.
Android dispone de todas las variables, funciones, expresiones y operadores
ms usuales de Java.
Una de las caractersticas ms importante de Android es la posibilidad de usar
componentes grficos dinmicos y reutilizables (en ingls se denominan Views).
Los paneles en Android se usan para disear (en ingls se denomina layout) la
interfaz grfica del usuario de la aplicacin.
El entorno de Eclipse ayuda al programador mostrando una ventana emergente
de ayuda al escribir el cdigo fuente. En ella se proponen los diferentes mtodos
disponibles
para
esa
clase.
Disponemos
tambin
del
atajo
de
teclado
[CTRL+BARRA_ESPACIADORA].
89
90
NDICE
2.1 ACTIVIDADES - ANDROID .................................................. 93
2.1.1 Introduccin..............................................................................93
2.1.2 Creacin de una actividad......................................................93
2.1.3 Ciclo de vida de una actividad ..............................................94
2.1.4 Cmo se implementa el ciclo de vida de una actividad ....94
2.2 EVENTOS Y LISTENERS ...................................................... 100
2.2.1 Gestionando los eventos del usuario ............................. 100
2.2.2 Uso de los Event Listeners ............................................. 100
2.2.3 Gestores de Eventos (Event Handlers)........................... 104
2.2.4 Modo tctil de pantalla ................................................... 105
2.2.5 Controlando la Vista con el foco activo.......................... 106
2.3 USO DEL EMULADOR DE ANDROID ................................. 106
2.3.1 Teclado del emulador ..................................................... 108
2.3.2 Cmo introducir tildes con el Teclado del Emulador ..... 110
2.3.3 Limitaciones del Emulador ............................................. 111
2.3.4 Tamao ventana emulador ............................................. 111
2.3.5 Otras opciones del Emulador ......................................... 112
2.3.6 Cmo configurar las opciones del Emulador ................. 113
2.4 COMPONENTES AVANZADOS ........................................... 114
2.4.1 Qu son los Adaptadores de Android (adapters) ........... 114
2.5 COMPONENTES PERSONALIZADOS................................ 127
2.5.1 Diseo de componentes personalizados ....................... 127
2.5.2 Cmo crear un componente extendido ......................... 127
2.5.3 Cmo combinar varios componentes para crear uno
compuesto ........................................................................... 130
2.1
ACTIVIDADES - ANDROID
2.1.1 Introduccin
Una Actividad (Activity) es un componente de Android que ofrece una pantalla
con la que los usuarios pueden interactuar con la aplicacin, como marcar el telfono,
sacar una foto, enviar un correo electrnico o ver un mapa. Cada Actividad tiene asociada una
ventana en la que se dibuja la interfaz de usuario. Normalmente, esta ventana ocupa toda la
pantalla, aunque puede ser menor que sta o flotar sobre otras ventanas.
Por lo general, una aplicacin de Android consta de mltiples actividades que estn
ms o menos ligadas entre s. Habitualmente, se define una actividad "principal", que es la que
se presenta al usuario cuando se inicia la aplicacin por primera vez. Una actividad puede
iniciar otra actividad con el fin de realizar diferentes operaciones. Cada vez que comienza una
nueva actividad, la actividad anterior se detiene y la enva a una pila de retroceso ("back
stack"). Esta pila usa el mecanismo de cola LIFO ("last in, first out"), por lo que, cuando el
usuario pulsa la tecla Volver atrs del mvil, se extrae de la pila la actividad anterior
(destruyndose la pila) y se reanuda. En la Unidad 3 veremos en detalle cmo funciona esta
pila.
Cuando una actividad se para porque se inicia una nueva actividad, se le notifica este
cambio de estado a travs de los mtodos de llamada callback
actividad.
Una funcin de llamada (en ingls callback) es una funcin que se remite a Android
cuando se inicia una Actividad, para que el sistema operativo la llame durante la ejecucin
de esta Actividad.
Existen varios mtodos de llamada callback que una actividad puede recibir debido a
un cambio en su estado; por ejemplo, cuando el sistema crea la Actividad, cuando se reactiva
o cuando se destruye. El programador puede aprovechar estos mtodos para ejecutar
sentencias especficas apropiadas para el cambio de estado. Por ejemplo, cuando una
Actividad se suspende es recomendable liberar de la memoria todos los objetos grandes.
Cuando la actividad se reanuda, se puede volver a reservar los recursos necesarios y
continuar con las acciones que se interrumpieron. Estos cambios de estado forman parte
del ciclo de vida de la actividad.
@Override
protected void onRestart() {
super.onRestart();
Toast.makeText(this, "Se ejecuta el mtodo onRestart", 1).show();
}
// Definimos el evento callback onResume de la Actividad
@Override
protected void onResume() {
super.onResume();
Toast.makeText(this, "Se ejecuta el mtodo onResume", 1).show();
}
// Definimos el evento callback onStart de la Actividad
@Override
protected void onStart() {
super.onStart();
95
}
// Definimos el evento callback onDestroy de la Actividad
@Override
protected void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Se ejecuta el mtodo onDestroy", 1).show();
}
// Definimos el evento callback onStop de la Actividad
@Override
protected void onStop() {
super.onStop();
Toast.makeText(this, "Se ejecuta el mtodo onStop", 1).show();
}
A continuacin, vamos a ver el ciclo de vida de una Actividad siguiendo sus estados y
los mtodos callback que desencadena cada uno de ellos:
El ciclo de vida de una Actividad ocurre entre las llamadas a los mtodos onCreate()
y OnDestroy(). En el primer mtodo la Actividad debe realizar la reserva de memoria,
el diseo de la interfaz de usuario y recuperar el estado de la sesin anterior. En el
segundo mtodo, hay que liberar todos los recursos usados con anterioridad.
El ciclo de vida "visible" de una Actividad ocurre entre las llamadas a los mtodos
OnStart() y OnStop(). Durante este tiempo el usuario puede ver e interactuar con la
pantalla de la Actividad. El sistema invoca el mtodo OnStop()cuando se inicia una
nueva actividad y la actual ya no est visible al usuario. Entre estos dos mtodos, el
programador debe definir y destruir respectivamente los recursos necesarios para
mostrar la Actividad para el usuario.
96
97
Mtodo
Descripcin
Kill
Siguiente
mtodo
onCreate()
No
onStart()
onRestart()
No
onStart()
onResume()
o
onStop()
No
onResume()
No
onPause()
onResume()
o
onStop()
onPause()
98
Mtodo
Descripcin
onStop()
Kill
Siguiente
mtodo
onRestart()
o
onDestroy()
ninguno
onDestroy()
La columna "Kill" de esta tabla indica si el sistema puede matar (kill) el proceso de la
Actividad cuando finaliza la ejecucin del mtodo sin ejecutar ninguna sentencia ms de la
Actividad. Hay tres mtodos as: onPause(), onStop() y onDestroy().
onPause() es el mtodo que se ejecuta siempre en caso de que el sistema operativo
mate una Actividad. Sin embargo, no es posible asegurar que el sistema invoque los mtodos
OnStop() y OnDestroy() porque se haya ejecutado onPause() y la Actividad haya acabado.
Por lo tanto, se debe utilizar el mtodo onPause() para guardar los datos importantes y
persistentes de la Actividad. No obstante, hay que ser selectivo sobre qu informacin debe
guardarse durante onPause(), ya que este mtodo bloquea el inicio de una nueva Actividad y
el usuario podra notar que el telfono se enlentece.
Los mtodos que se han marcado con "No" en la columna "Kill" estn, a priori,
protegidos. El sistema operativo slo los "mata" en una situacin de inestabilidad con falta de
memoria.
En la Unidad 3 veremos cmo usar esos eventos para guardar el estado de una
Actividad y poder recuperarlo cuando sta se reinicia.
cdigo fuente y ejectalo para mostrar en el emulador una aplicacin en la que hemos
utilizado los mtodos del ciclo de vida de una Actividad.
2.2
EVENTOS Y LISTENERS
El siguiente ejemplo muestra cmo especificar los mtodos de los eventos sobre un
EditText:
// Definimos el evento Change del EditText
texto.addTextChangedListener(new TextWatcher() {
101
switch (view.getId()) {
if (texto.getText().length() == 0) {
Toast.makeText(this, "Por favor, introduce un nmero",
Toast.LENGTH_LONG).show();
return;
}
102
if (kilometrosButton.isChecked()) {
distancia.setText("Kms son " +
formatoNumero.format(inputValue*0.6214) + " Millas");
} else {
distancia.setText("Millas son " +
formatoNumero.format(inputValue*1.6093) + " Kms");
}
break;
Recuerda que los eventos de tipo teclado siempre afectan a la Vista que est activa en
ese momento.
103
104
Hay otros mtodos que, aunque no forman parte de la clase Vista, debes conocer, ya
que permiten gestionar eventos de otros componentes de Android. Son los siguientes:
ViewGroup.onInterceptTouchEvent(MotionEvent):
permite
la
Vista
105
<LinearLayout
android:orientation="vertical"
... >
<Button android:id="@+id/arriba"
android:nextFocusUp="@+id/abajo"
... />
<Button android:id="@+id/abajo"
android:nextFocusDown="@+id/arriba"
... />
</LinearLayout>
Por lo general, en el diseo vertical anterior, intentar ir hacia arriba desde el primer
botn no cambia el foco de la aplicacin. Lo mismo ocurre con el segundo botn al intentar ir
hacia abajo. Sin embargo, al haber definido en el botn superior el nextFocusUp para pasar al
segundo botn, el foco cambia al botn de abajo y viceversa.
Si queremos indicar que una Vista que por defecto no recibe el foco de la aplicacin
pueda recibirlo, podemos usar el atributo XML de la Vista android:focusable al diseo la
interfaz de usuario. Tambin podemos usar el atributo android:focusableInTouchMode
cuando se trate del modo tctil.
Tambin desde el cdigo Java podemos usar el mtodo requestFocus() para indicar
al sistema que una Vista debe tener el foco.
2.3
Para desbloquear la pantalla hay que arrastrar con el ratn el icono "candado" hacia la
derecha.
La tabla siguiente resume las relaciones entre las teclas del emulador y las teclas del
teclado de tu ordenador:
Inicio
108
Funcin
Se vuelve a la pantalla
principal de Android.
Volver
Llamar
Colgar
Buscar
Botn encender/apagar
F2 o RePg
ESC
F3
F4
F5
BLOQUE_NUM_MAS (+),
Ctrl+5
Bajar volumen
BLOQUE_NUM_MENOS (-)
Ctrl+F6
Cambio orientacin
Conexin datos
Pantalla completa
Bola navegacin
Entra momentneamente en
modo bola navegacin.
Buscar informacin.
F7
Subir volumen
Cmara
Muestra un men
desplegable con las
opciones de la pantalla
actual.
F8
Alt+Intro
F6
Suprimir
El emulador ocupa la
pantalla completa del
monitor del ordenador.
Inicia el modo de
navegacin con bola
(trackball)
Mientras tengamos pulsada
la tecla Suprimir
109
Arrastrar izq/arriba/dcha/abajo
BLOQUE_NUM_4/8/6/2
Ten en cuenta que para usar las teclas del bloque numrico es necesario desactivar el
bloqueo numrico en tu ordenador.
NOTA: es recomendable familiarizarse con el emulador de Android usando las funciones del
dispositivo virtual e ir visitando las diferentes opciones del mismo as como utilizar los atajos
de teclado de la tabla anterior.
Pulsar un rato
110
Pulsar un rato
Atencin: tambin es posible pulsar un rato en la tecla de la vocal del teclado del ordenador
donde ests trabajando para poder escribir la tilde correspondiente.
111
En esta ventana podemos ver la escala (Scale) que se aplicar a la ventana del
emulador (un nmero entre 0,1 y 3). Para ello, podemos especificar la densidad del monitor del
ordenador en puntos por pulgada (Monitor DPI) y el tamao en pulgadas de la pantalla del
dispositivo Android (Screen Size).
Para arrancar el emulador basta con hacer clic en el botn Launch.
112
113
Nota: no todas las opciones posibles del Emulador estn incluidas en la ventana anterior;
algunas deben configurarse mediante rdenes en la lnea de comandos del sistema operativo
de tu ordenador.
En la Unidad 8 veremos cmo usar esta ventana para depurar aplicaciones Android.
2.4
COMPONENTES AVANZADOS
114
caso,
usamos
un
ID
de
diseo
predefinido
por
Android
<Spinnerandroid:id="@+id/ListadoOpciones"
android:prompt="@string/selecciona"
android:drawSelectorOnTop="true"
115
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
//
Si
se
selecciona
una
// actualizamos la etiqueta
opcin,
mostramos
un
mensaje
});
116
Para cambiar el aspecto de las opciones de la lista emergente hay que usar el mtodo
setDropDownViewResource(ID_layout). En este caso hemos utilizado el diseo predefinido
de Android para las listas desplegables android.R.layout.simple_spinner_dropdown_item.
Esto provoca que el diseo de la seleccin y el listado desplegable sean diferentes (fjate en el
cambio de color):
117
La Lista de seleccin (o ListView en ingls) permite al usuario hacer clic sobre una lista
de opciones seleccionables. Estas opciones se muestran directamente sobre el propio
componente; por lo tanto, no se trata de una lista emergente como el Spinner. Si no se
visualizan todas las opciones disponibles en la pantalla del dispositivo porque no caben, se
puede desplazar el listado con el dedo o los botones de navegacin.
En el ejemplo siguiente vamos a usar un Adaptador particularizado para que dibuje las
opciones del men personalizadas.
Fjate en el cdigo del siguiente ejemplo que define un ListView en el fichero main.xml
de layout de la aplicacin:
Ejemplo
<ListView android:id="@+id/ListaOpciones"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Para enlazar el adaptador que define las opciones de este tipo de listado y tratar el
evento que ocurre cuando el usuario selecciona una de las opciones disponibles, escribimos
las siguientes sentencias:
// En este caso definimos la matriz de opciones usando la clase Opcion
private Opcion[] datos = new Opcion[32];
...
// Definimos 32 Opciones en el ListView
for(int i=1; i<=32; i++)
datos[i-1] = new Opcion("Opcin " + i, "sta es la opcin " + i);
118
}
});
Fjate
que
en
este
caso
hemos
utilizado
un
nuevo
tipo
de
Adaptador:
AdaptadorOpciones(Activity contexto) {
}
// Mtodo que dibuja la Vista de cada Opcin
// Se invoca cada vez que haya que mostrar un elemento de la lista.
119
VistaTag vistaTag;
// Si Android indica que no hay una Vista reutilizable para
//la opcin, la definimos, inflamos el diseo que se define
// en el fichero listitem_opcion.xml y establecemos su contenido
If (item == null)
{
// Usamos un Inflater para inflar el diseo
// Ahora tenemos una Vista que se asocia al elemento
LayoutInflater inflater = contexto.getLayoutInflater();
// Definimos en la vista de vuelta el tipo de diseo
item = inflater.inflate(R.layout.listitem_opcion, null);
// Definimos el objeto que vamos a almacenar en el
//nuevo elemento
vistaTag = new VistaTag();
// Obtenemos los punteros a las etiquetas recin infladas
vistaTag.titulo = (TextView)item.findViewById(R.id.LblTitulo);
vistaTag.subtitulo =
(TextView)item.findViewById(R.id.LblSubTitulo);
// Guardamos el objeto en el elemento
item.setTag(vistaTag);
}
else
{
// Si estamos reutilizando una Vista, recuperamos el
// objeto interno
vistaTag = (VistaTag)item.getTag();
}
// Cargamos las opciones de la matriz de datos
vistaTag.titulo.setText(datos[position].getTitulo());
vistaTag.subtitulo.setText(datos[position].getSubtitulo());
// Devolvemos la Vista (nueva o reutilizada) que dibuja
// la opcin
return(item);
}
120
usa
para
almacenar
las
etiquetas
de
tipo
TextView
121
Ejemplo
<GridView android:id="@+id/GridOpciones"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:columnWidth="80px"
android:horizontalSpacing="5px"
android:verticalSpacing="10px"
android:stretchMode="columnWidth" />
Como en los anteriores ejemplos, para enlazar el adaptador que define las opciones de
este tipo de listado escribimos las siguientes sentencias:
122
ArrayAdapter<String> adaptador =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, datos);
Ejemplo
<AutoCompleteTextView android:id="@+id/miautocomplete"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
/>
Como en los anteriores ejemplos, para enlazar el adaptador que define las opciones de
este tipo de listado escribimos las siguientes sentencias:
123
...
miAutoComplete =
(AutoCompleteTextView)findViewById(R.id.miautocomplete);
miAutoComplete.addTextChangedListener(this);
miAutoComplete.setAdapter(adaptador);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
// Aqu escribimos
cambiado
}
124
el
cdigo
que
se
ejecuta
cuando
el
texto
ha
@Override
public void afterTextChanged(Editable s) {
Una Actividad con lista de seleccin (en ingls, ListActivity) es una actividad heredada
de la clase Activity que ya incluye el componente de seleccin ListView.
El componente ListActivity tiene un diseo predeterminado que consiste en una lista
de seleccin que ocupa toda la pantalla del dispositivo. Sin embargo, es posible personalizar
el diseo de esta lista usando la funcin setContentView() en el evento OnCreate() de la
Actividad. Para poder redisear esta lista de seleccin es obligatorio que, en el fichero
main.xml de layout de la aplicacin, se defina el componente ListView con el id
@+id/android:list.
Opcionalmente, la pantalla de la aplicacin puede contener otro objeto que se mostrar
cuando la lista de seleccin est vaca. Este componente que se muestra cuando la lista est
vaca debe tener el id android:id/empty.
El cdigo siguiente muestra un diseo personalizado poco agraciado de la pantalla.
Tiene una lista con un fondo verde, rojo y un escueto mensaje "sin datos".
Fjate en el cdigo de ejemplo que define este componente en el fichero main.xml de
layout de la aplicacin:
Ejemplo
<ListView
android:id="@+id/android:list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
125
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0000"
android:text="No hay datos"/>
Para cambiar el diseo de las opciones del ListView interno de la actividad ListActivity
hay que definir un nuevo fichero XML de diseo dentro de la carpeta res\layout. Por ejemplo,
el fichero se puede llamar fila.xml y contener el siguiente cdigo:
<TextView android:id="@+id/texto"
android:textSize="16sp"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
El cdigo anterior crea un diseo de una etiqueta en negrita para definir cada opcin
del listado.
Para acabar, vamos a cargar datos en el objeto ListView de la actividad ListActivity
usando un Adaptador de tipo matriz en el fichero Java correspondiente de la aplicacin:
126
2.5
COMPONENTES PERSONALIZADOS
127
EditText (cuadro de texto) para que muestre el nmero de caracteres que contiene a medida
que se escribe en l.
Se trata de simular un editor de mensajes cortos SMS del propio sistema operativo que
nos avisa del nmero de caracteres que contiene el mensaje. En nuestro caso, como resultado
obtendremos un componente como el que se muestra en la siguiente imagen:
128
pinceles();
}
public EditTextExtendido(Context context) {
super(context);
pinceles();
}
// Funcin que inicia las pinceles que usamos para pintar el cuadradito negro
private void pinceles()
{
pNegro = new Paint(Paint.ANTI_ALIAS_FLAG);
pNegro.setColor(Color.BLACK);
pNegro.setStyle(Style.FILL);
pBlanco = new Paint(Paint.ANTI_ALIAS_FLAG);
pBlanco.setColor(Color.WHITE);
}
// Para modificar el aspecto del EditText hay que reescribir este mtodo
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
que es el lienzo sobre el que podemos dibujar todos los elementos extra necesarios en el
componente.
La clase Canvas proporciona varios mtodos para dibujar lneas, rectngulos, elipses,
texto, imgenes, etctera, sobre el espacio ocupado por el componente. En este caso
nicamente vamos a dibujar un rectngulo que sirve de fondo para el contador y el texto con
el nmero de caracteres actual que ha escrito el usuario.
Para dibujar el grfico es necesario definir dos pinceles (clase Paint). El primero
permite pintar de color negro y con relleno slido, y el segundo pinta de color blanco. Como
slo es necesario crear estos pinceles una vez, los hemos definido como atributos de la clase
y los inicializamos en los tres constructores del componente.
Finalmente, dibujamos el fondo y el texto del contador mediante los mtodos
drawRect() y drawText()del objeto Canvas usando posiciones relativas al espacio ocupado
por el componente.
Para aadir el nuevo componente a la interfaz de nuestra aplicacin hay que incluirlo en
fichero res\layout\main.xml que define el diseo de la ventana como cualquier otro
componente, teniendo en cuenta que debemos hacer referencia a l con el nombre completo
de la nueva clase creada: es.mentor.unidad2.eje5.edittextext.EditTextExtendido. El fichero
tiene este aspecto:
<es.mentor.unidad2.eje5.edittextext.EditTextExtendido
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dip"
android:layout_weight="0.25"/>
130
un
nuevo
layout
XML
en
la
carpeta
\res\layout
con
el
nombre
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" android:padding="10dip">
</LinearLayout>
131
132
//
como
interfaz
del
133
listener.onLogin(textoUsuario.getText().toString(),
textoPassword.getText().toString());
}
});
}
134
el
usuario
la
contrasea no son
correctos.");
}
});
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sgo="http://schemas.android.com/apk/res/es.mentor.unidad2.eje6.logincomp
uesto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip" >
<es.mentor.unidad2.eje6.logincompuesto.ComponenteLogin
android:id="@+id/ComponenteLogin"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#0000AA"
135
sgo:texto_boton="Entrar" />
</LinearLayout>
<resources>
<declare-styleable name="ComponenteLogin">
<attr name="boton_text" format="string"/>
</declare-styleable>
</resources>
136
137
138
139
140
Unidad de Aprendizaje 9
FECTOS
DE TRANSICIN
EMS
INFORMACIN
SOBRE
Y
ANANDROID
IMACIN
NDICE
3.1
3.2
3.3
3.4
3.5
3.1
INTRODUCCIN
3.1.1
Introduccin
En esta Unidad vamos a explicar cmo funciona la tecla Retroceso de los
3.1.2
programador desarrolla una actividad para que el usuario realice un tipo especfico de accin.
Adems, una actividad puede arrancar otras actividades. Por ejemplo, una aplicacin de
correo electrnico puede tener una Actividad que muestre una lista con los mensajes nuevos.
As, cuando el usuario seleccione un correo electrnico, se puede abrir una nueva actividad
para mostrar su contenido.
Una
Actividad
tambin
puede
arrancar
las
actividades
que
definen
otras
aplicaciones. Por ejemplo, si una aplicacin tiene que enviar un correo electrnico, puede usar
el objeto Intencin (en ingls, Intent) de Android para realizar el envo incluyendo alguna
informacin, como la direccin de correo electrnico del destinatario y un mensaje.
En la Unidad 5 veremos cmo se usan estas Intenciones ("Intents").
Para que se pueda hacer esto, hay que declarar la Actividad que enva mensajes para
que admita este tipo de intenciones. En este caso, la intencin es enviar un correo
electrnico, por lo que la aplicacin disponible para crear correos electrnicos se inicia (si
hubiera varias Actividades que tuvieran la misma intencin, el sistema permite al usuario
seleccionar la que desea utilizar). Finalmente, cuando se enva el mensaje, la actividad inicial
se reanuda y parece que la Actividad de correo electrnico forma parte de la aplicacin
general. A pesar de que las actividades pueden pertenecer a diferentes aplicaciones, Android
mantiene la sensacin de que se trata de una nica aplicacin juntndolas en una sola Tarea
(Task).
Una Tarea es un conjunto de actividades con las que un usuario interacta. Android
organiza las actividades en una pila de ejecucin (en ingls stack) donde se van apilando las
actividades que el usuario va invocando. Cada Tarea tiene asociada su propia pila de
ejecucin independiente.
La ventana siguiente muestra la pantalla principal del dispositivo (HOME):
143
Cuando el usuario toca un icono de esta pantalla, se inicia una tarea asociada a la
aplicacin. Si es la primera vez que arrancamos la aplicacin, el sistema operativo crea una
nueva tarea y su Actividad principal ("main") queda almacenada en primer lugar en la pila de
Android.
Cuando esta Actividad principal arranca otra, la nueva Actividad se aade a la parte
superior de la pila y pasa a primer plano. La Actividad anterior permanece en la pila y se
detiene manteniendo el estado actual de la interfaz de usuario. Si el usuario pulsa la tecla de
retroceso
144
Nota: es posible mantener muchas tareas en segundo plano a la vez; sin embargo, si el
sistema operativo necesita memoria, puede destruirlas perdiendo sus estados de ejecucin.
3.1.3
<activity android:name=".BienvenidoActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
145
146
Por esta razn, es muy importante marcar la actividad principal con la categora
"android.intent.category.LAUNCHER", para que el usuario pueda volver a una aplicacin
que se encuentre en segundo plano y que ya no es visible.
3.2
el
mtodo
OnDestroy()
inmediatamente
seguido
por
onCreate().
Este
147
148
super.onCreate(estadoAlmacenado);
Muy importante: debido a que Android no garantiza que siempre se invoque el mtodo
onSaveInstanceState(), debe usarse nicamente para almacenar el estado transitorio de la
Actividad, es decir, la interfaz de usuario. Nunca debe emplearse para almacenar datos
persistentes con preferencias del usuario o datos de la aplicacin. En la Unidad 4 veremos
cmo se implementa esta funcionalidad.
149
150
En el cdigo anterior hemos usado los mtodos putString() y getString() del objeto
Bundle para almacenar el contenido de una variable extra en el estado de la Actividad.
151
Desde Eclipse puedes abrir el proyecto Ejemplo 1 (Guardar estado de una actividad) de la
Unidad 3. Estudia el cdigo fuente y ejectalo para mostrar en el emulador una aplicacin en
la que guardamos el estado de ejecucin de la Actividad
A continuacin, introduce algn texto en los campos que aparecen. Despus, haz clic
en el botn "INICIO"
Si volvemos a ejecutar la aplicacin, veremos que podemos ver tanto los datos tanto
de la caja de texto usuario como de la contrasea. Esto ocurre porque Android no ha
destruido la Actividad.
152
Para acceder a
estas herramientas hay que hacer clic en el icono "Dev Tools" que aparece en el lanzador de
aplicaciones. Despus, hacemos clic en la opcin "Development Settings" y, finalmente,
marcamos la opcin "Immediately destroy activities":
Si ahora ejecutas de nuevo la aplicacin y pulsas otra vez el botn "INICIO", vers el
mensaje "El sistema ha terminado la Actividad", que indica que la aplicacin se destruye:
153
3.3
varias tareas a la vez (concurrentemente). Esencialmente, un hilo es una tarea que se ejecuta
en paralelo con otra tarea. Todos los hilos que se ejecutan a la vez pueden compartir una
serie de recursos, tales como la memoria, los archivos abiertos, etctera. Esta tcnica permite
simplificar el diseo de una aplicacin que puede as llevar a cabo distintas funciones
simultneamente.
Cuando un usuario ejecuta una aplicacin en Android se inicia un nuevo proceso de
Linux con un nico hilo de ejecucin. Por defecto, todos los componentes de una misma
aplicacin se ejecutan en el mismo hilo principal (en ingls se denomina "main thread"). A
este hilo tambin se lo denomina hilo de la interfaz de usuario (en ingls, "UI thread").
Si se inicia una Actividad de una aplicacin que ya se est ejecutando y, por lo tanto,
ya existe un proceso asociado, entonces la nueva Actividad se inicia dentro de ese proceso y
utiliza el mismo hilo de ejecucin. Sin embargo, es posible disear aplicaciones que ejecuten
sus diferentes componentes de la aplicacin en procesos separados y el programador puede
crear subprocesos adicionales para cualquier proceso principal.
En este apartado vamos a estudiar cmo funcionan los procesos e hilos en una
aplicacin de Android.
3.3.1
Procesos
Ya hemos comentado que, por defecto, todos los componentes de una misma
en
particular.
Para
hacer
esto,
debemos
modificar
el
archivo
154
3.3.2
aplicacin el mayor tiempo posible en memoria. Sin embargo, a veces, es necesario eliminar
procesos antiguos para liberar memoria e iniciar nuevos
procesos se deben eliminar, el sistema ordena jerrquicamente por importancia cada proceso
basndose en qu componentes se estn ejecutando dentro de l y su estado. Los procesos
de menor importancia se eliminan primero, despus los de importancia media y as
sucesivamente.
Hay cinco niveles en la jerarqua de importancia. La siguiente lista muestra los
diferentes tipos de procesos por orden de importancia (el primer proceso es ms importante y
se destruye el ltimo):
1. Proceso en primer plano (Foreground): es un proceso en el que se ejecutan
componentes que est usando el usuario en ese momento. Por lo general, slo hay
unos pocos procesos en primer plano en un momento dado. Slo se eliminan
como ltimo recurso, cuando la memoria del telfono es tan baja que no puede
continuar con la aplicacin actual y la pantalla deja de hacer caso al usuario.
2. Proceso visible: es un proceso que no tiene ningn componente en primer plano,
pero puede afectar a lo que el usuario ve en la pantalla. Esto puede ocurrir, por
ejemplo, si la actividad en primer plano abre una ventana de dilogo que permite
ver a la la actividad anterior detrs de ella.
155
notar
156
denomina principal (main). Este hilo es muy importante porque es el encargado de gestionar
los eventos que dispara el usuario a los componentes adecuados e incluye tambin los
eventos que dibujan la pantalla. Por esta razn, a este hilo principal tambin se le llama hilo de
la interfaz de usuario (UI thread).
Este modelo de ejecucin de las aplicaciones se denomina Modelo de ejecucin
de un nico hilo (en ingls, Single Thread Model).
Android no crea un subproceso independiente para cada componente de la aplicacin.
Todos sus componentes se ejecutan dentro del mismo proceso en el hilo principal. Por lo
tanto, los mtodos que responden a eventos del sistema, como onKeyDown(), siempre se
ejecutan en este hilo principal o de la interfaz de usuario. Por ejemplo, cuando el usuario toca
con el dedo un botn de la pantalla del telfono, el hilo principal invoca el evento
correspondiente en el widget apropiado y lo redibuja.
Si un usuario interacciona mucho con una aplicacin, este modelo de ejecucin con un
nico hilo puede dar lugar a poca fluidez en ella a menos que implementemos adecuadamente
la aplicacin. Es decir, como todo lo que ejecuta la aplicacin se hace en un nico hilo
principal, llevar a cabo operaciones que van a tardar cierto tiempo, como acceder a Internet o
consultar una base de datos, bloquearn la interfaz de usuario. Cuando el hilo principal est
bloqueado la pantalla de aplicacin se bloquea (ni siquiera se dibuja) y, desde el punto de vista
del usuario, la aplicacin se bloquea. Adems, si el hilo principal est bloqueado durante 5
segundos, Android muestra al usuario una ventana con el mensaje "La aplicacin no
responde" (en ingls, ANR: Application Not Responding):
datos a los que accede dicha funcin (o mtodo) sean corrompidos por alguno de los hilos ya
que se asegura la atomicidad de la operacin, es decir, la funcin se ejecuta de forma
serializada sin interrupciones
Es decir, en Android se puede manipular la interfaz de usuario desde otro subproceso
Por lo tanto, hay tener en cuenta dos reglas a la hora de disear aplicaciones en Android:
1. No bloquear nunca el hilo principal o de la interfaz de usuario.
2. No acceder a la interfaz de usuario de Android desde un hilo exterior.
3.4
158
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
ejemplo,
para
arreglar
el
ejemplo
anterior
podemos
usar
el
mtodo
View.post(Runnable):
3.4.1
Lleva a cabo las operaciones que bloquean la pantalla al usuario en un proceso de segundo
plano y devuelve su resultado al hilo principal de la interfaz de usuario de manera sencilla.
Para usar esta funcionalidad de Android hay que extender la clase AsyncTask e
implementar los siguientes mtodos callback:
159
}
// Clase que descarga una imagen de Internet como una tarea asncrona.
// Es decir, podemos seguir usando la interfaz de usuario.
private class TareaDescargaImagen extends AsyncTask<String, Void, Bitmap> {
imagen.setImageBitmap(resultado);
else imagen.setImageResource(R.drawable.error);
imagen.setVisibility(View.VISIBLE);
} // end onPostExecute
}
El primer parmetro (String) define el tipo de variable que usamos como parmetro al
invocar doInBackground(). El segundo parmetro (Void) define el tipo de variable que
pasamos como parmetro al invocar onProgressUpdate(). Finalmente, el ltimo parmetro
(Bitmap) define el tipo de variable que pasamos como parmetro al invocar onPostExecute()
160
Es recomendable que el alumno o alumna lea el manual de la clase AsyncTask para conocer
ms funcionalidad, entre ella se encuentra:
Para entender mejor esta aplicacin que usa un proceso en segundo plano, inicia este
ejemplo en el emulador. Vers la pantalla siguiente:
161
3.5
MENS DE ANDROID
Mens Principales: son los usados con ms frecuencia. Aparecen en la zona inferior
de la pantalla al pulsar el botn Men
del telfono.
Submens: son los mens secundarios que aparecen al elegir una opcin de un men
principal.
Mens Contextuales: son muy tiles y se muestran al realizar una pulsacin larga
sobre algn elemento de la pantalla. Es el equivalente al botn derecho del ratn en un
PC.
Como es habitual en Android, existen dos formas de crear un men en una aplicacin
3.5.1
diseo en XML. Estos ficheros XML con el diseo del men se deben guardar en la carpeta
res\menu del proyecto y tienen una estructura de este tipo (archivo menu_principal.xml):
162
Podemos ver en el cdigo anterior que la estructura bsica del diseo del men es
muy sencilla. Aparece un elemento principal <menu> que contiene los elementos <item> que
corresponden con las diferentes opciones del men.
Estos elementos <item> tienen a su vez varias propiedades bsicas, como su ID
(atributo android:id), su texto (atributo android:title) y su icono (atributo android:icon). Los
iconos utilizados deben guardarse en las carpetas res\drawable-... del proyecto.
Adems, hemos definido un submen (men secundario) que se muestra al pulsar la
opcin 3 del un men principal. Los submens en Android se muestran en una lista emergente
cuyo ttulo contiene el texto de la opcin elegida del men principal. Este submen tiene dos
nuevas opciones secundarias. Para ello, hemos aadido un nuevo elemento <menu> dentro
del <item> correspondiente a la opcin 3.
De igual forma que otros archivos XML de un proyecto Android, podemos editarlo
visualmente haciendo clic en la pestaa Layout del archivo que define el men:
163
Una vez definido el men en el fichero XML, hay que implementar el mtodo
onCreateOptionsMenu() de la Actividad para que se cree en la pantalla. En este mtodo
debemos inflar el men de forma parecida a como ya hemos hecho con otro tipo de
componentes layouts. Primero obtenemos una referencia al objeto "inflador" mediante el
mtodo getMenuInflater() y, despus, generamos la estructura del men usando el mtodo
inflate() y pasndole como parmetro el ID del archivo XML de diseo del men. Finalmente,
el mtodo debe devolver el valor true para indicar a la Actividad que debe mostrar el men.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
164
del recurso.
Veamos cmo queda el cdigo utilizando esta otra forma de implementarlo que genera
un men exactamente igual al del ejemplo anterior:
165
// Si el usuario selecciona
// seleccionada en la etiqueta
una
opcin
del
men
mostramos
la
opcin
Desde Eclipse puedes abrir el proyecto Ejemplo 4 (Mens) de la Unidad 3. Estudia el cdigo
fuente y ejectalo para mostrar en el emulador una aplicacin en la que usamos un men
principal y un submen,
166
Para ver cmo funciona esta aplicacin que usa un men y un submen inicia este ejemplo en
el emulador. Vers la pantalla siguiente:
3.5.2
167
labelResultado = (TextView)findViewById(R.id.labelResultado);
listadoPrincipal = (ListView)findViewById(R.id.ListadoPrincipal);
registerForContextMenu(labelResultado);
registerForContextMenu(listadoPrincipal);
}// end onCreate
A continuacin, de igual forma que hicimos con los mens bsicos para crear las
opciones disponibles con el mtodo onCreateOptionsMenu(), vamos a construir los mens
contextuales asociados a los diferentes componentes de la aplicacin con el mtodo
onCreateContextMenu(). A diferencia del mtodo onCreateOptionsMenu() Android invoca
este mtodo cada vez que es necesario mostrar un men contextual. Este mtodo lo
implementaremos de misma forma que los mens bsicos, inflndolo con un archivo de
diseo XML o crendolo con sentencias Java. En este ejemplo hemos decidido disear los
mens en XML. El men contextual que aparece en la etiqueta se define en el fichero
menu_context_etiqueta.xml:
168
169
En el caso del men contextual para el listado hemos personalizado el ttulo del men
contextual mediante el mtodo setHeaderTitle(), para que muestre el texto del elemento
seleccionado en el listado.
Para hacer esto es necesario conocer la posicin del elemento seleccionado en el
listado mediante el ltimo parmetro menuInfo. Este parmetro contiene informacin adicional
del componente sobre el que el usuario ha pulsado para mostrar el men contextual. En este
caso en particular del componente ListView contiene la posicin del elemento pulsado. Para
obtenerlo, hacemos un cambio de formato (typecasting) del parmetro menuInfo a un objeto
del tipo AdapterContextMenuInfo y accedemos a su propiedad position.
Por ltimo, para implementar las acciones que hay que ejecutar cuando el usuario
selecciona una opcin determinada del men contextual vamos a implementar el mtodo
onContextItemSelected() de manera similar a cmo hacamos con onOptionsItemSelected()
para los mens bsicos:
switch (item.getItemId()) {
// Se selecciona la opcin 1 de men contextual de la etiqueta
case R.id.ContextLabelOp1:
labelResultado.setText("Etiqueta: Opcin 1");
return true;
170
Fjate en el cdigo anterior que se puede mantener pulsado el dedo sobre la etiqueta
azul o sobre una opcin del listado y seleccionar una de las opciones del men contextual.
utilizado
la
informacin
del objeto
171
para
modificar
la
opcin
del
listado
hemos
usado
el
mtodo
notifyDataSetChanged() del adaptador para que se recarguen los elementos del listado una
vez hemos modificado el texto de uno de ellos.
Para ver cmo funciona esta aplicacin que usa un men contextual inicia este
ejemplo en el emulador. Vers la pantalla siguiente:
3.5.3
173
3.5.3.1
Es una ventana de dilogo que obliga a que el usuario vea un mensaje bloqueando la
pantalla hasta que pulse la tecla volver
Si hacemos clic sobre el primer botn del ejemplo del curso, veremos que aparece el
siguiente mensaje:
3.5.3.2
174
"Has
pulsado
el
botn
'S'",
1).show();
}
});
ventana.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int boton) {
/* Sentencias si el usuario pulsa No */
Toast.makeText(getApplicationContext(), "Has pulsado el botn
'No'",1).show();
}
});
ventana.setNeutralButton("A veces", new
DialogInterface.OnClickListener() {
"Has
pulsado
el
botn
'A
veces'", 1).show();
}
175
});
ventana.show();
3.5.3.3
176
3.5.3.4
177
LayoutInflaterli
=(LayoutInflater)getApplicationContext().getSystemService(infService);
// Inflamos el componente compuesto definido en el XML
View inflador = li.inflate(R.layout.dialogo_entrada_texto, null);
// Buscamos los componentes dentro del Dilogo
final TextView nombreEdit = (TextView)
inflador.findViewById(R.id.nombre_edit);
final TextView passwordEdit = (TextView)
inflador.findViewById(R.id.password_edit);
ventana = new AlertDialog.Builder(this);
ventana.setTitle("Indica usuario y contrasea");
// Asignamos
previamente)
el
contenido
dentro
del
dilogo
(el
que
hemos
inflado
ventana.setView(inflador);
// No se puede incluir un mensaje dentro de este tipo de dilogo!!!
ventana.setPositiveButton("Aceptar", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int boton) {
Toast.makeText(getApplicationContext(), "Has escrito el nombre '"+
nombreEdit.getText().toString() +"', la contrasea '"+
passwordEdit.getText().toString() +"' y has pulsado el
botn 'Aceptar'", 1).show();
}
});
ventana.setNegativeButton("Cancelar", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int boton) {
Toast.makeText(getApplicationContext(), "Has pulsado el botn
'Cancelar'", 1).show();
}
});
ventana.show();
En el Ejemplo 5 de esta Unidad puedes ver otros tipos de ventanas de dilogo muy
178
179
hay
garantas
de
que
Android
invoque
siempre
el
mtodo
180
Si una aplicacin Android tiene que realizar operaciones que no son instantneas y
llevan cierto tiempo, hay que ejecutarlas en hilos separados en segundo plano.
Un Men es una serie de opciones que el usuario puede elegir para realizar una
determinada tarea.
En las aplicaciones Android podemos utilizar tres tipos de mens diferentes:
1. Mens Principales: aparecen en la zona inferior de la pantalla al pulsar el
botn Men del telfono.
2. Submens: mens secundarios que aparecen al elegir una opcin de un
men principal.
3. Mens Contextuales: se muestran al realizar una pulsacin larga sobre
algn elemento de la pantalla. Es el equivalente al botn derecho del ratn
en un PC.
Como es habitual en Android, existen dos formas de crear un men en una
aplicacin Android: mediante un fichero XML e "inflndolo" despus o creando el
men directamente mediante cdigo Java.
Las ventanas de dilogo son pequeas ventanas que el programador utiliza a
menudo para que el usuario tome una decisin o reciba un mensaje informativo.
181
Unidad de Aprendizaje 9
EFECTOS
TRABAJANDO
DE TRANSICIN
CON
Y
FICHEROS
ANIMACIN
NDICE
4.1 FICHEROS EN ANDROID .......................................................... 185
4.1.1 Introduccin ..................................................................... 185
4.1.2 Gestin de informacin en Android ................................. 185
4.1.3 Gestin del sistema de archivos en Android ................... 185
4.1.4 Clase Fichero File ............................................................. 186
4.1.4.1 Constructores ms importantes .............................. 186
4.1.4.2 Mtodos ms importantes....................................... 187
4.1.5 Ficheros en la memoria interna del diapositivo ............... 188
4.1.6 Fichero de recurso de la aplicacin ................................. 190
4.1.7 Fichero en almacenamiento externo................................ 191
4.1.8 Aadir datos a un fichero ................................................. 196
4.1.9 Gestionando las excepciones en la gestin de ficheros . 196
4.2 PREFERENCIAS DE UNA APLICACIN ANDROID ................. 197
4.2.1 Preferencia de las aplicaciones Android.......................... 197
4.2.2 Pantallas de opciones ...................................................... 200
4.3 RECURSOS DE LAS APLICACIONES ANDROID ..................... 207
4.3.1 Tipos de recursos............................................................. 208
4.3.2 Crear literales en ficheros de recursos con Eclipse......... 208
4.3.3 Recursos de tipo Cadena (String Resources) .................. 209
4.3.4.1 Cadena (String) ....................................................... 210
4.3.4.2 Matriz de cadenas (String Array)............................. 211
4.3.4.3 Cadenas de cantidad (Quantity Strings) ................. 212
4.3.4 Formatear y cambiar el estilo de las cadenas de recursos213
4.3.4.1 Escapando comillas simples y dobles.................... 213
4.3.4.2 Formatear cadenas de texto................................... 214
4.3.4.3 Cambio de estilo ..................................................... 214
4.4 ACCESO A INTERNET CON ANDROID ..................................... 215
4.4.1 Ejemplo de conexin a Internet........................................ 216
4.4.2 Conexin a travs de proxy ............................................. 220
4.5 QU SON JSON (JavaScript Object Notation? ........................ 221
4.5.1 Cmo usar JSON en nuestras aplicaciones a Android.... 222
4.5.2 Cmo escribir ficheros en formato JSON ........................ 225
4.1
4.1.1
FICHEROS EN ANDROID
Introduccin
En esta Unidad vamos a explicar cmo gestionar ficheros en Android, tanto en la
4.1.2
aplicaciones:
Preferencias de la aplicacin
En esta Unidad 4 trataremos las dos primeras formas, y en la Unidad 6 veremos las
bases de datos.
4.1.3
185
En Android, por defecto, los ficheros son privados y nicamente puede acceder a ellos
la aplicacin que los crea. Para compartir informacin de estos ficheros se utilizan los Content
Providers que veremos en la Unidad 7.
Lo primero que hay debemos tener en cuenta es dnde queremos almacenar estos
ficheros y la manera en que vamos a acceder a ellos: lectura o escritura.
Podemos leer y escribir ficheros localizados en:
1. La memoria interna del dispositivo: como fichero o como recurso de la
aplicacin.
2. La tarjeta SD externa, si existe, tambin denominada almacenamiento
externo.
4.1.4
sistema operativo. Un archivo en Android puede estar identificado por su ruta absoluta,
relativa al directorio raz del sistema de archivos, o por su ruta relativa, que es directorio actual
en el que se ejecuta la aplicacin. Esta clase File est basada en la clase de Java.
El acceso a los ficheros es similar al Java estndar: se deben crear inputs y outpus
streams.
La clase File puede hacer referencia a un archivo que ya exista o a uno que vayamos a
crear. Aunque el nombre de esta clase sea File, tambin puede, referirse a un directorio o un
enlace (link) de Linux.
Esta clase proporciona una funcionalidad limitada para obtener y establecer permisos
del archivo, cambiar el tipo de archivo o establecer su fecha de ltima modificacin.
4.1.4.1
Constructores ms importantes
File(File dir, String nombre): crea un fichero usando el nombre y el
directorio especificados como parmetros.
186
4.1.4.2
Mtodos ms importantes
String[] list(): devuelve un listado con los nombres de todos los ficheros y
subdirectorios contenidos en un directorio.
File[] listFiles(): devuelve un listado de tipo File con todos los ficheros y
subdirectorios contenidos en un directorio.
187
4.1.5
boolean setLastModified(long
modificacin del fichero.
time):
establece
la
ltima
fecha
de
de espacio que tienen muchos dispositivos, por lo que no deberamos abusar de este espacio
guardando ficheros de gran tamao.
Crear ficheros en la memoria interna es muy sencillo. Android dispone del mtodo
openFileOutput(), que recibe como parmetros el nombre del fichero y el modo de acceso al
mismo. Este modo de acceso puede ser:
o
188
OutputStreamWriter fileout=
new OutputStreamWriter(openFileOutput("fichero_interno.txt",
Context.MODE_PRIVATE));
fileout.write("En un lugar de la Mancha...");
fileout.close();
}
catch (Exception excepcion)
{
Log.e("Fichero", "Error al escribir fichero en memoria interna");
}
189
4.1.6
como un recurso de la propia aplicacin. Aunque este mtodo es muy til, nicamente
debemos utilizarlo cuando no necesitemos realizar modificaciones sobre el fichero, ya que el
acceso al mismo es de slo lectura.
Para incluir un fichero como recurso de la aplicacin debemos colocarlo en la carpeta
/res/raw del proyecto Android. Esta carpeta no suele estar creada por defecto, por lo que
debemos crearla manualmente en Eclipse.
Una vez creada la carpeta raw, podemos aadir en ella cualquier fichero que
necesitemos incluir con la aplicacin en tiempo de compilacin en forma de recurso. En el
Ejemplo 1 de esta Unidad hemos incluido el fichero de texto prueba_raw.txt.
Posteriormente, en tiempo de ejecucin, podemos acceder a este fichero, slo en modo de
lectura, de una forma similar a la que ya hemos visto anteriormente para el resto de ficheros en
la memoria interna del dispositivo.
Estos ficheros de tipo recurso tambin pueden ser binarios: por ejemplo, imgenes,
vdeos, etctera.
En primer lugar, para acceder a este fichero, obtenemos los recursos de la aplicacin
con
190
el
mtodo
getResources()
sobre
ste
utilizamos
el
mtodo
4.1.7
191
Otros valores que indicarn que existe algn tipo de problema y que, por lo tanto, no
podemos usar la memoria externa (MEDIA_UNMOUNTED, MEDIA_REMOVED, etctera).
Se puede consultar todos estos valores en la documentacin oficial de la clase
Environment.
Teniendo en cuenta esto, en el Ejemplo 1 realizamos comprobaciones previas del
} else
} else {
}
if (hayAlmacenamientoExt) {
192
telfono
no
tiene
ningn
almacenamiento
externo conectado.");
}
} // end compruebaTarjetaSD
193
else
resultado.append("No
hay
194
</application>
195
}
catch (Exception ex)
{
Log.e("Ficheros", "Error al leer fichero de memoria externa");
}
4.1.8
4.1.9
bloque try-catch. De esta manera se controlan los errores de ejecucin de las sentencias
mediante el manejo de excepciones estndar de Java.
Por ejemplo, Android puede lanzar las siguientes excepciones cuando ocurre un error
al manipular un fichero:
1. Si el fichero indicado en el parmetro del constructor FileOutputStream(File)
no existe, se lanza la excepcin FileNotFoundException.
196
try {
//
Sentencias
excepciones
que
queremos
ejecutar
que
pueden
lanzar
.
.
} catch (ExceptionType excepcion1) {
// Sentencias que gestiona la excepcin 1
.
.
} catch (ExceptionType excepcion2) {
// Sentencias que gestiona la excepcin 2
.
.
}
En el caso del Ejemplo 1 del curso hemos capturamos todas las excepciones en un
nico bloque para mostrar al usuario y en la consola de Eclipse un mensaje sencillo de error:
4.2
4.2.1
recupera para personalizar la experiencia del usuario. Por ejemplo, se debe almacenar
informacin personal, configuracin de la aplicacin, opciones de presentacin, etctera.
En el apartado anterior hemos visto cmo almacenar informacin en ficheros. Las
preferencias de una aplicacin se podran almacenar utilizando este mtodo, aunque Android
proporciona otro mtodo alternativo diseado especficamente para administrar este tipo de
datos: las Preferencias compartidas (shared preferences en ingls).
197
ejemplo,
para
obtener
la
referencia
la
coleccin
de
preferencias
SharedPreferences preferencias =
getSharedPreferences("MisPreferencias",Context.MODE_PRIVATE);
Una vez hemos creado el objeto que nos permite acceder a la coleccin de
preferencias, podemos leer, insertar o modificar claves de preferencias utilizando los mtodos
get() o put() correspondientes al tipo de dato de cada preferencia. Por ejemplo, para obtener
el valor de la preferencia email de tipo String escribimos la siguiente setencia:
SharedPreferences preferencias =
getSharedPreferences("MisPreferencias", Context.MODE_PRIVATE);
199
En este fichero XML observamos cmo se almacenan las dos preferencias del ejemplo
anterior con sus claves y valores correspondientes.
4.2.2
Pantallas de opciones
Si abrimos cualquier pantalla de preferencias estndar de Android, veremos que todas
Si nos fijamos en la imagen anterior, vemos que las distintas opciones se organizan
dentro de una pantalla de opciones que incluye varias categoras (General, Llamadas
entrantes, etctera).
Dentro de cada categora, aparecen varios tipos de opciones. Por ejemplo, de tipo
CheckBox (Modo Silencio) o de tipo lista de seleccin (Vibrar).
Android permite mejorar y simplificar la gestin de las preferencias de una aplicacin
mediante el uso de una pantalla de opciones.
Para definir la pantalla de opciones vamos a usar un fichero de diseo (layout) XML,
que guardamos en la carpeta /res/xml/pantallapreferencias.xml del proyecto.
El contenedor principal de nuestra pantalla de preferencias ser el elemento
<PreferenceScreen> que aparece en el fichero opciones.xml. Este elemento representa la
pantalla de opciones en s, dentro de la cual incluiremos el resto de componentes de la interfaz
de usuario.
Dentro de esta pantalla podemos incluir una lista de opciones organizadas por
categoras, que se representan mediante el elemento <PreferenceCategory>, al que
200
CheckBoxPreference
Se usa para introducir una opcin de preferencia que slo puede tener dos valores:
activada (marcada) o desactivada (desmarcada). Es el equivalente al componente de tipo
CheckBox. En este caso, hay que especificar los atributos: nombre interno de la opcin
(android:key),
texto
que
muestra
(android:title)
descripcin
de
la
opcin
<CheckBoxPreference android:key="opcion1"
android:title="Bsqueda automtica"
android:summary="Iniciar bsqueda automtica en Internet" />
EditTextPreference
Se utiliza para introducir una opcin de preferencia que contiene una cadena de texto.
Al pulsar sobre una opcin de este tipo, se muestra un cuadro de dilogo sencillo que solicita
al usuario un texto. Para este tipo de opcin, adems de los tres atributos comunes a la
opcin anterior, tambin hay que indicar el texto que aparece en el cuadro de dilogo
mediante el atributo android:dialogTitle. Por ejemplo:
<EditTextPreference android:key="opcion2"
android:title="Texto de la bsqueda"
android:summary="Indica el texto por defecto de la bsqueda"
android:dialogTitle="Introduce un texto" />
ListPreference
Se emplea para que el usuario seleccione una nica opcin de preferencia de una lista
de valores predefinida. Adems de los cuatro atributos anteriormente comentados, hay que
201
aadir dos ms: uno para indicar la lista de valores que se visualizan en la lista, y otro para
sealar los valores internos que guardaremos para cada uno de los valores de la lista anterior.
Por ejemplo, al usuario podemos mostrarle una lista de buscadores con el texto Google y
Bing, pero internamente almacenarlos como www.google.es y www.bing.com.
Esta lista de valores la definimos en el fichero XML /res/xml/opciones.xml con los
tipos de recursos <string-array> necesarios. En este caso son dos: uno para la lista de
valores visibles y otro para la lista de valores internos que se guardan en el fichero de
preferencias. Este fichero tiene este aspecto:
En
la
opcin
de
preferencia
utilizamos
los
atributos
android:entries
<ListPreference
android:key="opcion3"
android:title="Buscadores"
android:summary="Indica el buscador por defecto"
android:dialogTitle="Selecciona buscador"
android:entries="@array/nombre"
android:entryValues="@array/url" />
202
MultiSelectListPreference
Se emplea para que el usuario seleccione una o varias opciones de preferencia de una
lista de valores predefinida. Los atributos que debemos establecer son, por lo tanto, los
mismos que para el tipo ListPreference. Vemos un ejemplo a continuacin:
<MultiSelectListPreference
android:key="opcion4"
android:title="Varios buscadores"
android:summary="Indica varios buscadores"
android:dialogTitle="Selecciona buscadores"
android:entries="@array/nombre"
android:entryValues="@array/url" />
203
Una vez est definida la estructura de la pantalla de opciones, hay que implementar
una nueva Actividad que la llamaremos cuando queramos mostrar la pantalla de preferencias,
y que se encargar internamente de gestionar todas las opciones, guardarlas, modificarlas,
etctera, a partir de la definicin XML.
Android facilita el trabajo al programador ofreciendo la clase PreferenceActivity, que
se encarga de gestionar todas las operaciones internamente. nicamente hay que crear la
nueva Actividad PantallaPreferencias que se extiende de esta clase e implementar su
mtodo onCreate() para invocar el mtodo addPreferencesFromResource() indicando el
fichero XML en el que hemos definido la pantalla de opciones. El cdigo fuente se encuentra
en el fichero PantallaPreferencias.java:
204
<activity android:name=".PantallaPreferencias"
android:label="@string/app_name">
</activity>
Para acabar la aplicacin, hay que aadir algn mecanismo que nos permita mostrar la
pantalla de preferencias. Esta opcin suele estar en un men, pero para simplificar, en el
Ejemplo 2 vamos a incluir el botn preferenciasBtn en la interfaz del usuario, para mostrar la
ventana de preferencias.
Al pulsar este botn se muestra la ventana de preferencias mediante el mtodo
startActivity() al que pasamos como parmetros el contexto de la aplicacin y la clase de la
ventana de preferencias (PantallaPreferencias.class).
preferenciasBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(PreferenciasActivity.this,
PantallaPreferencias.class));
}
});
205
Por ltimo, la tercera opcin de tipo lista muestra una ventana emergente con la lista
de valores posibles, donde nicamente podemos seleccionar uno:
Una vez hayamos establecidos los valores de las preferencias, podemos salir de esta
ventana de opciones pulsando el botn Atrs del dispositivo o del emulador
. La Actividad
comprobarlo
vamos
aadir
la
interfaz
de
usuario
el
botn
obtenerOpcionesBtn, que recupera el valor actual de las tres preferencias y las muestra en la
pantalla.
Para acceder a las preferencias compartidas de la aplicacin usaremos el mtodo
getDefaultSharedPreferences(). Como hemos hecho anteriormente, usamos los distintos
mtodos get() para recuperar el valor de cada opcin dependiendo de su tipo:
206
obtenerPreferenciasBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences prefe =
PreferenceManager.getDefaultSharedPreferences(PreferenciasActivity.this);
lblResultado.setText("");
Log.i("", "Opcin 1: " + prefe.getBoolean("opcion1", false));
lblResultado.append("Bsqueda automtica: " +
prefe.getBoolean("opcion1", false));
Log.i("", "Opcin 2: " + prefe.getString("opcion2", ""));
lblResultado.append("\n\nTexto por defecto: " +
prefe.getString("opcion2", ""));
Log.i("", "Opcin 3: " + pref.getString("opcion3", ""));
lblResultado.append("\n\nBuscador: " +
prefe.getString("opcion3", ""));
}
});
4.3
Los Recursos de Android son archivos almacenados en el directorio /res del proyecto.
Estos ficheros de recursos pueden ser de tipo audio, vdeo, imgenes, texto, XML,
etctera, y se pueden integrar en la aplicacin.
Por qu usar ficheros con recursos?
207
4.3.1
Tipos de recursos
4.3.2
Despus, basta con seleccionar el tipo de recursos que necesitamos dar de alta y
rellenar el nombre y el valor que debe contener:
4.3.3
Un recurso de tipo Cadena (String) permite definir cadenas de texto para usarlas en la
aplicacin Android: Incluso podemos cambiar su estilo y formato. Hay tres recursos de tipo
Cadena:
Quantity Strings (Plurals): recurso que incluye dos cadenas segn una
cantidad sea singular o plural.
209
En el Ejemplo 3 de esta Unidad puedes ver cmo se hace referencia a esta etiqueta
desde el fichero XML que define el diseo de la pantalla principal main.xml:
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/etiqueta1"
android:text="@string/etiqueta1"
android:layout_margin="1dip"/>
210
<string-array name="nombre_matriz">
<item>texto elemento 1</item>
<item>texto elemento 2</item>
...
</string-array>
<string-array name="horoscopo">
<item>Cancer</item>
<item>Capricornio</item>
<item>Aries</item>
<item>Leo</item>
<item>Libra</item>
</string-array>
211
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
;
s.setAdapter(adapter);
Para obtener los elementos de la matriz desde el cdigo fuente en Java podemos usar
la funcin getStringArray:
<plurals name="nombre_plural">
<item quantity=["zero" | "one" | "two" | "few" | "many" | "other"]>
texto del literal</item>
</plurals>
212
Valor
Descripcin
zero
one
two
few
many
other
Para hacer referencia a este recurso de cadena en el cdigo fuente Java debemos
escribir R.plurals.numeroDeContactos.
En el Ejemplo 3 de esta Unidad puedes ver cmo se usa este recurso de tipo matriz
para cambiar el literal en funcin del nmero que escribe el usuario en una caja de texto:
//Obtenemos los recursos de la aplicacin
Resources res = getResources();
int total = Integer.parseInt(s.toString());
// Cambiamos el texto de la etiqueta plurales en funcin del contador
String contactosStr = res.getQuantityString(R.plurals.numeroDeContactos,
total, total);
txtPlurales.setText(contactosStr);
4.3.4
texto debemos "escaparlas", para que Android no las interprete como parte del fichero XML y
muestre errores de sintaxis.
213
Es necesario incluir siempre las comillas simples dentro de las dobles o usar el
carcter "\" para escaparlas. Adems, no se permite incluir entidades de HTML para los
caracteres singulares como "á".
A continuacin, mostramos algunos ejemplos que funcionan y otros que no:
<string
<string
<string
<string
String.format(String,
Object...) incluyendo en sta los argumentos que sean necesarios para formar el literal. Por
ejemplo, la siguiente cadena de recurso con formato
<string name="FormatoCadena">Hola %1$s! Tienes %2$d mensajes nuevos</string>
tiene dos argumentos: %1$s, que es una cadena y %2$d, que es un nmero decimal.
En el Ejemplo 3 de esta Unidad hemos usado as esta cadena con formato para formatear un
literal:
String strFormat=getString(R.string.FormatoCadena);
String texto=String.format(strFormat, "Usuario", 4);
etiqueta3.setText(texto);
Es posible definir una cadena de recurso que contenga cambios de estilo HTML en el
texto. As, en el Ejemplo 3 de esta Unidad definimos:
<string name="RecursoEstilo">Esto es un <u>ejemplo</u> de <i>Recurso</i> con
<b>Diseo</b> </string>
214
Para completar este ejemplo hemos incluido tambin un recurso de tipo imagen en el
directorio drawable y hemos definido un color para cambiar el aspecto de una de las
etiquetas.
Importante: Al definir recursos de tipo cadena hay que tener cuidado en no escribir caracteres
que Android no sepa interpretar. Cuando esto ocurra Eclipse mostrar el siguiente mensaje de
error y no permitir compilar el proyecto:
4.4
Android incluye la biblioteca Apache de cliente HTTP (Apache HttpClient library) que
permite a las aplicaciones conectar con servidores Web de Internet.
215
Android tambin permite usar la librera estndar Red de Java Java Networking API
(paquete java.net), aunque, si usamos este paquete java.net, Android utiliza internamente la
librera de Apache.
A partir de Android 2.2 tambin se puede utilizar la clase AndroidHttpClient. Para
construir un objeto a partir de esta clase hay que usar el constructor newInstance(), que
permite especificar el nombre de navegador (agente) que usa para conectar a una pgina de
Internet. La clase AndroidHttpClient incluye el protocolo seguro SSL y mtodos GZIP para
comprimir y descomprimir los datos recibidos.
Para que una aplicacin Android acceda a Internet, es necesario declararlo en el fichero
AndroidManifest.xml, que requiere el permiso "android.permission.INTERNET".
4.4.1
@Override
protected void onPause() {
super.onPause();
// En el caso de que la aplicacin se pause, guardamos las preferencias
SharedPreferences preferences = getSharedPreferences(PREFERENCIAS,
Activity.MODE_PRIVATE);
Editor preferenceEditor = preferences.edit();
preferenceEditor.putString(URL, pagWeb.getText().toString());
// No hay que olvidar nunca hacer el commit
preferenceEditor.commit();
}
217
// Clase que descarga una pgina de Internet como una tarea asncrona.
// Es decir, podemos seguir usando la interfaz de usuario.
private class TareaDescargaPaginaWeb extends
AsyncTask<String, String, String> {
// Mtodo que se ejecuta en segundo plano
protected String doInBackground(String... urls) {
try {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(urls[0]);
HttpResponse respuesta = client.execute(request);
// Obtenemos la respuesta
BufferedReader rd = new BufferedReader(new InputStreamReader(
respuesta.getEntity().getContent()));
String linea = "";
String resultado = "";
// Mientras podamos leer una lnea de la pgina Web
while ((linea = rd.readLine()) != null) {
218
resultado+=linea;
if (resultado.length()>1024) {
publishProgress(resultado);
resultado="";
}
} // end while
}
catch (Exception e) {
System.out.println("Error al descargar la pgina.");
return "ERROR al descargar la pgina: "+e.getMessage();
}
return null;
}
/** Actualiza la etiqueta al ir descargando la pgina */
protected void onProgressUpdate(String... values) {
ResultadoLabel.append(values[0]);
}
/** Cuando la tarea ha acabado, se invoca automticamente este mtodo */
protected void onPostExecute(String resultado) {
if (resultado !=null) ResultadoLabel.append(resultado);
cargando.setVisibility(View.INVISIBLE);
} // end onPostExecute
}
219
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">
</uses-permission>
4.4.2
Proxy, es interesante configurar el emulador de Android para que acceda a Internet a travs de
ese Proxy.
Para configurarlo, haz clic en el icono "Ajustes" y establece las siguientes opciones:
Conexiones inalmbricas->Redes mviles ->APN->Telkila-> Proxy/Puerto
220
4.4
221
4.5.1
Desde Eclipse puedes abrir el proyecto Ejemplo 5 (JSON) de la Unidad 4. Estudia el cdigo
fuente y ejectalo para mostrar en el AVD el resultado del programa anterior.
Si ejecutamos la aplicacin en el emulador, veremos la siguiente pantalla:
222
Vamos a mostrar con un ejemplo prctico cmo usar una fuente de datos en formato
JSON en una aplicacin Android. Si abrimos el fichero de cdigo fuente del Ejemplo 5,
veremos las siguientes sentencias:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Definimos la matriz que vamos a usar de adaptador en la ListActivity
ArrayList<String> datosAdaptador = new ArrayList<String>();
// Leemos los datos de la cuenta de Twitter
String datosCuentaTwitter = leeCuentaTwitter();
// Leemos el contenido interno del fichero obtenido
if (datosCuentaTwitter!= null)
try {
// Usamos una matriz de JSON
JSONArray matrizJSON = new JSONArray(datosCuentaTwitter);
TextView nNoticias = (TextView) findViewById(R.id.nNoticias);
nNoticias.setText("Nmero de noticias: " + matrizJSON.length());
// Recorremos ahora todos los elementos de la matriz
for (int i = 0; i < matrizJSON.length(); i++) {
// Leemos cada objeto y lo aadimos a la matriz de datos
JSONObject jsonObjeto = matrizJSON.getJSONObject(i);
datosAdaptador.add(jsonObjeto.getString("text"));
} // end for
} catch (Exception e) {
e.printStackTrace();
}
// Indicamos el adaptador de la ListActivity
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, datosAdaptador));
}
223
224
e.printStackTrace();
}
return builder.toString();
} // end leeCuentaTwitter
NOTA: Para que una aplicacin Android acceda a Internet es necesario declararlo en el fichero
AndroidManifest.xml, que requiere el permiso "android.permission.INTERNET".
4.5.2
JSONObject o del tipo JSONArray y utilizar el mtodo toString() para transformar este objeto
en datos JSON.
Veamos un ejemplo prctico:
225
226
227
INTENTS EN ANDROID
NDICE
5.1 INTENTS EN ANDROID.......................................................... 231
5.1.1 Introduccin ...........................................................................231
5.1.2 Intenciones(Intents) ..............................................................231
5.1.3 FicherosManifest ...................................................................232
5.1.4 Declararcapacidadesdeloscomponentesdelasaplicaciones233
5.1.5 Usodeintenciones .................................................................234
5.1.6 Arranqueexplcitodeunaactividad.......................................234
5.1.7 Arranqueimplcitodeunaactividad ......................................235
5.1.7.1 Ejecutar subactividades .....................................235
5.1.8 Filtrosdeintenciones .............................................................239
5.1.9 Resolucindeintencionesimplcitas......................................240
5.1.10 Usodeintencionesparaextenderaplicaciones ....................241
5.2 USO DE INTENTS ................................................................... 243
5.2.1 UsodeIntents ........................................................................243
5.2.2 InvocacinExplcita ................................................................243
5.2.3 InvocacinImplcita................................................................249
5.2.4 RegistroAccinparaInvocacinImplcita..............................252
5.2.5 DetectarAccionesdeIntents..................................................255
5.3 PERMISOS Y SEGURIDAD EN ANDROID ........................... 256
5.3.1 ArquitecturadeseguridaddeAndroid ...................................256
5.3.2 Firmadeaplicacin.................................................................256
5.3.3 IDdeusuarioyAccesoaficheros ...........................................257
5.3.4 Permisosdeaplicaciones........................................................257
5.3.5 AutoproteccindeaplicacionesAndroid ...............................261
5.3.6 Asignarpermisosdecomponentesinternosdelaaplicacin 262
5.3.7 Cmoobtienespermisosestasaplicaciones ..........................263
5.3.8 NotassobreseguridadenAndroid .........................................264
5.4 Tab.Layout .............................................................................. 264
5.4.1 PantallasconpestaasconTabLayout ..................................264
Intents
5.1
5.1.1
INTENTS EN ANDROID
Introduccin
En esta Unidad vamos a explicar cmo usar Intenciones (Intents) en Android para
5.1.2
Intenciones (Intents)
Las Intenciones (Intents) permiten a las aplicaciones de Android expresar la intencin
de que se desea ejecutar una accin sobre unos datos usando algn componente de sta o
de otra aplicacin. Las intenciones permiten interconectar componentes de la misma o de
distintas aplicaciones mediante mensajes.
De los cuatro componentes de Android, las Actividades, los Servicios y los Receptores
de mensajes de difusin se activan con un mensaje asncrono que se denomina Intencin. Los
Proveedores de contenidos quedan excluidos.
Para crear una Intencin hay que usar el objeto Intent de Android.
Las intenciones se utilizan para arrancar componentes de dos formas:
Implcita: invocando la accin y los datos sobre los que aplicar dicha accin.
Android selecciona, en tiempo de ejecucin, la actividad receptora que cumple
mejor con la accin y los datos solicitados.
Para las Actividades y Servicios, una intencin define la accin que queremos realizar
(por ejemplo, "ver" o "enviar" algo) y puede especificar el identificador URI de los datos que
va a utilizar esa accin. Por ejemplo, una intencin podra hacer una peticin para arrancar una
actividad que muestre una imagen o abra una pgina Web.
En algunos casos, se puede iniciar una subactividad para recibir un resultado, en
cuyo caso esta subactividad devuelve el resultado en otra nueva intencin. Por ejemplo, se
puede arrancar un Intent para que el usuario elija un contacto del telfono y lo devuelta a la
Actividad principal (esta intencin de respuesta se devuelve tambin como un identificador
URI que apunta al contacto seleccionado).
231
Las Intenciones son mensajes asncronos entre componentes de aplicaciones que se usan
para realizar acciones e intercambiar datos, tanto en la peticin como en la respuesta,.
De esta manera el usuario tiene la sensacin de estar usando una nica aplicacin cuando, en
realidad, son componentes de varias.
A continuacin, vemos un esquema que muestra cmo funciona un Intent:
5.1.3
Ficheros Manifest
Para que Android pueda iniciar un componente de una aplicacin, el sistema debe
conocer que existe este componente. Ya hemos visto que, para ello, se declaran los
componentes de una aplicacin en el fichero AndroidManifest.xml. Este fichero se encuentra
en el directorio raz del proyecto Android.
232
Intents
<activity>: Actividades
<service>: Servicios
5.1.4
una aplicacin hay que utilizar una intencin para ejecutar actividades, servicios y receptores
de mensajes de difusin.
Se puede hacer de forma explcita indicando el nombre de la clase del componente
destino.
Sin embargo, el potencial de uso de las intenciones radica en el concepto de Accin
mediante las invocaciones implcitas. En una Accin el programador slo tiene que describir
el tipo de accin que desea realizar y, opcionalmente, los datos sobre los que desea realizar
esa accin. Si hay varios componentes que pueden llevar a cabo esta accin de la intencin,
entonces el usuario del dispositivo puede seleccionar cul aplicar.
233
5.1.5
Uso de intenciones
Para arrancar una Actividad sin esperar una respuesta de la subactividad iniciada,
Ambos mtodos se pueden usar tanto en las invocaciones explcitas como implcitas.
La diferencia radica en que el primero inicia la subactividad y no espera respuesta de sta; el
segundo mtodo espera recibir una respuesta de la ejecucin de la subactividad.
5.1.6
234
Intents
5.1.7
Es importante insistir en que las aplicaciones de Android deben publicar las acciones que
ofrecen.
Por ejemplo, la aplicacin dialer de marcado de llamadas de telfono de Android
ofrece la accin Intent.ACTION_DIAL que se invoca as:
if (...) {
Intent intent = new Intent(Intent.ACTION DIAL,
Uri.parse("tel:91-6666"));
startActivity(intent);
}
El cdigo anterior inicia una llamada de telfono al nmero indicado como parmetro
en la intencin. Como hemos usado el mtodo startActivity(), no trataremos la respuesta de
su ejecucin.
5.1.7.1
Ejecutar subactividades
subactividad.
Para
arrancar
una
subactividad
hay
que
usar
el
mtodo
235
236
Intents
finish():
mtodo setResult() antes que el mtodo finish(), para devolver los resultados de la
ejecucin de sta.
238
Intents
Cdigo
de
resultado:
cdigo
que
devuelve
la
subactividad,
Intencin con datos devueltos: identificador URI con la intencin con los
resultados devueltos por la subactividad. Esta segunda actividad reciben
datos de la primera a travs de la clase Bundle que pueden ser recuperados a
travs de dos formas:
o
5.1.8
indica que debe incluirse en una lista de acciones alternativas que el usuario
puede aplicar a un conjunto de datos.
Datos: permite especificar mediante atributos los tipos de datos sobre los que
puede actuar el componente. Por ejemplo, android:host, android:mimetype,
android:path, etctera.
<activity android:name=".EjemploActividad"
android:label="Ver Texto">
<intent-filter>
<action android:name="es.mentor.intent.action.VER_TEXTO">
</action>
<category android:name="android.intent.category.DEFAULT"/>
<category
android:name="android.intent.category.CATEGORY_ALTERNATIVE"
/>
<data android:mimeType="vnd.visualizador.cursor.item/*"/>
</intent-filter>
</activity>
<b
5.1.9
intencin (Accin) con el mismo nombre. Por ejemplo, el dispositivo Android puede disponer
de varios programas para navegar por Internet; si el usuario solicita abrir una pgina HTML,
entonces se le muestra un listado con las opciones posibles que completan las acciones.
Android elige la intencin implcita que se resuelve con varias actividades posibles as:
1. Android genera una lista interna en el sistema operativo con todos los filtros de
intenciones posibles incluyendo los de las aplicaciones nativas preinstaladas.
2. Elimina los filtros que no coinciden con la accin solicitada.
3. Eliminan las categoras que no coinciden con la categora invocada.
4. Cada parte de la URI de los datos de la intencin que se invoca se compara
con la etiqueta <data> del filtro. Los parmetros especificados en el filtro han
de coincidir con los de la intencin. Es decir, no podemos hacer una llamada
240
Intents
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
}
5.1.10
241
El mtodo addIntentOptions() del objeto men recibe como parmetro una intencin
que especifica los datos para los que se quiere proporcionar una accin. Se invoca este
mtodo desde los mtodos onCreateOptionsMenu() o onCreateContextMenu(), que ya
hemos
estudiado.
La
CATEGORY_ALTERNATIVE
intencin
o
slo
especifica
los
datos
la
CATEGORY_SELECTED_ALTERNATIVE.
No
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Creamos un intent que se usa para resolver que acciones aplican a
// ese tipo de datos.
Intent intent = new Intent();
242
categora
se
debe
Intents
intent.setData(Dato.CONTENT_URI);
intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE);
// Buscamos el men que coincide con esos datos.
menu.addIntentOptions(
R.id.intent_group, // Menu group donde aadimos las nuevas opciones
0,
// ID nico de la opcin (ninguno)
0,
// Orden de la opcin (ninguno)
this.getComponentName(),
// Nombre Actividad actual
null,
// Opciones que se colocan al principio (ninguna)
intent, // Intent creado con los datos y la categora
0,
// Parmetro adicional (ninguno)
null); // Matriz de MenuItems que correla opciones (ninguna)
return true;
}
5.2
USO DE INTENTS
5.2.1
actividades. Para ello, vamos a invocar intenciones explcitamente entre dos actividades. La
primera actividad llama a la segunda, tambin llamada subactividad, a travs de una intencin
explcita. Esta segunda actividad recibe datos de la primera a travs de la clase Bundle, que
pueden ser recuperados a travs de intent.getExtras().
La segunda actividad (o subactividad) puede finalizar mediante el botn de retroceso
del telfono o por una accin del usuario en sta, por ejemplo, un clic en un botn o la
seleccin de una opcin en un listado. En este caso se lanza el mtodo finish(), en el que se
pueden transferir algunos datos como respuesta de la ejecucin a la actividad principal inicial.
En esta actividad principal se utiliza el mtodo startActivityForResult() para recibir estos
datos de la subactividad.
A continuacin, vamos a ver cmo funciona la invocacin explcita de Intenciones en
Android mediante un ejemplo sencillo que simula una aplicacin que gestiona un nico
contacto. En este ejemplo debemos prestar atencin al cdigo Java que interrelaciona ambas
Actividades.
Lo primero que vamos a hacer es definir el fichero XML que incluye los diseos (layout)
de ambas actividades. Puedes encontrar este diseo en los ficheros del proyecto Android:
243
Despus, creamos el cdigo fuente Java para las dos actividades. La segunda
actividad, que se invoca desde la primera, muestra los datos recibidos e indica si devuelve
datos a la actividad principal. Veamos el cdigo fuente de la actividad principal:
public class IntencionexplicitaActivity extends Activity {
private static final int COD_PETICION = 10;
private String nombre, apellidos;
private TextView resultadoLbl;
private Button ModContactoBtn, AltaContactoBtn;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Subrayamos la etiqueta que hace de ttulo
TextView tituloLbl = (TextView) findViewById(R.id.tituloLbl);
SpannableString contenido = new SpannableString(tituloLbl.getText());
contenido.setSpan(new UnderlineSpan(), 0, contenido.length(), 0);
tituloLbl.setText(contenido);
resultadoLbl = (TextView) findViewById(R.id.resultadoLbl);
// Al arrancar la aplicacin como no hay un contacto no se puede
modificar
ModContactoBtn = (Button) findViewById(R.id.ModContactoBtn);
AltaContactoBtn = (Button) findViewById(R.id.AltaContactoBtn);
ModContactoBtn.setEnabled(false);
resultadoLbl.setText("No has dado de alta ningn contacto");
// Cargamos las variables con el dato
nombre="";
apellidos="";
}
public void onClick(View view) {
Intent i = new Intent(this, ActividadDos.class);
244
Intents
switch (view.getId()) {
case R.id.AltaContactoBtn:
i.putExtra("operacion", "alta");
i.putExtra("nombre", "");
i.putExtra("apellidos", "");
break;
case R.id.ModContactoBtn:
i.putExtra("operacion", "modifica");
i.putExtra("nombre", nombre);
i.putExtra("apellidos", apellidos);
break;
}
// Invocamos explcitamente la actividad con los datos "i"
startActivityForResult(i, COD_PETICION);
}
@Override
// Este mtodo se invoca cuando la subactividad finaliza
protected void onActivityResult(int requestCode, int resultCode, Intent
data) {
// Si el Cd. peticin no coincide (otra aplicacin est usando esta
// actividad tambin) no tratamos la informacin
if (requestCode != COD_PETICION) return;
// Si la subactividad responde OK
if (resultCode == RESULT_OK) {
resultadoLbl.setText("");
if (data.hasExtra("nombre")) {
resultadoLbl.setText("Nombre: " +
data.getExtras().getString("nombre")+"\n");
nombre= data.getExtras().getString("nombre");
}
if (data.hasExtra("apellidos")) {
resultadoLbl.append("Apellidos: " +
data.getExtras().getString("apellidos")+"\n");
apellidos= data.getExtras().getString("apellidos");
245
}
if (!nombre.isEmpty() || !apellidos.isEmpty()) {
AltaContactoBtn.setEnabled(false);
ModContactoBtn.setEnabled(true);
String auxStr = "modificado";
String operacion = data.getExtras().getString("operacion");
if (operacion.equals("alta")) auxStr = "dado de alta";
Toast.makeText(this, "Has " + auxStr + " el contacto
correctamente", Toast.LENGTH_SHORT).show();
} else {
AltaContactoBtn.setEnabled(true);
ModContactoBtn.setEnabled(false);
}
} else
Toast.makeText(this, "Has salido de la subactividad sin pulsar
el botn 'Aceptar'", Toast.LENGTH_SHORT).show();
}
}
246
Intents
= (TextView) findViewById(R.id.tituloLbl);
247
super.finish();
}
}
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<activity android:name=".IntencionexplicitaActivity"
android:label="@string/app_name">
<intent-filter>
248
Intents
5.2.3
dos actividades mediante Acciones. Para ello, vamos usar actividades de aplicaciones que el
sistema operativo instala por defecto.
Lo primero que vamos a hacer es definir el fichero XML que incluye el diseo (layout)
de la actividad principal. Puedes encontrar este diseo en el fichero res/layout/main.xml del
proyecto Android.
Para poder usar Intents con componentes de Android hay que aadir los siguientes
permisos a la aplicacin en el fichero "AndroidManifest.xml":
249
<uses-permission android:name="android.permission.CALL_PRIVILEGED"></usespermission>
<uses-permission android:name="android.permission.CALL_PHONE"></usespermission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.READ_CONTACTS"></usespermission>
250
Intents
@Override
// Mtodo que se lanza cuando un Intent acaba su tarea. En este caso slo la
// accin que selecciona un contacto devuelve informacin
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == SELEC_CONTACTO) {
// En la Unidad 7 veremos los Content Providers. En este caso usamos
los contactos del telfono
Uri contactoData = data.getData();
Cursor c = managedQuery(contactoData, null, null, null, null);
if (c.moveToFirst()) {
String nombre= c.getString(c.getColumnIndexOrThrow(
ContactsContract.Contacts.DISPLAY_NAME));
Toast.makeText(this, "Nombre seleccionado: "+ nombre,
Toast.LENGTH_LONG).show();
}
} // end RESULT_OK
}
En el cdigo fuente anterior podemos ver que algunas actividades se inician con el
mtodo startActivity() porque no queremos saber el resultado de la ejecucin de la
subactividad. Sin embargo, el segundo botn "Seleccionar contacto" se inicia con el mtodo
startActivityForResult() para obtener el resultado de la ejecucin de la subactividad en el
mtodo onActivityResult(). En la prctica lo que hacemos es obtener el contacto
seleccionado mediante un identificador URI de la base de datos de contactos del telfono.
Desde Eclipse puedes abrir el proyecto Ejemplo 2 (Intencin implcita) de la Unidad 5. Estudia
el cdigo fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el
que hemos utilizado Intenciones invocadas de manera implcita.
251
Fjate que en el cdigo fuente no especificamos la aplicacin que tiene que lanzarse
para esa Accin, simplemente dejamos que Android decida qu aplicacin es ms apropiada
para la tarea solicitada.
5.2.4
dispone de componentes que pueden ser utilizados por otras aplicaciones mediante Acciones.
El Ejemplo 2 de este Unidad muestra cmo definir filtros de intenciones (Filter Intens)
de una Actividad interna de la aplicacin para que pueda ser invocada implcitamente desde
otra aplicacin mediante su Accin correspondiente.
En este caso, hemos definido en el sistema operativo un nuevo navegador de Internet.
Por simplificacin, esta nueva actividad del navegador de Internet lo vamos a iniciar desde la
misma aplicacin, si bien esta opcin aparecer tambin en otras aplicaciones del sistema
operativo que deseen navegar por Internet.
Para que Android sepa que hay una nueva Accin disponible en el sistema operativo,
tenemos
que
aadir
"AndroidManifest.xml":
252
la
Actividad
con
la
Accin
correspondiente
en
el
fichero
Intents
<activity android:name=".NavegadorActivity"
android:label="@string/navegadorAct">
<!-- Filtro que declara el nuevo navegador en el sistema operativo -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http"/>
</intent-filter>
</activity>
En este caso, la accin es visualizar (VIEW) el protocolo HTTP (esquema del dato).
Hemos usado la etiqueta <intent-filter> para definir la nueva accin. Por la nomenclatura de
Android, es muy importante definir el punto "." en el nombre de la actividad:
android:name=".NavegadorActivity".
Lo primero que vamos a hacer es definir el fichero XML que incluye el diseo (layout)
de la actividad secundaria (Navegador de Internet). Puedes encontrar este diseo en el fichero
res/layout/navegador.xml del proyecto Android.
253
} catch (Exception e) {
e.printStackTrace();
}
}
}
Desde Eclipse puedes abrir el proyecto Ejemplo 2 (Intencin implcita) de la Unidad 5. Estudia
el cdigo fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el
que hemos definido una nueva Accin mediante Filtros de Intenciones.
254
Intents
5.2.5
una determinada Accin en un Intent. Por ejemplo, puede ocurrir que ampliemos la
funcionalidad de una aplicacin usando una actividad de otra aplicacin opcional que el
usuario puede haber instalado.
Esto se puede hacer usando la clase PackageManager de Android y el mtodo
queryIntentActivities(), para consultar si algn componente instalado en el telfono responde
a esa accin.
El siguiente cdigo comprueba si una Accin existe. As, es muy fcil cambiar el
comportamiento de una aplicacin, como mostrar u ocultar opciones de la misma.
255
5.3
5.3.1
que, por defecto, una aplicacin no tiene permisos para realizar cualquier operacin que
pueda afectar negativamente a otras aplicaciones, al sistema operativo o al usuario. Esto
incluye la lectura o escritura de datos privados del usuario (como los contactos o correos
electrnicos), leer o escribir archivos de otra aplicacin, acceder a Internet, etctera.
Debido a que Android separa la ejecucin de las aplicaciones en cajas de arena (del
ingls sandbox), las aplicaciones deben compartir recursos y datos de manera explcita.
Un sandbox es un sistema de aislamiento de procesos, mediante el cual se pueden
ejecutar distintos programas con seguridad y de manera separada.
Para compartir recursos entre aplicaciones, stas deben declarar al sistema Android
los permisos adicionales que necesitan para funcionar correctamente y ampliar su
funcionalidad bsica. Las aplicaciones declaran los permisos que necesitan y el sistema
Android solicita al usuario su consentimiento cuando instala la aplicacin. Android no tiene
ningn mecanismo para dar permisos de forma dinmica (en tiempo de ejecucin).
5.3.2
Firma de aplicacin
Todas las aplicaciones Android (archivos .apk) deben estar firmadas con un certificado
Intents
5.3.3
nico de usuario de Linux. Esta identidad no cambia mientras el paquete est instalado en el
dispositivo. En un dispositivo diferente el mismo paquete puede tener un ID de usuario
distinto; as pues, lo importante es que cada paquete siempre tiene otro ID de usuario en un
dispositivo cualquiera.
Debido a que la seguridad en Android se hace a nivel de proceso, el cdigo de dos
paquetes cualquiera no se puede ejecutar en el mismo proceso por defecto, ya que funcionan
con diferentes usuarios de Linux.
Sin
embargo,
se
puede
utilizar
el
atributo
sharedUserId
del
fichero
5.3.4
Permisos de aplicaciones
Una aplicacin bsica de Android no tiene permisos asociados, por lo que no puede
hacer nada que afectara al usuario o a cualquier aplicacin instalada en el dispositivo. Para
hacer uso de las caractersticas protegidas del dispositivo, se debe incluir en el fichero
AndroidManifest.xml del proyecto una o ms etiquetas <uses-permission> que declaren los
permisos que necesita la aplicacin.
En alguno de los ejemplos anteriores del curso ya hemos usado esta etiqueta para
poder ampliar la funcionalidad de la aplicacin y acceder a determinados recursos del sistema
operativo.
257
En este caso, estamos manifestando que esta aplicacin necesita poder recibir
mensajes cortos SMS para funcionar.
Como hemos comentado, los permisos se asignan en el momento en que se instala la
aplicacin en el dispositivo. Para ello, se pide al usuario su consentimiento para que la
aplicacin pueda acceder a los recursos solicitados.
Por lo tanto, a la hora de programar una aplicacin Android, es importante seleccionar
slo los permisos que realmente necesita esa aplicacin y justificar la peticin al usuario. Ten
en cuenta que cuando programes y pruebes aplicaciones en el emulador de tu ordenador, este
mensaje no aparece; solamente aparece al instalar las aplicaciones en un dispositivo real.
La pantalla que informa de los permisos tiene este aspecto:
El programador puede definir sus propios permisos internos de aplicacin para que
otra aplicacin los utilice. Ms adelante veremos cmo se hace.
Todos los permisos del sistema comienzan con el texto android.permission y se
pueden ver en la documentacin oficial de Android para la clase Manifest.permission. Como
258
Intents
hemos dicho, las aplicaciones de terceros pueden tener sus propios permisos. De forma
general, resumimos algunos de los permisos ms utilizados:
259
Para que funcione bien esta aplicacin, debemos aadir la siguiente etiqueta en el
fichero AndroidManifest:
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
260
Intents
5.3.5
261
Ejemplo de permiso:
<permission
android:name="es.mentor.ejemplo.VER_LISTADO"
android:description="Permite ver el listado de ..."
android:label="Ver listado contactos" />
5.3.6
de
las
actividades
los
servicios
podemos
definir
el
atributo
android:permission, que indica el nombre del permiso necesario para acceder a ese elemento
de la aplicacin. Fjate en este ejemplo:
<activity android:name=".nombreActividad"
android:label="@string/app_name"
android:permission="es.mentor.ejemplo.VER_LISTADO">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
De esta forma, nicamente las aplicaciones que hayan solicitado el permiso indicado
podrn acceder al elemento de forma segura. En este contexto, el acceso significa lo
siguiente:
262
Intents
<provider android:name=".nombreProveedor"
android:authorities="es.mentor.ejemplo.proveedor"
android:readPermission="es.mentor.ejemplo.VER_LISTADO"
android:writePermission="es.mentor.ejemplo.ESCRIBIR_LISTADO" />
</provider>
5.3.7
externas estn solicitando los permisos necesarios para iniciar un componente de nuestra
aplicacin:
Los
servicios
pueden
checkCallingPermission().
verificar
Este
los
permisos
mtodo
usando
devuelve
el
mtodo
tambin
263
5.3.8
permisos que necesita sta. Es decir, si no asignamos bien los permisos en el fichero
AndroidManifest, veremos los errores en tiempo de ejecucin. Por esto, debemos prestar
especial cuidado a la hora de declarar los permisos correctos y probar la aplicacin en el
emulador de Android.
Adems,
si
definimos
en
la
aplicacin
permisos
internos
determinados
componentes, es importante documentar bien estos permisos para que otros desarrolladores
puedan aprovechar las capacidades de nuestra aplicacin.
5.4
5.4.1
Tab.Layout
Android mediante el uso de diversos componentes de tipo Layout, como los lineales, los
absolutos, los relativos, etctera.
Los Layouts son elementos organizativos bsicos de la interfaz, pero, teniendo en
cuenta el poco espacio disponible en las pantallas de los telfono o, simplemente, por
cuestiones de organizacin, a veces es interesante dividir la distribucin de los componentes
en varias pantallas.
Una de las formas clsicas de hacerlo en programacin es mediante la distribucin de
los componentes en pestaas (en ingls tabs).
Android tambin permite disear este tipo de interfaces de usuario, si bien lo hace de
una forma caracterstica, ya que la implementacin depende de varios elementos que deben
estar distribuidos y estructurados de una forma determinada.
Adicionalmente, no es suficiente con definir la interfaz en el fichero XML de diseo que
hemos utilizado en otros ejemplos, sino que tambin es necesario completarlo con algunas
sentencias de cdigo.
A continuacin, en el Ejemplo 4 de esta Unidad, vamos a ver paso a paso cmo
implementar este tipo de interfaces.
El elemento principal de Android de un conjunto de pestaas es el componente
TabHost. ste es el contenedor principal del conjunto de pestaas y debe tener
obligatoriamente como id el valor @android:id/tabhost.
264
Intents
Si abrimos el fichero XML del layout, veremos el siguiente cdigo que corresponde a
esta estructura:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="match_parent" android:layout_width="match_parent">
<TabHost android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
265
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TabWidget android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@android:id/tabs" />
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@android:id/tabcontent" >
<LinearLayout android:id="@+id/pest1"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView android:id="@+id/textView1"
android:text="Contenido de la Pestaa 1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/pest2"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView android:id="@+id/textView2"
android:text="Contenido de la Pestaa 2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
266
Intents
</TabHost>
</LinearLayout>
267
pestania.setIndicator("Pestaa 1",
res.getDrawable(android.R.drawable.ic_menu_agenda));
//Aadimos la pestaa 1 al TabHost
tabs.addTab(pestania);
// Preparamos un objeto con referencia a la pestaa 2
pestania=tabs.newTabSpec("mipestania2");
//Establecemos el contenido de la pestaa 2
pestania.setContent(R.id.pest2);
// Definimos la pestaa 2 en el TabHost
pestania.setIndicator("Pestaa 2",
res.getDrawable(android.R.drawable.ic_menu_directions));
//Aadimos la pestaa 2 al TabHost
tabs.addTab(pestania);
// Indicamos la pestaa activa por defecto
tabs.setCurrentTab(0);
268
Intents
evento
los
podemos
implementar
mediante
el
mtodo
269
Intents
los
permisos
necesarios
para
utilizar
recursos
de
otras
aplicaciones.
2. Seguridad interna (autoproteccin): la aplicacin utiliza Content
Providers, Servicios o Receptores de mensajes de difusin (Broadcast
Receivers). En este caso hay que controlar qu aplicaciones pueden acceder
a la informacin interna y cmo acceden a ella.
No existe un mecanismo que detecte automticamente al compilar los
permisos que necesita una aplicacin. Por esto, debemos prestar especial
cuidado a la hora de declarar los permisos correctos y probar la aplicacin en el
emulador de Android.
Android tambin permite disear interfaces de usuario con pestaas mediante la
clase TabHost.
271
NDICE
6.1 BASES DE DATOS .................................................................. 275
6.1.1 Introduccin ...........................................................................275
6.1.2 Teora sobre Bases de Datos ..............................................275
6.1.3 Ventajas de las bases de datos ..........................................279
6.1.4 Bases de datos relacionales................................................281
6.1.5 Diseo de bases de datos ...................................................283
6.2 SQLite en Android .................................................................. 284
6.2.1 Gestin de la informacin en Android ........................... 284
6.2.2 Gestin de la Base de Datos SQLite en Android........... 285
6.2.3 Creacin de Bases de datos SQLite.............................. 286
6.2.4 Modificacin de la informacin de BD SQLite............... 292
6.2.4.1 Mtodo insert() .....................................................293
6.2.4.2 Mtodo update() y mtodo delete() ..................294
6.2.5 Uso de parmetros en los mtodos SQLite................... 294
6.3 Consultas SQLite en Android ............................................... 295
6.3.1 Seleccin y recuperacin de Consultas de BD SQLite ..295
6.3.2 Ejemplo prctico de BD SQLite con Android ................ 298
6.3.3 Acceso y creacin de la Base de datos......................... 299
6.3.4 Recursos de diseo XML ............................................... 303
6.3.5 Actividades..................................................................... 304
6.3.6 Fichero Androidmanifest.xml ......................................... 310
6.4 GESTIN DE FICHEROS XML .............................................. 311
6.4.1 SAX es el modelo clsico en Android ............................ 316
6.4.2 SAX simplificado en Android.......................................... 323
6.4.3 DOM en Android ............................................................ 327
6.4.4 StAX en Android............................................................. 331
6.1
6.1.1
BASES DE DATOS
Introduccin
En esta Unidad vamos a repasar, como prembulo , la teora general sobre bases de
datos.
Despus, explicaremos cmo gestionar bases de datos SQLite en Android dentro de
las aplicaciones.
Finalmente, detallaremos el uso de ficheros XML en Android.
6.1.2
este
apartado
vamos
explicar
brevemente
algunos
conceptos
fundamentales sobre las bases de datos. Suponemos que el alumno o alumna ya tiene
conocimientos suficientes sobre las mismas y, por tanto, abordaremos slo algunos
conocimientos ms relacionados con la forma en que Android accede a las bases de datos y
trata su informacin.
El trmino base de datos es informtico, pero puede aplicarse tambin a la forma
como se almacena, ordena y utiliza manualmente la informacin. Por ejemplo, ya hemos visto
en la Unidad 4 cmo leer y almacenar informacin en ficheros de preferencias o archivos en la
memoria del dispositivo Android. La informacin de estos ficheros puede ser considerada una
base de datos en un sentido amplio. Es decir, se almacena y se consulta la informacin
cuando es necesario.
Sin embargo, en el sentido informtico, la palabra base de datos se refiere a una
coleccin, conjunto o depsito de datos, almacenados en un soporte magntico o de otro
tipo, accesibles por mltiples usuarios de forma rpida y eficaz mediante el ordenador a travs
de una o de varias aplicaciones informticas independientes de los datos. stos se relacionan
entre s y estn organizados de tal manera que es fcil introducirlos, actualizarlos, recuperarlos
o llevar a cabo con ellos otras operaciones de gestin.
En el caso de Android, las bases de datos son privadas y nicamente una
aplicacin puede acceder a ellas para leer y escribir datos. Cuando una aplicacin desea
consultar o modificar la informacin de la base de datos de otra aplicacin, Android dispone
de los Content Providers que permiten a otras aplicaciones hacer las peticiones necesarias a
la aplicacin que alberga la base de datos. sta devuelve a la aplicacin la informacin
solicitada con los resultados de esas operaciones.
Android usa SQLite como motor de base de datos relacional. En el siguiente apartado
veremos sus caractersticas. La informacin que mostramos a continuacin est basada en la
versin 3 de SQLite.
275
Autor
Editorial
Antonio
El invierno en Lisboa Muoz
Molina
Seix Barral
Tener o ser?
Fondo
de
Econmica
Erich Fromm
Cultura
Filas
Crnica
de
una Gabriel Garca
Bruguera
muerte anunciada
Mrquez
El lobo estepario
Hermann
Hesse
Anaya Editores
Cada fila contiene el ttulo, el autor y la editorial de un libro y se relaciona con las
dems filas gracias a que incluye el mismo tipo de informacin (datos de los libros) y en todas
ellas la informacin est organizada de la misma forma: la primera columna contiene el ttulo
del libro, la segunda, el autor y la tercera, la editorial.
As pues, una base de datos contiene un conjunto de ficheros cuya informacin est
organizada de tal forma que puede ser tratada informticamente con rapidez y eficacia. La
informacin de una base de datos puede almacenarse en un solo fichero o en varios.
Los ficheros de una base de datos estn grabados en el servidor. Tienen un nombre
(por ejemplo, flores, ros, libros, coches, amigos, artculos, clientes, ventas, facturas, etctera).
Su denominacin debe seguir las normas establecidas para que el nombre de un fichero sea
correcto. Como puede verse, hemos prescindido de las tildes en los identificadores que las
llevan ortogrficamente.
El tipo o extensin de estos ficheros de base de datos puede ser muy variado, segn
el tipo de base de datos utilizado: en dBase es dbf (Data Base File, Fichero de Base de Datos),
en Access mdb, en Interbase db o dbf, en MySQL myd, etctera.
En el caso de SQLite en Android, el archivo de la base de datos suele tener la
extensin .db, si bien, puede almacenarse en el directorio especfico de la aplicacin con
276
cualquier extensin e, incluso, sin ella. En otros sistemas operativos, los archivos de una base
de datos de tipo SQLite suelen tener la extensin .sqlite.
Las filas de un archivo de base de datos se denominan registros y las columnas,
campos (fields, en ingls).
As pues, un fichero de base de datos est integrado por registros, que son cada
uno de sus elementos o componentes (flor, ro, libro, coche, amigo, artculo, cliente, venta o
factura). Todos los registros contienen un conjunto de campos en los que se almacena su
informacin; este conjunto define la estructura del fichero que integra una base de datos.
En la representacin grfica siguiente puede observarse, en forma de tabla, la
estructura de un fichero que contiene una base de datos con informacin sobre personas:
Campos
Nombre Sueldo
Fecha_nac
Observacion Foto
1
2
3
4
Registros 5
6
7
8
En las filas aparecen hasta once registros, cada uno de los cuales, en este caso,
contiene los cinco campos siguientes: Nombre, Sueldo, Fecha_nac, Observacion y Foto.
En el ejemplo anterior slo se han incluido once registros y cinco campos, pero de
hecho en las bases de datos que vamos a usar el nmero de registros es ilimitado (depende
de la capacidad del soporte) y el de campos es muy amplio, segn el tipo de base de datos
usada. Todos los registros tienen los mismos campos.
Si comparamos un fichero de base de datos con los archivadores de una biblioteca,
podemos decir que stos integran la base de datos. Cada archivador es como un fichero de la
base de datos, las fichas que hay en su interior son los registros y los apartados de cada
ficha (ttulo, autor, editorial, etctera) son los campos.
277
278
INT
TINYINT
SMALLINT
MEDIUMINT
BIGINT
UNSIGNED BIG INT
INT2
INT8
Todos estos tipos de campo de nmero entero se pueden definir al crear una tabla, si
bien, internamente, SQLite los traduce por afinidad al tipo INTEGER anterior.
En el caso del tipo de campo numrico con decimales, podemos usar los siguientes
tipos de campos:
DOUBLE
DOUBLE PRECISION
FLOAT
Todos estos tipos de campo de nmero con decimales se pueden definir al crear una
tabla, si bien, internamente, SQLite los traduce por afinidad al tipo REAL anterior.
3. Campo de tipo Fecha y Lgico. Puede contener fechas y tiempos (horas, minutos,
segundos) o almacenar valores lgicos (true / false). Admite ndice. SQLite define el tipo de
campo interno NUMERIC para almacenar otros tipos de campos necesarios en las
aplicaciones en una tabla, tales como los campos lgicos o de fecha, as como los que
establecen los decimales exactos en un campo numrico. Podemos usar los siguientes tipos
de campos en SQLite:
DECIMAL(10,5)
BOOLEAN
DATE
DATETIME
Todos estos tipos de campo se pueden definir al crear una tabla, si bien, internamente,
SQLite los traduce por afinidad al tipo NUMERIC anterior.
4. Campo de tipo Memo. Es un campo de longitud variable que admite gran cantidad
de texto o datos binarios segn nuestras necesidades. Para cada registro tendr una longitud
distinta, segn la cantidad de datos que se introduzcan en este campo. No admite ndice.
SQLite admite nicamente BLOB.
6.1.3
las diversas soluciones propuestas para resolver los problemas de estructuracin y acceso a
dicha informacin.
6.1.4
Nombre
Direccin
Edad
Sexo
Profesin
Len Garca
C/ Zurita, 25
25
Admtvo.
Mara Prez
C/ Flores, 15
30
Abogada
C/ Ro Sil, 11
50
Dependiente
Filas
(Registros)
3
Jos
Rodrguez
Juana de Dios
Avda. Canarias, 50
70
Jubilada
Begoa Lpez
15
Estudiante
Columnas (Campos)
Como se ve, una tabla consta de filas y de columnas; en cada columna, denominada
campo en la base de datos, hay un dato: Nombre, Direccin, Edad, etctera; cada fila es un
registro que contiene todos los datos de los elementos de la base. Cada tabla tiene un
281
registro especial, denominado cabecera, que contiene los nombres de los campos y sus
atributos (tipo y longitud).
Generalmente, una base de datos no consta de una sola tabla, sino de varias.
Grficamente puede representarse as:
Estas tablas no son independientes unas de otras, sino que tienen al menos un
campo comn con las otras a travs del cual se puede acceder a la informacin que
contienen todas en conjunto.
Por ejemplo, la base de datos de una biblioteca puede estar integrada por una tabla de
libros, otra de lectores, otra de prstamos y otra de editoriales. El fichero de libros puede
contener la informacin completa de cada volumen: ttulo, autor, editorial, ao de edicin,
precio, nmero de pginas, cdigo de materia, nmero de registro, etctera.
El fichero de editoriales contendr los datos de cada entidad editora: nombre,
direccin, telfono, plazo de entrega, descuentos, etctera.
El fichero de lectores estar integrado por los datos personales y profesionales de
stos: nombre, DNI, direccin, telfono, profesin, centro de trabajo, nmero de carn,
etctera.
El fichero de prstamos contendr datos de este tipo: nmero de registro del libro
prestado, nmero de carn del lector, fecha del prstamo, plazo, etctera.
Como puede verse, la informacin no debe repetirse en todos los ficheros, pero s
debe poder relacionarse. Por ejemplo, los ficheros de libros y editoriales, tienen en comn el
campo EDITORIAL. Los ficheros de libros y prstamos tienen en comn, al menos, el
NMERO DE REGISTRO del libro prestado, gracias a lo cual desde uno se puede acceder a
los datos del otro. Los ficheros de lectores y prstamos tienen en comn el campo CARN,
etctera.
282
Son bases de datos relacionales Microsoft Access, Oracle, SQL Server, MySQL,
SQLite y otras.
6.1.5
que
se
espera
documentos, etctera.
A continuacin, se resumen las operaciones que deben llevarse a cabo al disear una
base de datos:
1. Atendiendo a la informacin que contiene es preciso:
Identificar los diferentes elementos informativos (artculos, clientes, ventas,
facturas, etctera) que forman parte de la base de datos.
283
Determinar los datos que debe contener cada uno de esos elementos.
Precisar el grado de necesidad y de utilizacin de cada dato.
Concretar las operaciones que se van a realizar con los datos: aritmticas, lgicas,
de salida slo por la pantalla, de salida tambin por la impresora, etctera.
Seleccionar el dato o datos esenciales que deben ser el campo clave por el que se
ordenarn las unidades o elementos mencionados.
Fijar los datos comunes a los diferentes ficheros de la base de datos que van a
permitir relacionar la informacin distribuida entre ellos.
2. Atendiendo a la estructura de la base de datos
Distribuir la informacin en ficheros segn los diferentes grupos que se hayan
hecho (artculos, clientes, etctera) y dar un nombre a cada fichero.
Determinar el nombre de cada campo de los registros de cada fichero. Este
nombre ha de ser claro y debe significar algo para que pueda recordarse fcilmente.
Decidir qu tipo conviene asignar a cada campo segn la clase de operaciones
que vayamos a realizar con sus datos.
Asignar a cada campo una longitud apropiada para tener los datos fundamentales
sin despilfarro de memoria interna ni de espacio en el disco duro o soporte
empleado.
Establecer un orden lgico y prctico agrupando los campos segn un criterio
concreto: clase e importancia de los datos, frecuencia de utilizacin, proximidad,
parecido, etctera.
Decidir cul o cules van a ser los campos clave permanentes y situarlos al
principio de la estructura.
No incluir campos que puedan ser el resultado de diversas operaciones de
tratamiento posterior.
Fijar los campos comunes a todos los ficheros para poder relacionarlos con otros
de la misma aplicacin.
6.2
6.2.1
SQLite en Android
284
Preferencias de la aplicacin
En la Unidad 4 hemos tratado las dos primeras formas y en esta Unidad 6 veremos las
bases de datos.
6.2.2
Es de cdigo libre.
285
6.2.3
SQLite consiste en usar la clase Java SQLiteOpenHelper. En realidad, debemos definir una
clase propia que derive de ella y personalizarla para adaptarnos a las necesidades concretas
de la aplicacin.
La clase SQLiteOpenHelper define un nico constructor que, normalmente, no es
necesario reescribir y los dos mtodos abstractos onCreate() y onUpgrade() que tendremos
que implementar con el cdigo Java necesario para crear la base de datos acorde con las
necesidades de la aplicacin. Tambin debemos hacerlo para modificar su estructura si hace
falta cambiar los campos que definen alguna tabla al actualizar la versin de la aplicacin.
En el Ejemplo 1 de esta Unidad, vamos a crear una base de datos muy sencilla
llamada BDBiblioteca.db, con una nica tabla interna llamada Ejemplares que albergar
nicamente cinco campos:
prestado: BOOLEAN
Para
esto,
vamos
crear
la
clase
BibliotecaSQLiteHelper
derivada
de
286
@Override
// Si la BD no existe, Android llama a este mtodo
public void onCreate(SQLiteDatabase db) {
//Se ejecuta la sentencia SQL de creacin de la tabla
db.execSQL(createBDSQL);
}
@Override
public void onUpgrade(SQLiteDatabase db, int versionAnterior, int
versionNueva) {
/* NOTA: para simplificar este ejemplo eliminamos directamente la tabla
* anterior y la creamos de nuevo.
* Sin embargo, lo normal sera migrar los datos de la tabla antigua
* a la nueva estructura de campos, por lo que las sentencias podran
* ser del estilo ALTER TABLE.
*/
//Se elimina la versin anterior de la tabla
db.execSQL("DROP TABLE IF EXISTS Ejemplares");
En el cdigo fuente anterior se define la variable esttica (en Java se definen as las
constantes) createBDSQL, donde se establece la orden SQL para crear la tabla llamada
Ejemplares con los campos alfanumricos descritos anteriormente.
ATENCIN: en este curso no se describe la sintaxis del lenguaje SQL, pues se considera que
el alumno o alumna conoce cmo usar una base de datos relacional.
287
288
289
Desde Eclipse puedes abrir el proyecto Ejemplo 1 (Crear base de datos SQLite) de la
Unidad 6. Estudia el cdigo fuente y ejectalo para mostrar en el AVD el resultado del
programa anterior, en el que hemos utilizado los mtodos de la base de datos SQLite.
Hemos visto que el fichero de la base de datos del Ejemplo 1 se ha creado en la ruta
correcta. Para comprobar que la tabla se ha creada correctamente y hemos insertado los
registros en la misma, podemos usar dos mtodos:
290
291
Vamos a comprobar que se han insertado bien los cinco registros del ejemplo en la
tabla Ejemplares. Para ello, escribimos la siguiente orden: SELECT * FROM Ejemplares;.
Si la orden est escrita correctamente, veremos el resultado en la pantalla; si no, se
mostrar el error correspondiente. En la imagen siguiente se muestra el resultado de todos los
comandos:
Para salir del cliente SQLite debemos escribir el comando ".exit" (fjate que lleva un
punto delante) y para abandonar la shell del emulador debemos escribir el comando "exit".
6.2.4
operaciones sobre una base de datos que no devuelven resultados. Por ejemplo, aadir,
actualizar y eliminar registros de una tabla; tambin se puede crear tablas, ndices de
bsqueda, etctera.
La primera forma. que ya la hemos visto anteriormente, consiste en usar el mtodo
execSQL() de la clase SQLiteDatabase. Este mtodo permite ejecutar cualquier orden SQL
sobre la base de datos siempre que no sea necesario obtener los resultados de la orden. Ya
hemos utilizado este mtodo indicando como parmetro la cadena de texto de la orden SQL.
Aunque ya hemos visto en el Ejemplo 1 cmo se usa este mtodo, a continuacin,
mostramos algunos ejemplos ms:
292
//Insertar un registro
db.execSQL("INSERT INTO Ejemplares (titulo, autor, anio, prestado)
VALUES ('Ttulo', 'Autor', 2001, 'false'));
//Eliminar un registro
db.execSQL("DELETE FROM Ejemplares WHERE _id=1");
//Actualizar un registro
db.execSQL("UPDATE Ejemplares SET autor='Nombre' WHERE _id=1");
Mtodo insert()
Este mtodo se usa para aadir nuevos registros en una tabla de la base de datos. Al
invocar insert (String table, String nullColumnHack, ContentValues values), es necesario
definir tres parmetros:
Los valores que queremos insertar los pasamos como elementos de una coleccin de
tipo ContentValues. Esta coleccin es del tipo duplos de clave-valor, donde la clave es el
nombre del campo de la tabla y el valor es el dato que debemos insertar en dicho campo.
Veamos un ejemplo sencillo:
//Creamos el registro a partir del objeto ContentValues
ContentValues nuevoRegistro = new ContentValues();
nuevoRegistro.put("titulo", "Ttulo de la obra");
nuevoRegistro.put("autor","Nombre del autor");
...
//Insertamos el registro en la tabla de la base de datos
db.insert("Ejemplares", null, nuevoRegistro);
293
Este mtodo devuelve el campo ID del nuevo registro insertado o el valor -1 si ocurre
algn error durante la operacin.
6.2.4.2
Estos mtodos se usan para actualizar o borrar registros de una tabla. Los mtodos
update (String table, ContentValues values, String whereClause, String[] whereArgs) y
delete(String table, String whereClause, String[] whereArgs) se invocan de manera
parecida a insert(). En estos mtodos hay que usar el parmetro adicional whereArgs para
indicar la condicin WHERE de la orden SQL.
Por ejemplo, para actualizar el autor del usuario de id 1 escribimos lo siguiente:
//Establecemos los campos-valores que actualizamos
ContentValues valores = new ContentValues();
valores.put("autor","Otro autor");
//Actualizamos el registro de la tabla
db.update("Ejemplares", valores, "_id=1");
En el tercer parmetro del mtodo update() indicamos la condicin tal como haramos
en la clusula WHERE en una orden UPDATE de SQL.
El mtodo delete() se aplica de igual forma. Por ejemplo, para eliminar el registro 2
escribimos lo siguiente:
6.2.5
Estos argumentos son piezas variables de la sentencia SQL, en forma de matriz, que
evitan tener que construir una sentencia SQL concatenando cadenas de texto y variables para
formar la orden final SQL.
Estos argumentos SQL se indican con el smbolo ? y los valores de dichos
argumentos deben pasarse en la matriz en el mismo orden que aparecen en la sentencia SQL.
Fjate en el siguiente ejemplo:
//Elimina un registro con execSQL() utilizando argumentos
String[] args = new String[]{"Nombre de autor"};
db.execSQL("DELETE FROM Ejemplares WHERE autor=?", args);
//Actualiza dos registros con update() utilizando argumentos
ContentValues valores = new ContentValues();
valores.put("Ttulo 1","Ttulo 2");
String[] args = new String[]{1, "2"};
db.update("Ejemplares", valores, "_id=? OR _id=?", args);
6.3
6.3.1
295
296
Una vez colocado el cursor en el registro que queremos leer, podemos utilizar
cualquiera de los mtodos getXXX(ndice_columna) existentes para cada tipo de dato y as
recuperar el dato de cada campo de ese registro.
Por ejemplo, si queremos recuperar la segunda columna del registro actual y sta
contiene un campo alfanumrico, usamos la sentencia getString(1).
La primera columna de la consulta tiene el ndice 0, la segunda columna tiene ndice 1 y as
sucesivamente.
En el caso de que la columna contenga un dato de tipo real, ejecutaramos la
sentencia getDouble(1).
Teniendo todo esto en cuenta, veamos, a continuacin, cmo recorrer todos los
registros devueltos por la consulta del ejemplo anterior usando un cursor:
String[] campos = new String[] {"autor", "titulo"};
String[] args = new String[] {"1"};
297
6.3.2
los mtodos de acceso a base de datos que hemos estudiado hasta ahora.
Desde Eclipse puedes abrir el proyecto Ejemplo 2 (Notas) de la Unidad 6. Estudia el cdigo
fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el que hemos
utilizado mtodos de la base de datos SQLite.
298
Se trata de una aplicacin donde un usuario puede gestiona notas sencillas por
categoras. Estas notas se almacenan en la base de datos "bdnotas.db" en la tabla "notas"
que tiene la siguiente estructura:
La aplicacin est formada por dos actividades: la primera muestra todas las notas en
un listado y la segunda permite editarlas o dar de alta una nueva. Ambas actividades se
interconectan con Intents invocados de manera explcita.
Para mostrar el listado con las notas en la actividad principal hemos heredado la clase
ListActivity. Como ya hemos visto anteriormente en el curso, esta clase define un ListView
interno. Podemos conectarlo con la clase Cursor, que devuelve los resultados de las consultas
a la BD, usando la clase SimpleCursorAdapter de Android.
Veamos cmo hacerlo en la prctica:
6.3.3
// Contructor de la clase
public NotasBDHelper(Context context)
Basada en esta clase anterior vamos a definir la nueva clase NotasBDAdapter, que es
la encargada de hacer las consultas a la base de datos, borrar y actualizar registros de sta.
300
Dentro de esta clase hemos definido el mtodo abrir(), que se conecta a la base de
datos utilizando la clase NotasBDHelper.
Para actualizar y dar de alta registros hemos usado un argumento del tipo
ContentValues, que hemos estudiado en el apartado anterior.
class NotasBDAdapter {
// Campos de la BD
public static final String CAMPO_ID = "_id";
public static final String CAMPO_CATEGORIA = "categoria";
public static final String CAMPO_TITULO = "titulo";
public static final String CAMPO_DESCRIPCION = "descripcion";
private static final String TABLA_BD = "notas";
private Context contexto;
private SQLiteDatabase basedatos;
private NotasBDHelper bdHelper;
301
302
}
return mCursor;
}
// Mtodo que crea un objeto ContentValues con los parmetros indicados
private ContentValues crearContentValues(String categoria, String titulo,
String descripcion) {
ContentValues values = new ContentValues();
values.put(CAMPO_CATEGORIA, categoria);
values.put(CAMPO_TITULO, titulo);
values.put(CAMPO_DESCRIPCION, descripcion);
return values;
}
}
6.3.4
El alumno o alumna puede abrir estos ficheros en su ordenador y ver cmo estn
implementados los distintos diseos.
Adems, se definen los dos ficheros strings.xml y categorias.xml en la carpeta
res/values con los literales que usa la aplicacin.
303
6.3.5
Actividades
Como hemos comentado, la aplicacin est formada por dos actividades: la actividad
principal (NotasActivity) muestra un listado con todas las notas y la segunda (GestionarNota)
sirve para editarlas o dar de alta una nueva.
Veamos el contenido de la actividad principal:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Hacemos ms ancha la lnea de divisin entre elementos en el
listado
this.getListView().setDividerHeight(3);
304
return true;
}
// El usuario hace clic en una opcin del men principal
@Override
public boolean onMenuItemSelected(int id, MenuItem item) {
// Buscamos la opcin del men principal seleccionada
switch (item.getItemId()) {
case R.id.insertar:
// Creamos una actividad indicando el tipo de peticin
// "ACTIVIDAD_NUEVA" y esperamos el resultado de la misma
Intent i = new Intent(this, DetallesNota.class);
startActivityForResult(i, ACTIVIDAD_NUEVA);
// Indicamos que hemos manejado la opcin del men
return true;
}
return super.onMenuItemSelected(id, item);
}
// El usuario hace clic en una opcin del men contextual del listado
@Override
public boolean onContextItemSelected(MenuItem item) {
// Buscamos la opcin del men contextual seleccionada
switch (item.getItemId()) {
case MENU_ID:
// Obtenemos el id del elemento seleccionado
AdapterContextMenuInfo info = (AdapterContextMenuInfo)
item.getMenuInfo();
// Borramos ese registro
bdHelper.borraNota(info.id);
// Recargamos los datos
cargaDatos();
// Indicamos que hemos manejado la opcin del men
return true;
}
return super.onContextItemSelected(item);
305
}
// Cuando hacemos clic en un elemento del listado, se edita la Nota
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
// Creamos una actividad indicando el tipo de peticin
// "ACTIVIDAD_EDITAR" y esperamos el resultado de la misma
Intent i = new Intent(this, DetallesNota.class);
// Pasamos el campo _id como un dato extra
i.putExtra(NotasBDAdapter.CAMPO_ID, id);
startActivityForResult(i, ACTIVIDAD_EDITAR);
}
// Mtodo que se llama cuando una subactividad devuelve el resultado
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
// Recargamos los datos si se ha modificado algo.
// Es decir, el usuario ha hecho clic en OK
if (resultCode == Activity.RESULT_OK) cargaDatos();
}
private void cargaDatos() {
cursor = bdHelper.obtenerNotas();
// Se indica que a la Actividad principal que controle los recursos
// cursor. Es decir, si se termina la Actividad, se elimina esta
// Cursor de la memoria
startManagingCursor(cursor);
306
307
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
// Creamos un adaptador u abrimos la BD
bdHelper = new NotasBDAdapter(this);
bdHelper.abrir();
// Dibujamos el UI y buscamos sus Vistas
setContentView(R.layout.editar_nota);
categoriaSpinner = (Spinner) findViewById(R.id.category);
tituloText = (EditText) findViewById(R.id.nota_editar_titulo);
descripcionText = (EditText)
findViewById(R.id.nota_editar_descripcion);
Button aceptaBoton = (Button) findViewById(R.id.nota_editar_boton);
// Variable con el ID del registro actual
filaId = null;
// Obtenemos el campo ID que se debe haber pasado en la invocacin
// de la actividad si estamos editando el registro
Bundle extras = getIntent().getExtras();
// Si extras contiene algo cargamos ese ID
if (extras != null) {
filaId = extras.getLong(NotasBDAdapter.CAMPO_ID);
}
308
// Alta de registro
if (filaId == null) {
bdHelper.crearNota(categoria, titulo, descripcion);
} else { // Modificacin de registro
bdHelper.actualizarNota(filaId, categoria, titulo,
descripcion);
}
setResult(RESULT_OK);
// Acabamos la actividad
finish();
}
});
} // end onCreate
309
6.3.6
Fichero Androidmanifest.xml
Para que la subactividad GestionarNota est disponible en el sistema operativo,
<activity android:name=".GestionarNota"
android:windowSoftInputMode="stateVisible|adjustResize">
</activity>
El
atributo
android:windowSoftInputMode
310
indica
cmo
interacciona
esta
En este ejemplo hemos usado las opciones stateVisible y adjustResize para que el
teclado se muestre cuando el usuario acceda a un componente de introduccin de texto y
cambie las proporciones de la pantalla para hacer un "hueco" al teclado.
En la ayuda oficial de Android puedes encontrar todos los posibles valores con su
descripcin.
6.4
311
StAX: es una mezcla de las dos modelos anteriores. En este caso, tambin se
lee el fichero XML de forma secuencial, pero podemos controlar la forma en
que se leen sus elementos. En el caso de SAX es obligatorio leer todos los
elementos a la vez. Este modelo es tambin mucho ms rpido que DOM,
pero algo ms lento de SAX.
Si abrimos el documento RSS de esta fuente de noticias (en ingls feed), vemos la
estructura siguiente:
<rss version="2.0">
<channel>
<title>20minutos.es</title>
<link> http://www.20minutos.es/</link>
<description> Diario de informacin general y ...</description>
<language>es-ES</language>
<pubDate> Fri, 28 Oct 2011 18:54:41 GMT</pubDate>
312
313
// Clase que sirve para cargar en un objeto cada noticia que leamos del
fichero XML
public class Noticia {
// Dispone de las variables y mtodos tpicos de una clase sencilla
private String titulo;
private URL enlace;
private String descripcion;
private String fecha;
314
try {
this.enlace = new URL(enlace);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
Por simplificacin, hemos tratado todos los datos como cadenas de texto.
315
6.4.1
316
return noticias;
}
317
318
implements RSSParser {
319
El constructor de la clase anterior acepta como parmetro una direccin URL del
documento XML que analiza y controla la validez de dicha direccin
generando una
// Creamos un objeto del parser (analizador XML) en funcin del tipo (opcin
// men principal). La direccin (URL) de la fuente de noticias es una
//constante en este ejemplo
RSSParser analizador = XMLParser.getParser(tipo, feedUrl);
// Guardamos el momento actual de inicio de
long inicio = System.currentTimeMillis();
// Descargamos y analizamos el fichero XML
noticias = analizador.analizar();
// Calculamos el tiempo que ha tardado en leer el XML
long duracion = System.currentTimeMillis() - inicio;
// Mostramos el tiempo de lectura del XML
Toast.makeText(this, "Se han cargado los datos en "+duracion+" milisegundos",
1).show();
// Creamos un listado con todos los ttulos de las noticias
List<String> titulos = new ArrayList<String>(noticias.size());
for (Noticia msg : noticias){
titulos.add(msg.getTitulo());
}
321
Observa que, como estamos usando la misma aplicacin para mostrar cmo
funcionan todos los modelos de carga de archivos XML en Android, hemos creado una clase
abstracta que devuelve un objeto en funcin del tipo de analizador que el usuario ha decido
usar en ese momento.
NOTA: Para que esta aplicacin Android acceda a Internet, es necesario declararlo en el
fichero AndroidManifest.xml, que requiere el permiso "android.permission.INTERNET".
322
6.4.2
implements RSSParser {
323
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
/*
* Definimos los listerners de estos elementos anteriores
*/
// Mtodo de inicio de una nueva etiqueta item
item.setStartElementListener(new StartElementListener(){
public void start(Attributes attrs) {
noticiaActual = new Noticia();
}
});
// Mtodo de finalizacin de una nueva etiqueta item
item.setEndElementListener(new EndElementListener(){
public void end() {
noticias.add(noticiaActual);
}
});
324
325
En este nuevo modelo SAX simplificado de Android las acciones que debemos realizar
dentro de cada mtodo se definen dentro de la misma clase asociadas a etiquetas concretas
del XML.
Para esto, lo primero que hacemos es navegar por la estructura del archivo XML hasta
encontrar las etiquetas que tenemos que tratar y asignarlaa a algunos mtodos de tipo
listeners ("escuchadores") disponibles como StartElementListener() de inicio de etiqueta o
EndElementListener() de finalizacin de etiqueta, incluyendo las sentencias oportunas dentro
de estos mtodos.
Por ejemplo, para obtener el elemento <item>, en primer lugar buscamos el elemento
raz del XML (<rss>) declarando un objeto RootElement. Despus, accedemos a su elemento
hijo <channel> y, finalmente, obtenemos de ste ltimo el elemento hijo <item>. En cada
"salto" hemos utilizado el mtodo getChild().
Una vez hemos llegado a la etiqueta buscada, asignamos los listeners necesarios. En
este caso, uno de apertura y otro de cierre de etiqueta item, donde inicializamos la noticia
actual y la aadimos a la lista final, respectivamente, de forma similar a como lo hemos hecho
para el modelo SAX clsico.
326
6.4.3
DOM en Android
Como hemos comentado, el modelo DOM debe leer el documento XML
completamente antes de poder realizar ninguna accin con su contenido. Es decir, cambia
radicalmente la manera de leer los archivos XML.
Al acabar la lectura del documento XML este modelo devuelve todo su contenido en
una estructura de tipo rbol, donde los distintos elementos del fichero XML se representan en
forma de nodos y su jerarqua padre-hijo se establece mediante relaciones entre dichos nodos.
Por ejemplo, si tenemos el siguiente documento XML:
<noticias>
<noticia>
<titulo>Ttulo 1</titulo>
<enlace>Enlace 1</link>
</noticia>
<noticia>
<titulo>Ttulo 2</titulo>
<enlace>Enlace 2</link>
</noticia>
<noticias>
327
Como vemos, este rbol conserva la misma informacin del fichero XML, pero en
forma de nodos y relaciones entre nodos. Por esta razn es sencillo buscar fcilmente dentro
de la estructura un elemento en concreto.
Este rbol se conserva en memoria una vez ledo el documento completo, lo que
permite procesarlo en cualquier orden y tantas veces como sea necesario, a diferencia del
modelo SAX, donde el tratamiento es secuencial y siempre desde el principio hasta el final del
documento. Es decir, no se puede volver atrs una vez finalizada la lectura del documento
XML.
El modelo DOM de Android ofrece una serie de clases y mtodos que permiten cargar
la informacin de la forma descrita y facilitan la bsqueda de elementos dentro de la estructura
creada.
Veamos cmo queda el analizador XML usando el modelo DOM de Android:
implements RSSParser {
328
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
329
if (nombre.equalsIgnoreCase(EtiquetasRSS.TITLE)){
noticia.setTitulo(contenido.getFirstChild().getNodeValue());
} else if (nombre.equalsIgnoreCase(EtiquetasRSS.LINK)){
noticia.setEnlace(contenido.getFirstChild().getNodeValue());
} else if (nombre.equalsIgnoreCase(EtiquetasRSS.DESCRIPTION)){
// Puede ocurrir que el texto est distribuido en varias
// lneas, por lo que hay que leer todos los nodos internos
StringBuilder text = new StringBuilder();
NodeList chars = contenido.getChildNodes();
for (int k=0;k<chars.getLength();k++){
text.append(chars.item(k).getNodeValue());
}
noticia.setDescripcion(text.toString());
} else if (nombre.equalsIgnoreCase(EtiquetasRSS.PUB_DATE)){
noticia.setFecha(contenido.getFirstChild().getNodeValue());
}
} // end for j
// Aadimos la noticia al listado
noticias.add(noticia);
} // end for i
} catch (Exception e) {
throw new RuntimeException(e);
}
return noticias;
}
330
el
primer
paso
es
instanciar
la
API
de
DOM
partir
de
la
clase
Despus,
recorremos
estos
nodos
hijos
obteniendo
su
texto
6.4.4
StAX en Android
Este modelo StAX de lectura de documentos XML es muy parecido a SAX. La
diferencia principal est en que, mientras que en el modelo SAX no hay control de ejecucin
una vez iniciada la lectura del XML (el parser lee automticamente todo el XML desde el inicio
hasta el final invocando los mtodos necesarios), en el modelo StAX podemos guiar la lectura
del documento o intervenir en ella, solicitando de forma explcita la lectura del siguiente
elemento del documento XML y respondiendo al resultado con las acciones oportunas.
En este ejemplo hemos usado la implementacin de StAX de Android que se lama
XmlPull. Fjate en el cdigo fuente de este analizador:
331
implements RSSParser {
try {
// Asignamos el stream del XML al parsr
parser.setInput(this.getInputStream(), null);
// Guardamos el tipo de evento actual = START_DOCUMENT
int eventType = parser.getEventType();
Noticia noticiaActual = null;
// Variable que controla si se ha acabado el documento XML
boolean docAcabado = false;
// Mientras no acabe el documento
332
333
docAcabado = true;
}
break;
}
eventType = parser.next();
} // end while
} catch (Exception e) {
throw new RuntimeException(e);
}
// Devolvemos las noticias
return noticias;
}
334
Una vez identificado el tipo de evento, podemos consultar el nombre de la etiqueta del
elemento XML mediante parser.getName() y el texto contenido mediante parser.nextText().
Si ejecutas la aplicacin en el emulador de Android, vers que puedes acceder a los
distintos modelos de tratamiento de ficheros XML pulsando la tecla men
del emulador:
335
Si haces clic sobre una noticia vers que Android te permite seleccionar el navegador
que quieres usar para iniciar la accin Intent.ACTION_VIEW que permite abrir una pgina
Web:
336
337
338
CONTENT PROVIDERS,
SERVICIOS Y
NOTIFICACIONES
NDICE
7.1
7.2
7.3
7.6
7.1
CONTENT PROVIDERS
7.1.1 Introduccin
En esta Unidad vamos a estudiar los proveedores de contenidos (Content
Providers) para compartir informacin entre aplicaciones y el Resolvedor de contenidos
(Content Resolver) para consultar y actualizar la informacin de los Content Providers.
Despus, explicaremos cmo funcionan los servicios en Android.
A continuacin, detallaremos el uso de notificaciones en las aplicaciones Android.
Finalmente, veremos cmo utilizar el componente ViewPager que permite cambiar de
pantalla deslizando el dedo horizontalmente en el dispositivo.
En la Unidad 5 ya hemos visto un ejemplo muy sencillo sobre del acceso a un Content
Provider ya existente, concretamente en la lista de contactos de Android.
341
Fjate que en este ejemplo los botones "Insertar" y "Eliminar" son excluyentes. Slo se
puede borrar un alumno si previamente ha sido dado de alta y viceversa.
Se trata de un Content Provider que comparte informacin de los alumnos de un
colegio.
La aplicacin del colegio almacena la informacin que queremos compartir en una base
de datos SQLite.
342
En este ejemplo, los registros devueltos por el Content Provider de alumnos tiene este
aspecto:
Lo primero que hemos hecho en este Ejemplo es crear una aplicacin muy simple que
almacena y consulta los datos de los alumnos con la estructura similar a la tabla anterior.
Para esto, aplicamos los mismos conceptos que ya hemos estudiado en la Unidad 6
para el tratamiento de bases de datos.
Creamos una clase heredada de SQLiteOpenHelper donde definimos las sentencias
SQL que crean la tabla de alumnos implementando los mtodos onCreate() y onUpgrade(). El
cdigo de esta nueva clase tiene este aspecto:
343
//
344
Fjate que hemos incluido el campo _id en la tabla de la base de datos de alumnos.
Este campo lo declaramos como INTEGER PRIMARY KEY AUTOINCREMENT para que se
incremente automticamente cada vez que insertamos un nuevo registro en la tabla.
Adems, esta clase aade algunos registros de ejemplo para poder hacer pruebas.
Una vez que ya contamos con una aplicacin que ha definido su base de datos, vamos
a construir el nuevo Content Provider que permite compartir sus datos con otras aplicaciones.
El acceso a un Content Provider se realiza siempre mediante un identificador URI. Un
identificador URI es una cadena de texto parecida a una direccin Web de Internet. Es decir, si
para acceder a Google con el navegador escribimos http://www.google.es, para acceder a un
Content
Provider
utilizamos
una
direccin
similar
content://es.mentor.unidad7.ejemplo/alumnos.
Los identificadores URI de los Content Providers se pueden dividir en tres partes:
Prefijo content://: indica que dicho recurso debe ser tratado por un Content
Provider.
346
Por ltimo, vamos a definir varias cadenas constantes privadas que almacenen
informacin auxiliar con el nombre de la base de datos, su versin y la tabla a la que accede el
Content Provider.
Lo primero que debe hacer un Content Provider cuando otra aplicacin le solicita una
operacin es interpretar el URI utilizado. Para facilitar esta tarea al programador, Android
proporciona la clase llamada UriMatcher que interpreta los patrones en un URI.
Esto es muy til para determinar, por ejemplo, si un URI hace referencia a una tabla
genrica o a un registro concreto a travs de su ID:
Para ello definimos tambin en esta clase un objeto UriMatcher y dos nuevas
constantes que representan los dos tipos de URI que hemos indicado: acceso genrico a la
tabla (ALUMNOS) o acceso a un alumno por ID (ALUMNOS_ID).
Despus, creamos el objeto UriMatcher indicando el formato de ambos tipos de URI
de forma que pueda diferenciarlos y devolvernos su tipo (una de las dos constantes definidas,
ALUMNOS o ALUMNOS_ID):
//Necesario para UriMatcher
private static final int ALUMNOS = 1;
private static final int ALUMNOS_ID = 2;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("es.mentor.unidad7.ejemplo", "alumnos", ALUMNOS);
uriMatcher.addURI("es.mentor.unidad7.ejemplo", "alumnos/#", ALUMNOS_ID);
}
347
El mtodo ms importante del Content Provider es query(). Este mtodo recibe como
parmetros un URI, una lista de nombres de columna, un criterio de seleccin, una lista de
valores para las variables utilizadas en el criterio anterior y un criterio de ordenacin.
Todos estos parmetros son similares a los que estudiamos cuando tratamos sobre las
bases de datos SQLite para Android.
El mtodo query() devuelve los datos solicitados segn el URI, los criterios de
seleccin y ordenacin indicados como parmetros. As, si el URI hace referencia a un alumno
en concreto por su ID, se debe ser el nico registro devuelto. Si se solicita el contenido de la
tabla de alumnos, hay que realizar la consulta SQL correspondiente a la base de datos
respetando los criterios pasados como parmetros.
Para distinguir entre los dos tipos posibles de URI utilizamos el mtodo match() del
objeto uriMatcher. Si el tipo devuelto es ALUMNOS_ID, es decir, se ha solicitado informacin
de un alumno en concreto, sustituimos el criterio de seleccin por uno que busca en la tabla de
alumnos slo el registro con el ID indicado en la URI. Para obtener este ID utilizamos el mtodo
getLastPathSegment() del objeto uri, que extrae el ltimo elemento de la URI, en este caso el
ID del alumno.
Despus, hay que realizar la consulta a la base de datos mediante el mtodo query()
de SQLiteDatabase. Esto es muy fcil, ya que los parmetros son similares a los empleados
en el mtodo query() del Content Provider:
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
// Accedemos a la base de datos en modo lectura
SQLiteDatabase db = colegioBDhelper.getReadableDatabase();
348
Podemos observar que los resultados se devuelven en forma de Cursor, tal y como lo
hace el mtodo query() de SQLiteDatabase.
Por otra parte, los mtodos update() y delete() son completamente similares al mtodo
anterior. nicamente se diferencian en que stos devuelven como resultado el nmero de
registros afectados en lugar de un cursor. Veamos su cdigo:
@Override
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
// Variable temporal
int cont;
// Accedemos a la base de datos en modo escritura
SQLiteDatabase db = colegioBDhelper.getWritableDatabase();
//Si es una actualizacin a un ID concreto construimos el WHERE
String where = selection;
if(uriMatcher.match(uri) == ALUMNOS_ID){
where = "_id=" + uri.getLastPathSegment();
}
// Actualizamos la tabla
cont = db.update(TABLA_ALUMNOS, values, where, selectionArgs);
// Devolvemos el n de registros afectados por la consulta
return cont;
}
349
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Variable temporal
int cont;
// Accedemos a la base de datos en modo escritura
SQLiteDatabase db = colegioBDhelper.getWritableDatabase();
//Si borramos un ID concreto construimos el WHERE
String where = selection;
if(uriMatcher.match(uri) == ALUMNOS_ID){
where = "_id=" + uri.getLastPathSegment();
}
// Borramos los registros
cont = db.delete(TABLA_ALUMNOS, where, selectionArgs);
// Devolvemos el n de registros afectados por la consulta
return cont;
}
350
Por ltimo, slo queda implementar el mtodo getType(). Este mtodo se utiliza para
identificar el tipo de datos que devuelve el Content Provider. Este tipo de datos se expresa
como un MIME Type, tal y como hacen los navegadores Web para determinar qu tipo de
datos se est recibiendo al hacer una peticin a un servidor. Identificar el tipo de datos que
devuelve un Content Provider ayuda a Android a determinar qu aplicaciones son capaces de
procesar dichos datos.
En este ejemplo, existen dos tipos MIME distintos para cada entidad del Content
Provider: el primero se usa cuando se devuelve un registro nico concreto y el segundo cuando
se devuelven varios registros simultneamente. As, podemos utilizar los siguientes patrones
para definir uno u otro tipo de datos:
vnd.android.cursor.dir/vnd.mentor.alumno
vnd.android.cursor.item/vnd.mentor.alumno
@Override
public String getType(Uri uri) {
// Devolvemos un tipo de dato en funcin del URI
int match = uriMatcher.match(uri);
switch (match)
{
case ALUMNOS:
return "vnd.android.cursor.dir/vnd.mentor.alumno";
case ALUMNOS_ID:
return "vnd.android.cursor.item/vnd.mentor.alumno";
default:
return null;
finalizar
con
el
Content
Provider,
debemos
declararlo
en
el
fichero
<application android:icon="@drawable/icon"
android:label="@string/app_name">
...
<provider android:name=".ColegioContentProvider"
android:authorities="es.mentor.unidad7.ejemplo"/>
</application>
7.2
del ejemplo que hemos creado. Lo hacemos as para simplificar el ejemplo; de cualquier forma,
el cdigo necesario es exactamente el mismo si lo usamos desde otra aplicacin distinta.
Utilizar un Content Provider ya existente es muy sencillo, sobre todo si lo comparamos
con todo el proceso anterior de construccin de uno nuevo.
Para ello, vamos a usar la clase ContentResolver de Android que permite realizar
acciones (consultas de datos, actualizaciones de informacin, etctera) con cualquier Content
Provider que est disponible en el sistema operativo Android.
Desde la actividad principal hay que utilizar el mtodo getContentResolver() para
obtener la referencia de la aplicacin al objeto ContentResolver.
Una vez obtenida esta referencia, podemos utilizar sus mtodos query(), update(),
insert() y delete() para realizar las acciones equivalentes sobre el Content Provider.
En la aplicacin del ejemplo anterior hay tres botones en la pantalla principal: uno para
hacer una consulta de todos los alumnos, otro para insertar registros nuevos y el ltimo para
eliminar todos los registros nuevos insertados con el segundo botn.
Empecemos por la consulta de alumnos. El procedimiento es prcticamente igual al
que hemos estudiado para acceder a bases de datos SQLite.
Primero definimos una matriz con los nombres de las columnas de la tabla que
queremos recuperar en el resultado de la consulta: ID, nombre, apellidos y curso.
352
ColegioContentProvider.CONTENT_URI;
//Hacemos la consulta
Cursor cur = cr.query(alumnosUri,
columnas, //Columnas solicitadas
null,
//Condicin de la query
null,
null);
Una vez solicitada la consulta, hay que recorrer el cursor para procesar los registros.
Veamos cmo queda el cdigo fuente:
// Si obtenemos resultados
if (cur.moveToFirst())
{
String nombre;
String apellidos;
String curso;
353
do {
nombre = cur.getString(colNombre);
apellidos = cur.getString(colApellidos);
curso = cur.getString(colCurso);
txtResultados.append(nombre + " " + apellidos + ". Curso: " +
curso + "\n");
} while (cur.moveToNext()); // end while
}
354
7.3
Hemos visto lo sencillo que resulta acceder a los datos proporcionados por un Content
Provider.
Mediante este mecanismo podemos utilizar en nuestras aplicaciones muchos datos de la
propia plataforma Android. En la documentacin oficial del paquete android.provider podemos
consultar los datos que estn disponibles a travs de este mecanismo. Entre ellos encontramos
el historial de llamadas, la agenda de contactos, etctera.
Para ver cmo se usan los Content Providers con un tipo de datos definido por Android, en
el Ejemplo 2 de esta Unidad vamos a consultar el historial de llamadas del dispositivo, usando
el Content Provider android.provider.CallLog.
Desde Eclipse puedes abrir el proyecto Ejemplo 2 (Historial de llamadas) de la Unidad 7.
Estudia el cdigo fuente y ejectalo para mostrar en el AVD el resultado del programa, en el
que hemos utilizado un Content Provider definido por Android.
Para poder ver algn dato en este ejemplo, en primer lugar, vamos a registrar varias
llamadas en el emulador de Android. As, los resultados de la consulta al historial de llamadas
devolvern algunos registros.
A continuacin, vamos a simular varias llamadas salientes desde el emulador y varias
llamadas entrantes desde el DDMS.
Las llamadas salientes son sencillas de realizar usando el emulador como si se tratara de
un telfono normal y corriente. Accedemos al icono telfono, marcamos un nmero y
descolgamos como si se tratara de un dispositivo fsico:
355
Para simular llamadas entrantes debemos acceder desde Eclipse a la vista del DDMS. En
esta vista, en la pestaa Emulator Control aparece el apartado Telephony Actions, donde
podemos introducir un nmero cualquiera de telfono origen Incoming number y pulsar el
botn Call para que el dispositivo del emulador reciba una llamada entrante.
Sin aceptar la llamada en el emulador, pulsaremos Hang Up para terminar la llamada
simulando as una llamada perdida.
Una vez hemos simulado tanto llamadas entrantes como llamadas salientes, vamos a
desarrollar una aplicacin que consulte el historial de llamadas.
Si consultamos la documentacin del Content Provider android.provider.CallLog, veremos
que podemos extraer diferentes datos relacionados con la lista de llamadas. En este ejemplo
vamos a usar nicamente el nmero origen o destino de la llamada y el tipo de llamada
(entrante, saliente y perdida). Los nombres de estas columnas se almacenan en las
constantes Calls.NUMBER y Calls.TYPE respectivamente.
A continuacin, definimos una matriz con las columnas que vamos a recuperar,
obtenemos la referencia al Content Resolver de la aplicacin y ejecutamos la consulta
llamando al mtodo query(). Por ltimo, recorremos el cursor obtenido y procesamos los
resultados. Veamos el cdigo fuente:
356
Calls.CONTENT_URI;
//Condicin de la query
null,
null);
357
tipoLlamada = "SALIDA";
else if(tipo == Calls.MISSED_TYPE)
tipoLlamada = "PERDIDA";
// Mostramos la informacin
txtResultados.append(tipoLlamada + " : " + telefono + "\n");
} while (cur.moveToNext()); // end while
} else txtResultados.setText("No hay ninguna llamada en el histrico del
telfono. Para que funcione bien esta aplicacin debes simular alguna
llamada entrante o saliente. En la teora del curso de esta Unidad se
muestra cmo hacerlo.");
358
7.4
Actividad
Simplemente hay que implementar los mtodos onStartCommand() para el modo Autnomo y
onBind() para el modo Ligado.
Cualquier componente de una aplicacin puede iniciar un servicio. Incluso un
componente de otra aplicacin distinta a la que define el servicio tambin puede iniciarlo de la
misma forma que iniciaramos una Actividad de otra aplicacin mediante Intenciones.
Tambin se puede declarar un servicio como privado en la aplicacin, en el archivo
AndroidManifest.xml, y bloquear el acceso desde otras aplicaciones.
Los servicios tienen que ser declarados en el archivo AndroidManifest.xml con la
etiqueta <service android:name="nombreClase"> </service> y la implementacin de la
clase debe heredarse de la clase Service.
IMPORTANTE: los servicios propios de una aplicacin se ejecutan en el hilo principal de su
proceso; por lo tanto, para no bloquear el hilo principal o de la interfaz debemos, ejecutar estos
servicios con hilos de ejecucin, tal y como hemos visto en la Unidad 3.
7.4.2 Servicios propios
Una aplicacin puede declarar su propio servicio para llevar a cabo operaciones que
tarden en ejecutarse y no necesiten interactuar con el usuario o para suministrar una nueva
funcionalidad a otras aplicaciones.
A continuacin, se muestra un esquema con los mtodos que invoca Android cuando
lanzamos un servicio segn su modo de funcionamiento:
360
Una Actividad puede iniciar un servicio en modo Autnomo a travs del mtodo
StartService() y detenerlo mediante el mtodo StopService(). Cuando lo hacemos, Android
invoca su mtodo onCreate(); despus, se invoca el mtodo onStartCommand() con los datos
proporcionados por la Intencin de la actividad.
En el mtodo startService() tambin podemos indicar como parmetro el
comportamiento del ciclo de vida de los servicios:
Si la actividad quiere interactuar con un servicio (modo Dependiente o Ligado) para, por
ejemplo, mostrar el progreso de una operacin, puede utilizar el mtodo bindService(). Para
esto, hay que usar el objeto ServiceConnection, que permite conectarse al servicio y devuelve
un objeto de tipo IBinder, que la actividad puede utilizar para comunicar con el servicio. Ms
adelante veremos en detalle cmo definir servicios en modo Ligado dentro de las aplicaciones
Android.
Para enviar un mensaje de difusin mediante una Intencin pendiente hay que usar su
mtodo getBroadcast(). Para iniciar una subactividad mediante una Intencin pendiente hay
que usar su mtodo getActivity().
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<receiver android:name="ReceptorLlamadas">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE">
</action>
</intent-filter>
</receiver>
</application>
...
<uses-permission android:name="android.permission.READ_PHONE_STATE">
</uses-permission>
362
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
String estado = extras.getString(TelephonyManager.EXTRA_STATE);
Log.w("ESTADO TELEFONO", estado);
if (estado.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
String numeroTelefono= extras
.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.w("NUMERO TELEFONO", numeroTelefono);
}
}
}
}
363
364
}
}
<receiver android:name="MiBroadcastReceiver"></receiver>
...
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
A continuacin, solo queda indicar en la actividad principal que se inicie una la cuenta
atrs:
365
int i = Integer.parseInt(texto.getText().toString());
// Cargamos el BroadcastReceiver
Intent intent = new Intent(this, MiBroadcastReceiver.class);
// Lo iniciamos como una Intencin pendiente
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 1, intent, 0);
// Creamos una alarma
AlarmManager alarmManager = (AlarmManager)
getSystemService(ALARM_SERVICE);
// Establecemos el tiempo de la alarma e indicamos el pendingIntent
que se debe ejecutar cuando acabe la cuenta
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (i * 1000), pendingIntent);
// Mostramos un mensaje indicando que comienza la cuenta atrs
Toast.makeText(this, "Inicio de Cuenta atrs de " + i + " segundos",
Toast.LENGTH_LONG).show();
}
}
Para cargar el servicio "Alarma" por defecto de Android, hemos usado el mtodo
getSystemService(), al que indicamos como parmetro el nombre del servicio al que
queremos acceder.
En el cdigo anterior podemos observar que hemos usado la clase AlarmManager
para acceder al servicio de gestin de alarmas. Con su mtodo set() se crea una nueva alarma
que salta pasados n segundos y que lanza, a continuacin, la intencin pendiente (es realidad
es una intencin que hereda los permisos de la actividad principal).
Esta intencin pendiente se forma a partir de una intencin normal que invoca
explcitamente la clase que recibe el mensaje y que transformamos en un mensaje de difusin
con el mtodo getBroadcast() de PendingIntent.
Si ejecutas el Ejemplo 3 de esta Unidad vers las siguientes pantallas:
366
Service {
367
368
}, 0, INTERVALO);
}
369
Como vamos a usar el servicio en modo Ligado, hemos definido el mtodo onBind() en
el cdigo Java anterior.
En el archivo AndroidManifest.xml debemos declarar el nuevo servicio:
<service android:name=".Servicio"></service>
370
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Para conectar con el servicio definido en la clase Servicio, hemos escrito la sentencia:
371
service: Intent que identifica el servicio al que queremos conectar. Este Intent
puede ser explcito (como en el ejemplo) indicando el nombre de la clase que
implementa el servicio o implcito sealando la accin que se define mediante
un IntentFilter de un servicio publicado en el sistema.
(servicio
normal
que
puede
ser
Desde Eclipse puedes abrir el proyecto Ejemplo 4 (Servicio) de la Unidad 7. Estudia el cdigo
fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el que hemos
definido un Servicio.
372
7.5
Tras obtener una referencia al objeto Toast a travs de este mtodo, usamos el
mtodo show() para mostrar el mensaje en la pantalla.
En el Ejemplo 5 de esta Unidad vamos a definir distintos tipos de Toast.
Desde Eclipse puedes abrir el proyecto Ejemplo 5 (Notificaciones) de la Unidad 7. Estudia el
cdigo fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el que
hemos usado distintos tipos de Toast.
Para comenzar, vamos a incluir un botn que muestre un Toast bsico cuando
hagamos clic sobre l:
374
}
});
375
}
});
376
android:padding="5dip" >
<ImageView android:id="@+id/imagen"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/info" />
<TextView android:id="@+id/mensajeLbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="#FFFFFF"
android:paddingLeft="10dip" />
</LinearLayout>
Para asignar este fichero de diseo (layout) a un Toast, hay que proceder de una
forma algo distinta a como lo hemos hecho en las anteriores notificaciones.
En primer lugar, hay que inflar el layout mediante un objeto LayoutInflater, como ya
hemos usado en varias ocasiones a lo largo del curso, para disear la interfaz de usuario. Una
vez construido el layout, modificamos los valores de los distintos componentes internos de ste
para mostrar la informacin.
En este ejemplo, modificamos el mensaje de la etiqueta de texto y asignamos
estticamente una imagen en el layout XML mediante el atributo android:src. Despus,
establecemos la duracin de la notificacin con el mtodo setDuration() y asignamos el layout
personalizado al Toast mediante el mtodo setView(). El cdigo fuente incluido en el tercer
botn del ejemplo tiene este aspecto:
377
Por ejemplo, cuando hay una llamada perdida en nuestro telfono, se muestra en un
lado el siguiente icono en la barra de estado:
Arrastrar
379
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notManager = (NotificationManager) getSystemService(ns);
// Creamos la notificacin
Notification notificacion = new Notification(icono, textoEstado, hora);
380
usando
al
atributo
flags
de
la
notificacin
con
el
valor
Notification.FLAG_AUTO_CANCEL.
Tambin podramos indicar que, al crearse la notificacin, el dispositivo suene, vibre o
se encienda el LED de estado presente en muchos dispositivos. Para ello, basta con aadir al
atributo defaults de la notificacin los valores DEFAULT_SOUND, DEFAULT_VIBRATE o
DEFAULT_LIGHTS.
//Para aadir sonido, vibracin y luces hay que descomentar estas sentencias
//notif.defaults |= Notification.DEFAULT_SOUND;
//notif.defaults |= Notification.DEFAULT_VIBRATE;
//notif.defaults |= Notification.DEFAULT_LIGHTS;
//Enviamos la notificacin
notManager.notify(ID_MEN_BARRA_NOTIF, notificacion);
381
382
7.6
Si has utilizado alguna vez un dispositivo Android, te habrs dado cuenta de que
algunas aplicaciones permiten desplazar pginas deslizando el dedo horizontalmente sobre la
pantalla. Por ejemplo, en la aplicacin del Android Market y en el visor de imgenes podemos
cambiar de pgina dentro de la misma aplicacin:
383
Al desplazar el dedo
cambia de pantalla.
se
C:\cursos_Mentor\Android\android-sdk-windows\extras\android\support\v4
A continuacin, aadimos la librera al Build Path haciendo clic con el botn derecho
del ratn sobre el archivo de la librera y eligiendo la opcin "Build Path->Add to Build Path"
del men desplegable:
385
La aplicacin que vamos a desarrollar consta de una Actividad que muestra un visor
sencillo de imgenes dentro del ViewPager. Para generar las pginas contenidas en este
ViewPager es necesario usar un objeto PagerAdapter, que se encarga de alimentar de
pginas al componente ViewPager.
Veamos las sentencias comentadas para crear la Actividad principal de la aplicacin:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Buscamos el ViewPager en el diseo main.xml
vPager = (ViewPager) findViewById(R.id.vPager);
// Creamos el adaptador de N Pginas y pasamos el contexto de la
aplicacin
vPagerAdapter = new CustomPagerAdapter(NUMERO_VIEWS, this);
// Asignamos el adaptador al ViewPager
vPager.setAdapter(vPagerAdapter);
386
@Override
public void onPageScrollStateChanged(int arg0) {
// No definimos nada en el evento al hacer scroll en la pgina
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// No definimos nada en el evento al hacer scroll en la pgina
}
}); // end setOnPageChangeListener
}
}
387
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/vPager"/>
</LinearLayout>
Como se trata de una Vista que se define en un paquete extra de Android, es necesario
incluir el nombre completo del mismo android.support.v4.view.ViewPager.
Luego, creamos el adaptador personalizado a partir de la clase PagerAdapter, para
que cree las pginas internas del ViewPager, devolviendo vistas segn vamos desplazando el
dedo horizontalmente por la pantalla:
/**
*
*
* @param collection La Vista (View) donde se almacena la pgina.
* @param position Nmero de pgina que debemos crear.
* @return Devuelve el objeto que representa la pgina.
388
No tiene por qu
389
/**
*
*
* @param collection La Vista (View) donde se elimina la pgina.
* @param position Nmero de pgina que debemos eliminar.
* @return object El mismo objeto creado en {@link #instantiateItem(View,
int)}.
*/
@Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((LinearLayout) view);
}
/**
*
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view==((LinearLayout)object);
}
/**
* Android invoca este mtodo cuando el cambio de una de las pginas se ha
completado.
*/
@Override
390
/**
* Mtodo que se invoca cuando Android indica que hay que recuperar el
estado de ejecucin
*/
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {}
/**
* Mtodo que se invoca cuando Android indica que hay que guardar el estado
de ejecucin
*/
@Override
public Parcelable saveState() {
return null;
}
/**
* Android invoca este mtodo cuando se inicia el cambio de una de las
pginas.
*/
@Override
public void startUpdate(View arg0) {}
}
imagen
usando
el
mtodo
getIdentifier(nombre_recurso,
tipo_recurso,
paquete_recurso).
Desde Eclipse puedes abrir el proyecto Ejemplo 6 (ViewPager) de la Unidad 7. Estudia el
cdigo fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el que
hemos usado un ViewPager.
Arrastrar
Cambio de pgina
392
Arrastrar
Cambio de pgina
Dependiente o Ligado (bind): ofrece una interfaz de tipo clienteservidor que permite a los componentes de una aplicacin interactuar
con l enviando peticiones y recibiendo su resultado. Un servicio ligado
slo se ejecuta mientras otro componente de la aplicacin est unido a
l.
393
del
dispositivo
Android
durante
unos
segundos
desaparece
automticamente sin requerir ningn tipo de actuacin por parte del usuario.
Los mensajes de notificacin de la barra de estado de Android se muestran en
la barra de estado de los dispositivos Android cuando recibimos un mensaje
SMS, hay actualizaciones disponibles, est el reproductor de msica funcionando,
etctera.
Para generar notificaciones en la barra de estado del sistema, hay que obtener una
referencia
al
servicio
de notificaciones
de
Android
usando
la
clase
NotificationManager.
El componente ViewPager permite disear aplicaciones que incluyen pginas que
se pueden desplazar deslizando el dedo horizontalmente sobre la pantalla.
Este componente ViewPager no forma parte de las clases por defecto del SDK de
Android. Est incluido en el paquete externo de Compatibilidad de Android.
394
ANDROID AVANZADO
NDICE
8.1 INTRODUCCIN ................................................................................... 397
8.2 CMO DEPURAR APLICACIONES ANDROID CON ECLIPSE ..... 397
8.2.1 Estableciendo Puntos de interrupcin (Breakpoints) ............... 399
8.2.2 Iniciar la depuracin (Debug) del cdigo .................................... 400
8.2.3 Datos de depuracin (Debug) del cdigo................................... 401
8.2.4 Desactivar la depuracin de cdigo ............................................ 403
8.2.5 Propiedades de los puntos de interrupcin ............................... 404
8.2.6 Puntos de interrupcin de excepciones ..................................... 405
8.2.7 Puntos de interrupcin de mtodo .............................................. 405
8.2.8 Puntos de interrupcin de clase (class) ..................................... 405
8.2.9 Finalizar la Depuracin del cdigo .............................................. 406
8.3 USO DE MAPAS EN APLICACIONES ANDROID ............................ 406
8.3.1 Preparacin del Entorno de programacin ................................ 407
8.3.2 Cmo incluir mapas en las aplicaciones Android ..................... 410
8.4 DESARROLLO DE APLICACIONES SENSIBLES A LA
ORIENTACIN DEL DISPOSITIVO .................................................... 418
8.4.1 Cambio de orientacin automtica.............................................. 420
8.4.2 Mantener la informacin del estado durante el cambio de
orientacin ...................................................................................... 424
8.4.3 Cambio de orientacin Manual ...................................................... 427
8.5 DESPLEGAR APLICACIONES ANDROID EN DISPOSITIVOS
VIRTUALES (AVD) O REALES ........................................................... 431
8.6 CMO PUBLICAR APLICACIONES EN EL ANDROID MARKET .. 435
8.6.1 Alta de cuenta de desarrollador en el Android Market ............. 435
8.6.2 Recomendaciones sobre aplicaciones para Android Market .. 439
8.6.2.1 Recomendaciones sobre aplicaciones para Android
Market .................................................................................... 439
Android Avanzado
8.1
INTRODUCCIN
8.2
397
Object o = null;
o.toString();
}
}
// Clase sencilla que implementa un contador
public class Contador {
Si ejecutas la aplicacin tal y como est, vers que aparece el siguiente mensaje de error:
398
Android Avanzado
Si haces clic en el botn "Force close", la aplicacin termina. Veamos cmo depurar
este programa que provoca un error.
8.2.1
marca en el cdigo fuente que indica al depurador del lenguaje en que estemos programando
que debe detener o pausar la ejecucin del programa para poder evaluar los valores asignados
a las variables y permitir al programador detectar errores en tiempo de ejecucin.
Para establecer puntos de interrupcin con Eclipse, hay que hacer clic en la opcin
"Toggle Breakpoint" del men desplegable que aparece si pulsamos el botn derecho del
ratn sobre el nmero de lnea del cdigo fuente correspondiente. Tambin podemos hacer
doble clic en este nmero de lnea para activar o desactivar esta opcin:
399
8.2.2
men principal de Eclipse. Tambin podemos usar la tecla rpida [F11] o usar el icono
del
men principal.
Si lo hacemos, a continuacin se instalar y se ejecutar la aplicacin en el dispositivo
virtual. Despus, Eclipse muestra el siguiente mensaje:
Contestaremos que s para cambiar el tipo de Perspectiva a "Debug", muy til para
depurar programas. A continuacin, cambiar la perspectiva de Eclipse as:
Y la ejecucin del programa se parar en la primera lnea del cdigo que tenga un
punto de interrupcin.
Podemos usar los siguientes atajos de teclado para depurar el programa:
400
Android Avanzado
Comando Descripcin
F5
F6
F7
La ejecucin sigue todas las sentencias de todos los mtodos o funciones que
formen nuestro programa. Es decir, ejecuta en secuencia todas las rdenes que
conforman el programa.
F8
Nota: tambin existen unos botones de acceso rpido que permiten ejecutar estas
rdenes. Observa la imagen siguiente:
8.2.3
401
Es posible tambin usar este men para cambiar las columnas que han de aparecer en
esta vista:
Adems, es posible utilizar la opcin "New Detail Formater" (men desplegable con el
botn derecho del ratn) para modificar la informacin mostrada sobre la variable. Por ejemplo,
como
el
texto
(posicin
de
memoria
de
una
variable)
402
Android Avanzado
8.2.4
Si pulsas este botn otra vez, los puntos de interrupcin se activarn de nuevo.
403
8.2.5
de este punto para, por ejemplo, establecer una condicin lgica de parada. En las
propiedades se puede, por ejemplo, activar el punto de interrupcin y parar la ejecucin del
programa slo cuando una variable tenga cierto valor o se cumpla cierta condicin.
Para acceder a las propiedades del punto de interrupcin, hay que hacer clic en la
opcin "Breakpoint Properties..." del men desplegable con el botn derecho del ratn sobre
el punto de interrupcin:
404
Android Avanzado
8.2.6
inicia una excepcin especfica. Para definir este tipo de punto de interrupcin, hay que hacer
clic en el icono de excepcin siguiente:
8.2.7
izquierdo del editor del mtodo correspondiente. Detiene el programa durante al ejecutar el
mtodo o, despus, al finalizar la ejecucin del mismo.
8.2.8
405
8.2.9
nuevo. Cuando hagamos alguna modificacin del cdigo fuente, aparecer el siguiente
mensaje para indicar que no se puede sustituir el cdigo de una aplicacin ya instalada en el
emulador de Android y se pregunta si deseamos desconectar ("Disconnect") el modo Debug:
Nota: en esta Unidad 8 puedes encontrar el vdeo Cmo depurar aplicaciones Android en
Eclipse, que muestra visualmente cmo llevar a cabo la depuracin del Ejemplo 1 de esta
Unidad.
8.3
406
Android Avanzado
8.3.1
que tenemos instalado el paquete correspondiente a las APIs de Google. Este paquete se
llama normalmente Google APIs by Google, Android API x, revisin y.
Al instalar el SDK de Android en Eclipse deberas haber aadido ya este paquete. Para
comprobar que est correctamente instalado, haz clic en el botn "Opens the Android SDK
Manager" de Eclipse:
407
Para acabar de crear el dispositivo virtual, hacemos clic en el botn "Create AVD".
Para poder utilizar la API de Google Maps es necesario obtener previamente una
clave de uso (API Key) que estar asociada al certificado con el que firmamos digitalmente las
aplicaciones. En el apartado "Permisos y Seguridad" de la Unidad 5 ya hemos hablado de
estos certificados, necesarios para firmar aplicaciones.
Si cambiamos el certificado con el que firmamos nuestra aplicacin, algo que
normalmente se hace como paso previo a la publicacin de la aplicacin en el Android Market,
tendremos que modificar tambin la clave de uso de la API.
Cuando compilamos una aplicacin en Eclipse y la probamos en el emulador de
Android, se aplica automticamente un certificado de depuracin creado por defecto. Por lo
tanto, para poder depurar en el emulador aplicaciones que hagan uso de Google Maps, hay
que solicitar una clave asociada a este certificado de depuracin.
En primer lugar, hay que localizar el fichero donde se almacenan los datos del
certificado de depuracin "debug.keystore". Podemos conocer la ruta de este fichero
accediendo a las preferencias de Eclipse, seccin "Android", apartado "Build":
408
Android Avanzado
una
ventana
de
lnea
de
comandos
en
el
directorio
C:\Program
Files
-keystore
409
Nota: Observa que hemos borrado intencionalmente parte de la clave, pues, cuando
solicites sta, te darn otra diferente.
Ya hemos terminado la preparacin del entorno de programacin para poder utilizar los
servicios de Google Maps dentro de nuestras aplicaciones Android.
8.3.2
mapa sobre el que podemos hacer unas operaciones sencillas, como cambiar a vista satlite o
desplazar el mapa.
Para poder ver este proyecto en tu emulador Android es necesario que obtengas la clave de
uso de la API de Mapas de Google y la cambies en el fichero de diseo main.xml de la interfaz
de usuario. Si no lo haces, arrancar la aplicacin del ejemplo pero no se mostrar el mapa,
como en la imagen siguiente:
410
Android Avanzado
Hay que tener en cuenta que, a la hora de crear el proyecto Android en Eclipse,
tenemos que seleccionar "Google APIs" en el campo "Build Target" en las propiedades del
proyecto:
Adems, tambin hemos establecido el atributo clickable a true, para que el usuario
pueda interactuar con el componente si quiere, por ejemplo, desplazar el mapa con el dedo.
Los componentes MapView slo se pueden utilizar desde una actividad de tipo
MapActivity. La clase MapActivity se extiende de la clase Activity y permite la gestin del
ciclo de vida de la Actividad y de los servicios de visualizacin de un mapas. De igual forma
que ListActivity se usa para mostrar listas, MapActivity se usa para mostrar mapas.
En el Ejemplo 2 la Actividad principal hereda la clase MapActivity, tal y como vemos
en el siguiente cdigo:
public class MapasActivity extends MapActivity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Obtenemos una referencia a las Vistas de la Actividad
mapa = (MapView)findViewById(R.id.mapa);
412
Android Avanzado
sateliteBtn = (Button)findViewById(R.id.SateliteBtn);
irBtn = (Button)findViewById(R.id.IrBtn);
animarBtn = (Button)findViewById(R.id.AnimarBtn);
moverBtn = (Button)findViewById(R.id.MoverBtn);
//Definimos el Controlador del mapa
controlMapa = mapa.getController();
// Definimos un nuevo punto de localizacin
GeoPoint loc = new GeoPoint(latitud.intValue(), longitud.intValue());
// Centramos el mapa en este punto
controlMapa.setCenter(loc);
// Hacemos zoon a 6 (puede tomar el valor de 1 a 21)
controlMapa.setZoom(6);
//Mostramos los controles de zoom sobre el mapa
mapa.setBuiltInZoomControls(true);
413
GeoPoint
loc
new
GeoPoint(latitud.intValue(),
longitud.intValue());
loc
new
GeoPoint(latitud.intValue(),
longitud.intValue());
414
Android Avanzado
setSatellite(true)
setStreetView(true)
setTraffic(true)
Tambin existen otros tres mtodos para consultar el estado de cada uno de estos
modos: isSatellite(), isStreetView() y isTraffic().
En el evento onClick del botn sateliteBtn hemos usado el mtodo setSatellite() para
intercambiar el modo satlite y el estndar.
Adems de los mtodos para personalizar el aspecto grfico del mapa, tambin
disponemos de varios mtodos para consultar la informacin geogrfica visualizada en el
mismo. Por ejemplo, podemos saber las coordenadas geogrficas en las que el mapa est
centrado actualmente
Como podemos observar en el cdigo anterior, las coordenadas del centro del mapa se
obtienen mediante el mtodo getMapCenter() en forma de objeto GeoPoint que encapsula los
valores de latitud y longitud expresados en microgrados (grados * 1E6). Los valores en la
magnitud
grados
se
pueden
obtener
mediante
los
mtodos
getLatitudeE6()
getLongitudeE6() respectivamente.
El nivel de zoom del mapa contiene un valor entero entre 1 y 21, siendo 21 el que
ofrece mayor nivel de detalle en el mapa.
Para modificar el centro del mapa, en primer lugar, debemos acceder al controlador del
mapa (MapController) mediante el mtodo getController(). Este mtodo devuelve un objeto
MapController con el que podemos modificar la posicin central del mapa. Para ello, podemos
usar los mtodos setCenter() y setZoom() a los que podemos indicar las coordenadas
centrales del mapa y el nivel de zoom deseado, respectivamente.
En este ejemplo hemos incluido un botn irBtn que centra el mapa sobre un punto
determinado y hemos aplicado un nivel de zoom (10), que permite distinguir en el mapa
algunos detalle. Si pruebas el ejemplo del curso, vers que el desplazamiento a la posicin y el
zoom al nivel indicados se hacen de forma instantnea sin ningn tipo de animacin.
Para mejorar la sensacin de movimiento en el mapa, la API de Google nos ofrece otra
serie de mtodos que permiten desplazar el mapa a una posicin especfica de forma
progresiva y aumentar o disminuir el nivel de zoom de forma animada. El mtodo
animateTo(GeoPoint) desplaza el mapa hasta un punto determinado y los mtodos zoomIn()
y zoomOut() aumentan o disminuyen de forma progresiva, respectivamente, en 1 el nivel de
zoom. En el botn animarBtn hemos usado este mtodo para desplazar de forma animada el
mapa.
Para acabar, disponemos de otro mtodo que permite desplazar el mapa un
determinado nmero de pixeles en cierta direccin, tal y como puede hacer un usuario con el
dedo sobre el mapa. Este mtodo se llama scrollBy() y recibe como parmetros el nmero de
pixeles que queremos desplazarnos en horizontal y en vertical. En el botn moverBtn hemos
usado este mtodo para desplazar el mapa automticamente.
Finalmente, ten en cuenta que, para ejecutar la aplicacin del ejemplo sobre el
emulador de Android, hay que modificar el fichero AndroidManifest.xml. Es necesario
especificar que hacemos uso de la API de Google Maps mediante la clusula <uses-library> y,
en segundo lugar, hay que solicitar los permisos de acceso a Internet mediante la clusula
<uses-permission>.
Veamos el aspecto que tiene este fichero:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="es.mentor.unidad8.eje2.mapas"
android:versionCode="1"
416
Android Avanzado
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:required="true"
android:name="com.google.android.maps">
</uses-library>
<activity
android:label="@string/app_name"
android:name=".MapasActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
Desde Eclipse puedes abrir el proyecto Ejemplo 2 (Mapas) de la Unidad 8. Estudia el cdigo
fuente y ejectalo para mostrar en el AVD el resultado del programa anterior, en el que hemos
utilizado un mapa.
417
8.4
Si has usado alguna vez un telfono con Android, vers que, al cambiar la orientacin
del mismo de vertical a horizontal y viceversa, normalmente se modifica el aspecto de la
aplicacin que ests usando distribuyndose las Vistas de la interfaz de usuario de forma
acorde.
Aunque a priori este cambio de orientacin del dispositivo parece sencillo, a veces los
desarrolladores de aplicaciones Android deben desarrollar complejos cdigos para controlarlo.
Este apartado describe cmo implementar esta funcionalidad.
Por ejemplo, si tenemos abierta la aplicacin de Contactos de Android y cambiamos la
orientacin del telfono de vertical a horizontal, la aplicacin modifica el aspecto de la interfaz
del usuario proporcionalmente:
418
Android Avanzado
ATENCIN
Para cambiar la orientacin del emulador de Android
[BLOQUE_NUM_7], [Ctrl+F11], [BLOQUE_NUM_9], [Ctrl+F12].
podemos
usar
las
teclas
Ten en cuenta que el cambio de orientacin puede tardar unos segundos en el emulador
dependiendo de la capacidad del PC con el que trabajes.
En el Ejemplo 3 de esta Unidad vamos a mostrar cmo funcionan las dos formas de
controlar el cambio de orientacin del dispositivo Android.
419
Por lo tanto, hay que probar el Ejemplo 3 de esta Unidad en otra versin de Android.
Tal y como hemos hecho para la versin 2.3.3 en la Instalacin del curso, hay que descargar
las libreras de Android 2.2 y crear el dispositivo virtual correspondiente:
Tambin puedes usar la versin de Android del curso teniendo en cuenta que puedes
cambiar al modo horizontal, pero no volver de nuevo al vertical.
8.4.1
orientacin de la pantalla del dispositivo. Consiste en crear una carpeta de diseo separada
(/res/layout) que contenga los archivos XML que determinan la interfaz de usuario en cada tipo
de orientacin.
Para definir el modo horizontal (landscape), hay que crear la carpeta res/layout-land.
Esta nueva carpeta contiene tambin el archivo main.xml:
420
Android Avanzado
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="10dp"
android:layout_marginTop="32dp"
android:text="Esta aplicacin muestra cmo
orientacin del dispositivo Android.
controlar
el
cambio
de
421
<Button
android:id="@+id/boton1"
android:layout_width="150px"
android:layout_height="60px"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView1"
android:layout_marginLeft="100dp"
android:layout_marginTop="93dp"
android:text="Botn" />
<EditText
android:id="@+id/editText"
android:layout_width="197dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/boton1"
android:layout_marginLeft="50dp"
android:layout_marginTop="150dp" />
</RelativeLayout>
<TextView
android:id="@+id/textView1"
422
Android Avanzado
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:text="Esta aplicacin muestra cmo
orientacin del dispositivo Android.
controlar
el
cambio
de
<EditText
android:id="@+id/editText"
android:layout_width="197dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/boton1"
android:layout_marginLeft="50dp"
android:layout_marginTop="70dp" />
</RelativeLayout>
423
Si no creas este archivo para el modo horizontal y ejecutas la aplicacin, vers que al
cambiar al modo horizontal desaparece el componente TextView:
8.4.2
orientacin del dispositivo virtual, vers que el texto escrito en este componente se mantiene
sin aadir nuevo cdigo Java.
En el apartado "Guardar y recuperar el estado de una Actividad" de la Unidad 3 hemos
estudiado que, cuando cambia la orientacin de la pantalla (vertical/horizontal), Android reinicia
la Actividad usando el mtodo OnDestroy() e inmediatamente llama de nuevo a onCreate().
Este comportamiento de reinicio est diseado para que la aplicacin se adapte a la nueva
configuracin de forma automtica, y as cambiar la posicin de los componentes.
424
Android Avanzado
425
Android Avanzado
guardar informacin usando el objeto de tipo Bundle. No permite guardar estructuras de datos
ms complejas, como objetos.
Para estos casos, podemos usar el mtodo onRetainNonConfigurationInstance().
Este mtodo se activa cuando una actividad est a punto de ser destruida debido a un cambio
de configuracin, como un cambio de orientacin de la pantalla. Este mtodo permite guardar
una estructura de datos devolviendo un objeto como resultado de su ejecucin. Fjate en el
siguiente ejemplo:
@Override
public Object onRetainNonConfigurationInstance()
{
// Devolvemos un objeto donde hemos guardado un estado de ejecucin
return(objeto);
}
Fjate que el mtodo anterior devuelve el tipo objeto (Object), lo que permite
prcticamente devolver cualquier tipo de dato.
Para extraer los datos guardados se puede usar dentro del mtodo onCreate() el
mtodo getLastNonConfigurationInstance(). Por ejemplo, as:
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Recuperamos el objeto original
Objeto objeto = (Objeto) getLastNonConfigurationInstance();
}
427
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- CUIDADO! Para que el cambio lo haga Android debemos permitirle que
gestione esta funcionalidad. Esto se consigue
quitando el atributo android:configChanges="orientation..." -->
<activity
android:label="@string/app_name"
android:name=".OrientacionActivity"
android:configChanges="orientation|keyboardHidden" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
428
Android Avanzado
"Cambio
a
horizontal",
Toast.LENGTH_SHORT).show();
setContentView(R.layout.main);
} else {
Toast.makeText(this,
"Cambio
a
vertical",
Toast.LENGTH_SHORT).show();
setContentView(R.layout.main);
}
//Obtenemos una referencia a las Vistas de la Actividad
et = (EditText)findViewById(R.id.editText);
//
Escribimos
orientacin
el
texto
que
tena
el
EditText
antes
del
cambio
de
et.setText(texto);
}
429
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
//Obtenemos una referencia al EditText de la Actividad
et = (EditText)findViewById(R.id.editText);
}
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".OrientacionActivity"
android:screenOrientation="landscape"
<intent-filter >
430
>
Android Avanzado
</manifest>
modo
8.5
DESPLEGAR
APLICACIONES
VIRTUALES (AVD) O REALES
ANDROID
EN
DISPOSITIVOS
Para arrancar manualmente un dispositivo virtual desde Eclipse hay que pulsar el
siguiente botn de la barra de herramientas:
Desde la ventana de
dispositivos
virtuales
seleccionamos
el
dispositivo
que
Adems, el dispositivo real debe estar configurado para admitir la instalacin de aplicaciones
sin firmar por el Android Market. Si accedes en Ajustes->Aplicaciones debes marcar la
siguiente opcin:
432
Android Avanzado
433
Tras obtener este identificador del emulador, vamos a instalar la aplicacin mediante el
comando adb -s identificador-del-emulador install nombre-fichero-apk. Fjate en el
siguiente ejemplo:
434
Android Avanzado
8.6
8.6.1
http://market.android.com/publish
En esta pgina introducimos el usuario y la contrasea de Google:
La primera vez que accedemos a la pgina se muestra un asistente para dar de alta
una nueva cuenta de desarrollador en el Android Market. Introducimos los datos que se
solicitan (nombre del desarrollador, correo electrnico, URL del sitio Web y nmero de
telfono). Despus, pulsamos el enlace "Seguir":
Para poder darnos de alta como desarrolladores del Android Market y publicar
aplicaciones, hay que abonar 25,00$. Se trata de una cuota nica sin caducidad. Para pagar
436
Android Avanzado
esta cuota podemos usar el servicio Google Checkout o pulsar en "Continuar" para pagar con
tarjeta de crdito:
437
Si todo est correcto, el asistente mostrar la siguiente ventana, indicando que "Su
pedido se ha enviado al Android Market". Para continuar con el proceso, pulsamos en el enlace
"Vuelve al sitio de desarrolladores de Android Market para completar el registro":
438
Android Avanzado
8.6.2
439
Es importante tener en cuenta que cuanto mayores sean los requisitos de hardware (cmara,
bluetooth, GPS, brjula, sensor de movimiento, etctera), la aplicacin ser visible e instalable
en un menor nmero de dispositivos Android.
8.6.2.2
Siempre hay que tener en cuenta que estamos desarrollando aplicaciones para
dispositivos con pantalla muy pequea, si son telfonos, lo que no ocurre en
los tablets, y teclado limitado, por lo que las aplicaciones deberan mostrar
pocos campos de texto y opciones reducidas.
440
Android Avanzado
Las aplicaciones deben ser rpidas. Si es necesario realizar algn proceso que
pueda tardar unos segundos, es recomendable avisar al usuario o, incluso,
usar hilos de ejecucin, servicios, etctera. El usuario de un dispositivo mvil
espera siempre rapidez de respuesta.
8.6.3
Market does not accept apks signed with the debug certificate. Create a new certificate
that is valid for at least 50 years. Market requires that the certificate used to sign the apk be
valid until at least October 22, 2033. Create a new certificate. Market requires the
minSdkVersion to be set to a positive 32-bit integer in AndroidManifest.xml.
Uno de los requisitos para poder publicar de aplicaciones en Android Market es
que el paquete de instalacin APK debe estar firmado con un certificado vlido de al
menos 25 aos. A continuacin, explicamos cmo hacerlo.
En primer lugar, una vez desarrollada y probada la aplicacin Android con Eclipse,
hacemos clic con el botn derecho del ratn sobre la carpeta del proyecto y seleccionamos la
opcin "Export" del men emergente:
441
442
Android Avanzado
444
Android Avanzado
Si hemos seguido bien los pasos anteriores, ya dispondremos del fichero APK firmado
con el certificado que podemos publicar en el Android Market:
8.6.4
https://market.android.com/publish/Home
Pulsamos en el enlace "Subir aplicacin":
445
446
Android Avanzado
Tras subirlo, pulsamos en el enlace "Activar" para introducir los datos necesarios para
publicar la aplicacin en el Android Market. Desde esta pgina podemos activar o desactivar la
publicacin de las aplicaciones subidas. Por ejemplo, si hemos detectado algn error y no
queremos que los usuarios se descarguen una aplicacin hasta solucionar el problema,
podremos desactivarla:
448
Android Avanzado
Informacin de contacto:
o
Sitio web.
Correo electrnico.
Telfono.
En la siguiente ventana se muestra parte de los datos que hay que incluir:
Una vez introducidos los datos, pulsamos en el botn "Guardar" de la parte superior
derecha. A continuacin, se comprueba si los datos son completos y correctos y, si no hay
errores, se guardarn los datos asociados al archivo APK.
449
450
Android Avanzado
451