Android

294
Android: Programación de dispositivos móviles a través de ejemplos José Enrique Amaro Soriano zf\ Alfaomega marcombo e dic io ne s c n ic a s

Transcript of Android

Page 1: Android

Android: Programación de dispositivos

móviles a través de ejemplos

José Enrique Amaro Soriano

zf\ Alfaomega

marcombo e d i c i o n e s t é c n i c a s

Page 2: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 7

ÍNDICE GENERAL

1. ......................................................................................................................................... INTRODUCCIÓN .......................................................................................................................11

1.1. Acerca de este libro ............................................................................................. 11

1.2. .................................................................................... A quién va dirigido ................. !

...................................................................................... 11

1.3. Resumen de los contenidos ................................................................................ 12

1.4. ......................................................................................................................................

Requerimientos ............................................................................................................... 13

1.5. Créditos y Agradecimientos ............................................................................... 14

2. ESCRIBIR Y MANIPULAR TEXTO ................................................................................15

2.1. Actividad básica: Hola Android ............................................................................ 15

2.2. Color de fondo y formato del texto ....................................................................... 16

2.3. Modificando el texto desde Java.......................................................................... 18

2.4. Modificando el color desde Java.......................................................................... 19

2.5. Añadir texto adicional con addView ..................................................................... 20

2.6. Definir un método print() ...................................................................................... 21

2.7. Escribiendo resultados de operaciones ............................................................... 23

2.8. Ejemplo: una tabla del seno ................................................................................ 25

2.9. Añadir texto con Append() ................................................................................... 25

2.10. ....................................................................................................................................

Extendiendo la pantalla con ScrollView .......................................................................... 26

3. BOTONES ............................................................................................................................29

3.1. Definición de un botón en el layout ...................................................................... 29

3.2. Caso de dos botones ........................................................................................... 32

3.3. Uso de Toast para mostrar un mensaje emergente............................................. 34

3.4. Cambiar el texto de un botón ............................................................................... 36

3.5. Cambiar el color de los botones .......................................................................... 37

3.6. Calculadora ......................................................................................................... 39

4. INTRODUCCIÓN DE TEXTOS ........................................................................................47

4.1. TextField .............................................................................................................. 47

4.2. OnKeyListener ..................................................................................................... 49

4.3. Forma alternativa de implementar OnKeyListener............................................... 52

5. GUARDAR DATOS CON SharedPreferences ..................................................................54

6. ACTIVIDADES ....................................................................................................................59

6.1. Uso de Intent para iniciar actividades .................................................................. 59 6.2. Pasar valores numéricos entre actividades ......................................................... 62

7. MANEJO DE FICHEROS ..................................................................................................64

7.1. Escribir datos en un fichero en la tarjeta SD ........................................................ 64 7.2. Leer un fichero en el directorio res ...................................................................... 67

Page 3: Android
Page 4: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS Df; I .ir MPLOS

8. GRÁFICOS ........................................................................................................... 70

3.1. .....................................................................................................................................

Dibujando en un Canvas ............................................................................................... 70

3.2. .....................................................................................................................................

Formato del texto .......................................................................................................... .72

8.3. .....................................................................................................................................

Altura del canvas ............................................................................................................ 74

8.4. .....................................................................................................................................

Dimensiones del canvas .............................................................................................. .76

8.5. .....................................................................................................................................

Formas geométricas ...................................................................................................... 78

8 6. Curvas ..................................................................................................................... 80

8.7. .....................................................................................................................................

Traslaciones y rotaciones ............................................................................................... 82

8.8. .....................................................................................................................................

Texto siguiendo una curva ............................................................................................. 83

8.9. .....................................................................................................................................

Caracteres Unicode ....................................................................................................... 85

8.10. ...................................................................................................................................

LayoutParams ................................................................................................................ 87

9. GRÁFICOS INTERACTIVOS ................................................................................ 91

9.1. .....................................................................................................................................

Evento ACTION_DOWN ................................................................................................ 91

9.2. .....................................................................................................................................

Evento ACTIONJJP ....................................................................................................... 93

9.3. .....................................................................................................................................

Evento ACTION_MOVE ................................................................................................. 94

9.4. .....................................................................................................................................

Dibujar en la pantalla ..................................................................................................... 96

9.5. .....................................................................................................................................

Mover objetos ................................................................................................................. 98

10. IMÁGENES ......................................................................................................... 101

10.1. ...................................................................................................................................

Insertar una imagen en el layout .................................................................................. 101

10.2. ...................................................................................................................................

Controlando las imágenes en Java .............................................................................. 102

10.3. ...................................................................................................................................

Botones con imágenes ................................................................................................. 106

10.4. ...................................................................................................................................

Insertar imágenes en un canvas .................................................................................. 110

10.5. ...................................................................................................................................

Ajustar imagen a las dimensiones de la pantalla ......................................................... 113

11. REPRODUCIR SONIDO ..................................................................................... 116

11.1. ...................................................................................................................................

Page 5: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS Df; I .ir MPLOS

Uso de MediaPlayer ..................................................................................................... 116 11.2. ................................................................................................................................... Reproducir efectos de sonido ...................................................................................... 117

12. APLICANDO TEMAS .......................................................................................... 121

12.1. ...................................................................................................................................

Tema por defecto ......................................................................................................... 121

12.2. ...................................................................................................................................

Tema NoTitleBar .......................................................................................................... 123

12.3. ...................................................................................................................................

Tema Dialog ................................................................................................................. 124

12.4. ...................................................................................................................................

Tema Light ................................................................................................................... 125

13. RECURSOS ...................................................................................................... 127

13.1. ...................................................................................................................................

El recurso string ........................................................................................................... 127

13.2. ...................................................................................................................................

El recurso color ............................................................................................................ 129

13.3. ...................................................................................................................................

Usando recursos en un Layout .................................................................................... 131

14. HILOS Y CONTROLADORES ............................................................................ 137

14.1. ................................................................................................................................... Ejecuciones en background con Thread ...................................................................... 137 14.2. ................................................................................................................................... Diálogos de progreso ................................................................................................... 141

Page 6: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 9

14.3. .................................................................................................................................... Interfaz Runnable ......................................................................................................... 145 14.4. .................................................................................................................................... Notificaciones ............................................................................................................ 149

15. ANIMACIONES .................................................................................................... 155

15.1. ....................................................................................................................................

Movimiento uniforme. La bola botadora ........................................................................ 155

15.2. ....................................................................................................................................

Movimiento acelerado. La bola botadora II ................................................................... 159

15.3. ....................................................................................................................................

Conservación de la energía .......................................................................................... 161

15.4. ....................................................................................................................................

Simulación de caída con ligadura ................................................................................. 163

APÉNDICE A ................................................................................................................ 173

ELEMENTOS DE JAVA ................................................................................................ 173

A.1. Programa básico de Java con Android .................................................................. 173

A.2. Variables ................................................................................................................ 177

A.3. Conversión de variables ........................................................................................ 179

A.4. Operaciones con variables .................................................................................... 181

A.5. Funciones matemáticas ......................................................................................... 183

A.6. Bloque if-else ......................................................................................................... 186

A.7. Bucles for ............................................................................................................... 188

A.8. Bucle while ............................................................................................................ 189

A.9. Bloques switch ....................................................................................................... 192

A. 10. Métodos .............................................................................................................. 193

A.11. Clases y objetos .................................................................................................. 196

A.12. Sub-clases ........................................................................................................... 203

A. 13. Variables y métodos estáticos y finales .............................................................. 206

A. 14. Arrays ................................................................................................................. 208

A.15. Arrays 2D ............................................................................................................. 210

A.16. Cadenas .............................................................................................................. 213

A. 17. Formato numérico ............................................................................................... 217

A. 18. Manejo de Excepciones ...................................................................................... 220

A. 19. Interfaces ............................................................................................................ 223

A.20. Clases anónimas ................................................................................................. 227

A.21. Otras características de Java .............................................................................. 232

A.21.1. Paquetes........................................................................................................... 232

A.21.2. Clases públicas ................................................................................................. 232

A.21.3. Privilegios de acceso de los métodos y variables ............................................. 232

A.......................................................................................................................................... 2

1.4. Clases y métodos abstractos ................................................................................. 233

APÉNDICE B ................................................................................................................ 234

HERRAMIENTAS DE DESARROLLO DE ANDROID ................................................... 234

B.......................................................................................................................................... 1

. Eclipse ....................................................................................................................... 234

Page 7: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 10

B.1.1. Problemas en la instalación ................................................................................ 234

B.1.2. Importar una clase Java de otro proyecto ........................................................... 234

B.1.3. Importar un proyecto completo ya existente ....................................................... 235

B. ......................................................................................................................................... 2

. Android Virtual Device (AVD) ...................................................................................... 236

B. ......................................................................................................................................... 3

. Dalvik Debug Monitor Server (DDMS)......................................................................... 236

Page 8: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS ()( I .II MI ’I.0S

B. 4. Instalar driver dispositivo Android de Samsung en Linux (Ubuntu Jaunty) ............................................................................................................... 237

APÉNDICE C ............................................................................................................................ 238

APLICACIONES ............................................................................................................238

C. ........................................................................................................................................ 1

. Interacción neutrón-protón .......................................................................................... 238

C. ........................................................................................................................................ 2

. Ajuste por mínimos cuadrados .................................................................................... 243

C. ........................................................................................................................................ 3

. Energía del Helio-4 ..................................................................................................... 257

BIBLIOGRAFÍA ....................................................................................................................... 267

1. INTRODUCCIÓN

1.1. Acerca de este libro

Aunque el sistema operativo Android tiene apenas unos años de vida, la librería Java de

Android consiste ya en más de 150 paquetes (APIs), que contienen miles de clases,

métodos, interfaces y constantes. Todas estas clases están documentadas en la página

web de Android Developers. La vasta extensión del software de desarrollo de Android

(SDK) puede resultar extremadamente abrumadora para el que se acerca por primera vez a

este sistema, especialmente si también es nuevo en el lenguaje de programación Java. La

bibliografía existente tiende a estar dirigida a profesionales y los pocos libros introductorios

están enfocados a construir completas aplicaciones de telefonía, que por su extensión y

complejidad contribuyen a incrementar la frustración del principiante. En muchos casos se

requiere un conocimiento avanzado de Java. Los manuales de Android ilustran todo tipo de

aplicaciones para controlar sensores, enviar SMS, utilizar el GPS, acceso a servicios de

internet, juegos, telefonía, fotografía, video, música, etc. Pero en general se pasa por alto

que los dispositivos Android son verdaderos ordenadores que pueden utilizarse también

para cálculo numérico y aplicaciones científicas y técnicas, tanto para docencia como para

uso profesional e investigación. Con Android es posible realizar aplicaciones de cálculo y

literalmente llevárselas en el bolsillo.

En este libro pretendemos hacer un acercamiento distinto a Android. No introduciremos

toda la artillería de Android necesaria para escribir complejas aplicaciones de calidad

profesional para publicarlas en el mercado Android. Se trata de presentar en pocas páginas

las herramientas necesarias para poder realizar en poco tiempo programas sencillos de

computación para uso científico y técnico, aunque no se descartan otras aplicaciones en los

estudios, en el trabajo, artísticas o, simplemente, para ocio o disfrute personal.

1.2. A quién va dirigido

Este libro está dirigido al principiante con escasos o nulos conocimientos de Java, que

quiere escribir rápidamente programas para uso personal. En particular, podrán

beneficiarse de este libro los estudiantes, profesores, científicos o profesionales de

cualquier tipo, con conocimientos previos de algún lenguaje de

Page 9: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

Page 10: Android
Page 11: Android

12 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS Df I .II IMPIOS

programación, que pretendan utilizar sus dispositivos Android para ejecutar sus propias

aplicaciones.

Siguiendo la filosofía de que un ejemplo vale más que mil palabras, introducimos los

conceptos mediante ejemplos que consisten en pequeñas aplicaciones que ilustran algún

aspecto concreto de Android. Todos los ejemplos se acompañan con capturas de la

pantalla. El resultado es un acercamiento rápido y práctico al sistema.

1.3. Resumen de los contenidos

En las primeras noventa páginas (capítulos 2 a 8), se introducen los conceptos esenciales

para escribir completas aplicaciones Android con funciones de entrada y salida de datos,

lectura y escritura de ficheros, y herramientas gráficas, utilizando sólo un pequeño conjunto

de clases y métodos de la librería de Android. A continuación, se introducen otras

herramientas no esenciales, aunque igualmente asequibles, como gráficos interactivos

(capítulo 9), manejo de imágenes (capítulo 10), sonido (capítulo 11), temas (capítulo 12) y

recursos (capítulo 13). El capítulo 14 introduce ya conceptos más avanzados, incluyendo

procesos, controladores, diálogos de progreso y notificaciones. Finalmente el capítulo 15

describe cómo realizar animaciones gráficas, con aplicación directa a simulaciones.

El libro se complementa con un apéndice de introducción al lenguaje de programación

Java, usando exclusivamente Android (apéndice A). El lector que no conozca Java podrá

adquirir las nociones básicas de este lenguaje estudiando el apéndice A, a la vez que

avanza en el estudio del capítulo 2.

Aunque en este libro no se describe el software específico para desarrollo de Android

(editores, compiladores, emuladores, etc), el apéndice B contiene algunas notas sobre el

uso de estas herramientas, que pueden ser útiles en algún momento.

Finalmente, en el apéndice C aplicamos los conceptos y técnicas introducidas en este

libro para realizar un programa completo de cálculo científico.

Algunos de los ejemplos de este libro pueden descargarse de la página web del autor:

http://www.ugr.es/~amaro/android

Estas aplicaciones podrán ser instaladas directamente en un dispositivo Android, o podrán

ser examinadas y modificadas por el usuario, puesto que se proporciona su código fuente.

Para poder seguir los ejemplos de este libro, el lector debe instalar el Android Software

Development Kit (SDK) en su ordenador. Este software funciona con todos los sistemas

operativos y se puede descargar gratuitamente de la página web de Android Developers:

http://developer.android.com/sdk/index.html

La instalación del Android SDK está perfectamente documentada siguiendo los links de

dicha página, o directamente en:

Page 12: Android

1.4. Requerimientos

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE fcJtMPLOS 13

http://developer.android.com/sdk/installing.html

En particular, puesto que Android utiliza Java, también será necesario instalar previamente

el kit de desarrollo de Java, o JDK (Java Development Kit) de la página web de Oracle:

http://www.oracle.com/technetwork/java/javase/downloads/index.htmi

Se recomienda seguir los ejemplos de este libro usando el programa Eclipse. Eclipse

es un entorno de desarrollo interactivo (IDE) que facilita el desarrollo de aplicaciones Java y

Android. Permite editar, compilar, ejecutar y depurar las aplicaciones Android. Eclipse es

gratuito y se descarga de la página de Eclipse Foundation:

http://www.eclipse.org

Además, Eclipse importa automáticamente los paquetes de Java necesarios para nuestra

aplicación y permite corregir sobre la marcha errores de programación.

En la página de Android Developers se explica cómo crear una nueva aplicación de

Android usando Eclipse. En particular, recomendamos encarecidamente, como primer

paso para programar en Android, visitar primero la siguiente página, donde se

documenta con todo detalle cómo crear la aplicación básica de Android hello-world:

http://developer.android.com/resources/tutorials/hello-world.html

Siguiendo todas las instrucciones indicadas en esta página, el lector será capaz de ejecutar,

desde Eclipse, su primera aplicación de Android en el emulador, la cual será el punto de

partida del capítulo 2.

Page 13: Android

1.5. Créditos y Agradecimientos

14 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

El material de este libro fue inicialmente concebido para un proyecto de innovación docente

de la Universidad de Granada, dirigido por el autor en el Departamento de Física Atómica,

Molecular y Nuclear.

Sus contenidos conforman también el material didáctico para un curso de la Escuela de

Posgrado de la Universidad de Granada, titulado Desarrollo de Aplicaciones de Android

para Científicos. El curso está dirigido a universitarios de las ramas de Ciencias, Ingenierías

y Arquitectura y tiene una carga lectiva de 75 horas totales y 30 horas presenciales,

correspondientes a 3 créditos ECTS.

Todos los programas y ejemplos son originales del autor. Todas las fotografías, excepto

las indicadas, son propiedad del autor.

Las fotografías de los físicos Bohr, Plank, Pauli y Schrödinger utilizadas en el ejemplo

8.3 están en el dominio público y han sido descargadas de la Wikipedia, donde están

almacenadas como archivos de Wikimedia Commons.

Todos los dibujos y gráficos son obra del autor.

Agradezco a Enrique Ruiz Arrióla y Rodrigo Navarro su permiso para adaptar a Android

y publicar en el Apéndice C el programa de ajuste de la interacción neutrón-protón y el

cálculo de la energía del núcleo de helio-4. Dicho programa ha sido realizado en el ámbito

del proyecto de investigación del Plan Nacional de l+D+i, del Ministerio de Ciencia e

Innovación, titulado Dinámica de Sistemas Hadrónicos en Física Nuclear a Energías

Intermedias.

Finalmente, agradezco a Miguel Ángel por haber convertido a Word todo el libro desde

su formato original en LaTeX.

2. ESCRIBIR Y MANIPULAR TEXTO

2.1. Actividad básica: Hola Android

Comenzamos examinando el siguiente listado del programa por defecto generado por Eclipse

al crear un nuevo proyecto android. Se trata de escribir el mensaje “Hola Android” en la

pantalla. En este programa básico se define la clase Activity, que contiene el método

onCreate () que se ejecuta cuando se crea la actividad (ver la sección A.1 en el apéndice

para una explicación detallada de los elementos Java de esta actividad)

package prueba.android.hello;

import android.app.Activity;

Page 14: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 15

public class Hello extends Activity {

/** Called when the activity is first created. 1/

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); }

}

Lo que hace la ultima instrucción del programa anterior

setcontentview (R. layout .main), es “inflar” la vista de la pantalla (o “layout”).

Esta vista está definida en el fichero main.xml, al que hace referencia la variable R.

layout. main.

<?xml version="l.0" encoding="utf-8"?>

<LinearLayout xmlns:android=

"http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

androi d:1ayout_wi dth="f i1l_parent"

1 Cambiar el color de fondo a blanco en lugar de negro añadiendo el modificador

android:background = a la etiqueta

LinearLayout.,

• Cambiar el color del texto a negro añadiendo en Textview el modificador

android: textColor = "#000000".

• Cambiar el tamaño del texto a 24 puntos con android: textsize =

"24sp".

Page 15: Android

16 ANDROID: PROGRAMACIÓN OE DISPOSITIVOS MÓVILES A TRAVÉMH I II MPLOS

android:layout_he ight ="wr ap_con c

enr" android:text="Hola Android" / >

</LinearLayout>

La cadena de texto que queremos escribir en la pantalla se define en este fichero xml

mediante TextView android:text="Hola Android". El resultado de ejecutar este

proyecto en el emulador de android (AVD) se muestra en la figura 2.1.

ra ase 2:41 PM |

2.2. Color de fondo y formato del texto

A partir del fichero main.xml del ejemplo anterior podemos añadir otras propiedades de

formato para modificar la presentación y el formato del texto. Por ejemplo, podemos:

• Centrar el texto mediante android: layout_gravity = "center". Nótese que

para que esto surta efecto debemos definir la anchura de Textvie'w igual a la

anchura del texto que contiene mediante android: layout_width =

“wrap_content", ya que con fill_parent se considera el texto igual de

ancho que el Layout, que a su vez es igual de ancho que la pantalla y no es posible el

centrado.

Figura 2.1. Hola Android.

ES Si US 7:03 PM i Helio

Hola Android

Page 16: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 17

Figura 2.2. Hola Android en negro sobre blanco.

Con todos estos cambios el fichero main.xml quedaría de la siguiente forma:

<?xml version=111. 0 " encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#ffffff" android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:layout_width="wrap_content"

android:layout_gravity="center"

android:layout_height="wrap_content"

android:textColor="#00000 0"

android:textSize="24sp"

android:text="Negro sobre blanco Android" /> El resultado puede verse en la figura 2.2.

2.3. Modificando el texto desde java

La cadena de texto que se muestra en pantalla está definida en el fichero de layout

main.xml. Podemos modificarla desde java. Para ello primero añadimos una etiqueta (o

ID) al texto Textview en el archivo xml:

<TextView

android:id="@+id/myTextView"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:textColor="#000000" android:t

ext S i z e="2 0 sp" android:text="Hola

Android" />

Aqui hemos añadido la linea android:id y el texto quedará identificado mediante la

etiqueta myTextview. A continuación en la clase Activity del código java escribimos la

siguiente instrucción que define un objeto Textview asociado a la id myTextview que

hemos indicado en main.xml:

Textview myTextView=(Textview) findViewByld(R.id.myTextview);

El método f indViewByld () aplicado a variable R. id.myTextview se encarga

de localizar el bloque en main.xml asociado a Textview. A continuación, definimos otro

texto con el método setText ():

myTextview.setText(

"He modificado Textview con un nuevo texto" +

"usando java");

Page 17: Android

18 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVf B DF FJEMPLOS

El programa java quedaría así:

package prueba.android.hello;

import android.app.Activity;

import android.os.Bundle; import android.widget.Textview;

public class Hello extends Activity {

(»Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Textview myTextView=

Page 18: Android

ANDROID; PROGRAMACIÓN DE DISPOSITIVOS MÓVIII 3 A TRAVÉS DF EJt MPLOS

(TextView) findViewByld(R.id.myTextView);

myTextView. setText {

"He modificado TextView con un nuevo texto " +

"usando java"); }

}

Y el resultado se puede ver en la figura 2.3. setText () no modifica el texto que hay

escrito en el fichero main.xml, sólo el que se muestra en la pantalla del teléfono.

Q¡ íjffii©6:31 PM Helio

He modificado TextView con un

nuevo texto usando java

Figura 2.3. Texto modificado con setText().

2.4. Modificando el color desde Java

También se pueden modificar otras propiedades del texto con java. Por ejemplo,

setTextColor () para cambiar el color. Así, añadiendo la siguiente instrucción definiríamos

el texto rojo:0

myTextView.setTextColor(Color.argb(255,255,0,0)) ;

El método Color .argb (alpha, red, green,blue) construye el color

asociado a las componentes de alpha (transparencia), rojo, verde y azul, que son números

enteros entre 0 y 255. El resultado se ve en la figura 2.4.

Page 19: Android

20 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

Figura 2.4. Texto de color con setTextColor().

2.5. Añadir texto adicional con addView

Para añadir nuevo texto a un layout usamos el método LinearLayout. addview

(Textview) . Para ello debemos definir un nuevo objeto de tipo Textview mediante:

Textview tv=new Textview(this);

y sus propiedades, por ejemplo, color y tamaño:

tv. setTextColor (Color. argb (255,0,0,0) ) ,-

tv.setTextSize(40) ;

y finalmente el texto a escribir:

tv.setText("añadiendo nuevo texto con addview");

Este objeto se debe añadir al layout que debemos definir previamente mediante:

LinearLayout 11 =

(LinearLayout)findViewByld(R.id.myLinearLayout);

11.addview(tv);

Qj SAB« 7;01 PM 1 H* 1 He modificado Textview con un nuevo

texto usando java

Page 20: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII f=S A TRAVÉS l)f I .11 MPLOS 21

donde f indViewByld (R. id.myLinearLayout) se refiere a la id del layout que

habremos definido en el fichero main. xml:

<LinearLayout

android:id="@+id/myLinearLayout"

>

|j) 11:39 AM

He modificado TextView con un nuevo texto usando java

añadiendo

nuevo texto

con addView

Figura 2.5. Añadiendo nuevo texto al layout.

El código completo para añadir un texto a un layout queda como sigue:

TextView tv=new TextView(this);

tv.setTextColor(Color.argb(255,0,0,0));

tv.setTextSize(40) ;

tv.setText("añadiendo nuevo texto con addView");

LinearLayout 11=

(LinearLayout)findViewByld(R.id.myLinearLayout);

11.addView(tv);

y el resultado puede verse en la figura 2.5.

2.6. Definir un método print()

El código del ejemplo anterior habrá que repetirlo cada vez que queramos añadir un nuevo

texto al layout. Para simplificar la escritura podemos definir un método

print (Layout, string) para añadir un texto a un layout. Esto nos permite ilustrar

también el normal uso de Java en Android. Por ejemplo, añadimos el siguiente método a

nuestra actividad:

Page 21: Android

22 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A IHAVÍ S DI I JEMPLOS

public void print(LinearLayout 11, String texto){

TextView tv=new TextView(this);

tv.setTextColor(Color.argb(255,0,0,0));

tv.setTextSizs(18); tv.setText(texto);

11.addView(tv);

}

de manera que para añadir un texto al layout nos basta llamar a este método:

LinearLayout 11 =

(LinearLayout)findViewByld(R.id.myLinearLayout);

print(11,"Añadiendo texto al layout usando el método print()"

+" que hemos definido");

Además, podemos definir un método print () alternativo añadiendo parámetros para

escribir el texto con un tamaño y un color dados:

public void print(LinearLayout 11, String texto, int size, int

r, int g, int b){

TextView tv=new TextView(this);

tv.setTextColor(Color.argb(255,r,g,b));

tv.setTextSize(size); tv.setText(texto);

11.addView(tv); }

Ya podemos ejecutar este método cuanto queramos con distintos tamaños y colores, por

ejemplo:

LinearLayout 11 =

(LinearLayout)findViewByld(R.id.myLinearLayout);

print(11,"text aize 18 red ",18,255,0,0); print(11,"text size

24 green ",24,0,255,0); print(11,"text size 28 blue

",28,0,0,255); print(11,"text size 32 amarillo ",32,255,255,0);

print(11,"text size 28 magenta ",28,255,0,255); print(11,"text

size 24 cyan ",24,0,255,255);

El resultado se muestra en la figura 2.6. ! □ '»BU® 12:24 PM

Hullo ; -

He modificado TextView con urt nuevo

sexto usando Java

text size 18

red text size 24

green text size 28

blue

Page 22: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I S A TRAVÉS DE EJEMPLOS 23

text size 28 magenta

text size 24 cyan

Figura 2.6. Resultado de escribir usando la función print().

2.7. Escribiendo resultados de operaciones

Utilizando setTex podemos escribir cualquier texto o el resultado de cualquier operación

matemática, por ejemplo:

double a-2.25;

double b=l.

25; double

c=a+b;

tv.setText("La suma de "+ a + " mas " + b + " es " + c );

Aunque setText admite sólo cadenas, estas se pueden concatenar con números

usando el signo +. También podemos aprovechar la función printO definida en el

ejemplo anterior. Aquí tenemos el programa Helio modificado para escribir el resultado

de una operacion:

public class Helio extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView myTextView =

(TextView)findViewByld(R.id.myTextView);

myTextView.setText(

"Ejemplo de resultados de operaciones matemáticas" +

"usando java");

double a=2.25;

double b=1.25;

double c=a+b;

LinearLayout 11 =

(LinearLayout)findViewByld(R.id.myLinearLayout);

print(11,

"La suma de "+ a + " mas " + b + " es " + c); }

public void print(LinearLayout 11, String texto){

Page 23: Android

myTextView.setTextColor(Color.argb(255,255, 0> 0}) ;

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS 111 I .II MPLOS

TextView tv=new TextView(this);

tv.setTextColor(Color.argb(255,0,0,0));

tv.setTextSize(18);

tv.setText(texto);

11.addView(tv); }

}

El resultado se puede ver en la flgura 2.7.

[5 SBB« 12:46 PM

Hello

Ejemplo de resultados de operaciones

matemáticasusando java

La suma de 2.25 mas 1.25 es 3.5

Figura 2.7. Resultado de operaciones matemáticas.

Page 24: Android

AI II iHi )ll) PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 25

2.8. Ejemplo: una tabla del seno

Otro ejemplo, en lugar de la simple suma anterior, escribamos una tabla de la función seno

entre 0 y 1

LinearLayout 11=

(LinearLayout)findViewByld(R.id.myLinearLayout);

print(ll,"\n Tabla de sin(x):\n"); for(int i=0;i<10;i++){

double x=i/10.0; double sx=Math.sin(x);

print(ll, "sin( " + x + " ) = " + sx); }

El resultado está en la figura 2.8. El símbolo \n indica nueva línea. Recordamos además

en este ejemplo cómo se realiza un ciclo repetitivo en Java usando for ().

[5j SU® 12:56 PM Hello

Ejemplo de resultados de

operaciones matemáticas usando

¡ava

Tabla de sin(x):

sin( 0.0) = 0.0

sin( 0.1 >=0.09983341664682815 5¡n(

0.2 ) = 0.19866933079506122 sin( 0.3 )

= 0.29552020666133955 sin( 0.4 ) =

0.3894183423086505 sin( 0.5 ) =

0.479425538604203 S¡n( 0.6 ) =

0.5646424733950354 sin( 0.7 ) =

0.644217687237691 sin( 0.8 ) =

0.7173560908995228 sin( 0.9 ) =

0.7833269096274834

Figura 2.8. Resultado de operaciones matemáticas. Tabla del seno.

1.9. Añadir texto con AppendQ

8« puede añadir texto a un objeto TextView usando el método append(). Por njnmplo:

Page 25: Android

public class HolaAndroid2 extends Activity [

26 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

View v=findViewByld(R.id.myTextView);

TextView myTextView=(TextView) v;

myTextView.setText("Texto 1 definido con setText");

myTextView.append("\n Texto 2 con append")?

myTextView.append("\n Texto 3 con append");

myTextView.append("\n Texto 4 con append"); } }

El resultado se muestra en la figura 2.9.

IISI ©2:34 PM

HolaAndroid2

Texto 1 definido con setText

Texto 2 con append Texto 3

con append Texto 4 con

append

Figura 2.9. Añadir texto a un textView con appendQ.

2.10. Extendiendo la pantalla con ScrollView

Si vamos a escribir mucho texto en un Layout, llega un momento en que aquél se sale

de la pantalla y ya no es posible verlo, aunque el texto en teoría está ahí (de

forma virtual). Para remediar esto, se puede insertar el layout dentro de un

Scrollview, que permite mover la vista hacía arriba o hacia abajo a lo largo del layout.

Por ejemplo, la siguiente actividad escribe una tabla de la función seno con cien puntos, que

llega a salirse de la pantalla:

Page 26: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILI S A TRAVÉ H Ut I Jl MPI.OS 27

public class HolaAndroid.2 extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

View v=findViewByld(R.id.myTextView);

TextView myTextView=(TextView) v;

for(double x=0; x<l; x=x+0.01){ double

y=Math.sin(x);

myTextView.append("sin("+x+") = "+y+"\n"); }

une 6:14 PM HolaAndroid2 Hola Anaroidsm(O.O) = 0.0 sin(0.01) = 0.009999833334166664 sin(0.02) = 0.01999866669333308 sin(0.03) = 0.02999550020249566 sin(0.04) = 0.03998933418663416 sin(0.05) = 0.04997916927067833 sin(0.060000000000000005) = 0.0599640064794446 sin(0.07) = 0.06994284733753277 s¡n(0.08) = 0.0799146939691727 sin(0.09) = 0.08987854919801104 sin(0.09999999999999999) = 0.09983341664682814 sin(0.10999999999999999) = 0.1097783008371748 sin(0.11999999999999998) = 0.11971220728891935 sin(0.12999999999999998) = 0.12963414261969483 sin(0.13999999999999999) = 0.13954311464423647 sin(0.15) = 0.14943813247359922 sin(0.16) = 0.15931820661424598 sin(0.17) = 0.16918234906699603 sin(0.18000000000000002) = 0.1790295734258242 Sin(0.19000000000000003) = 0.1888588949765006 sin(0.20000000000000004) = 0.19866933079506124 Sin(0.21000000000000005) = 0.2084598998460996 sin(0.22000000000000006) = 0.21822962308086938 sin(0.23000000000000007) = 0.22797752353518846 si n(0.24000000000000007) = 0.23770262642713466 sin(0.25000000000000006) = 0.247403959254523 sin(0.26000000000000006) = 0.2570805518921552 sin(0.2700000000000001) = 0.2667314366888312 S ¡ n(0.2800000000000001) = 0.2763556485641138 s¡n(0.2900000000000001) = 0.28595222510483564 sin(0.3000000000000001) = 0.29552020666133966

sin(0.3100000000000001) = 0.3050586364434436 sin(0.3200000000000001) = 0.3145665606161179 sin(0.3300000000000001) = 0.3240430283948685

Figura 2.10. Un ScrollView permite extenderla vista y acceder a la parte del texto oculta

porque se sale de la pantalla.

Para verla completa basta modificar main.xml insertando el LinearLayout dentro de

un Scrollview:

<?xml version=111. 0" encoding= "utf-8 "?>

<ScrollView

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#ffffff"

android:layout_height="wrap_content" android: id=

"@+id/scrollViewl11 android:1ayou t_wi dth="f ill_parent">

<LinearLayout

android:id="@+id/linearLayoutl"

android:layout_width="fi1l_parent"

android:layout_height="fill_parent">

Page 27: Android

28 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

<TextView

android:id="@+id/myTextView"

android:textColor="#000000"

android:textSize="12sp"

android:layout_gravity="center"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Hola Android" /> </LinearLayout> </ScrollView>

El resultado se muestra en la figura 2.10. La barra vertical de la derecha indica el sector

que se esta mostrando.

3. BOTONES

En Android los botones permiten interaccionar con las aplicaciones para realizar acciones.

3.1. Definición de un botón en el layout

l_o más simple es definir un botón dentro de un layout mediante:

<Button

android:id="@+id/myButton"

android:text="Boton"

android:layout_width="fill_parent"

andró i d:1ayout_he ight ="wrap_cont ent">

</Button>

I ste botón lo añadimos al fichero main.xml del ejemplo “Hola Android" que se modifica

así:

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

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android

android:id="@+id/myLinearLayout" andró

id:background="#ffffff" android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:id="@+id/myTextView"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:textColor="#000000"

android:textSize="20sp"

android:text="Hola Android" />

Page 28: Android
Page 29: Android

30 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉ S Of I II MPI.OS

<Button

android:id="@+id/myButton" android:

text= " Bo ton11 android:layout_width="f

ill_parent"

android:layout_height="wrap_content">

</Button>

</LinearLayout>

La actividad principal “inflará” este botón junto con el layout. Por ejemplo:

public class Hello extends Activity implements

onClickListener {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView myTextView=

(TextView) findViewByld(R.id.myTextView);

myTextView.setText("Ejemplo de botón"); }

El resultado se muestra en la figura 3.1. Nótese que en la primera linea hemos

añadido a la clase Helio la propiedad:

[5 Si<82:00 PM Hello

Page 30: Android

implements OnClickLístener

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '.A I RAVI'Mil I IIMPIOB .11

Esto es necesario para que la actividad “escuche los clicks" y responda al pulsar sobre el

botón. Para que el botón responda a una acción primero debemos definir el botón como un

objeto de tipo view asociado a su ID:

View boton=findViewByld(R.id.myButton);

y luego definir a este botón como un “oyente" de clicks en nuestra actividad:

boton.setOnClickListener(this);

Para finalizar la implementación de la interfaz OnClickListener, debemos definir el

método onClickOque contiene las instrucciones a seguir cuando se pulse el botón:

public void onClick(View v) { myTextView.setText("Has pulsado el botón");

}

El ejemplo final quedaría así:

package prueba.android.hello;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.TextView;

public class Hello extends Activity implements

OnClickListener{

/** Called when the activity is first created. */

TextView myTextView;

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState) ;

setContentView(R.layout.main);

myTextView=(TextView)findViewByld(R.id.myTextView);

myTextView.setText("Ejemplo de botón");

View boton=findViewByld(R.id.myButton);

boton.setOnClickListener(this); }public void onClick(View v) {

myTextView. setText ("Has pulsado el botón.");

}

Nótese que en el encabezamiento hemos incluido también las importaciones necesarias

Page 31: Android

ANDROID: PROGRAMACIÓN DI DISPOSITIVOS MÓVILES A IKAVÉK 1)1 I II Ml*l OS 33

para que el programa funcione. Estas líneas generalmente las obviamos en nuestros

ejemplos, porque el programa Eclipse nos informa y hace las importaciones necesarias,

pulsando con el botón derecho del ratón sobre los nombres de los objetos que quedan

subrayados en rojo en Eclipse.

Lo que hace el método onClickO es modificar el texto de myTextView, que hemos

tenido que declarar fuera del método onCreate () como campo de la clase Helio para

que esté definido en toda actividad, también en onClick ()

TextView myTextView;

Al pulsar el botón se ejecuta el método onClick Oque redefine el texto de

myTextView, ’’has pulsado el botón”, como se ve en la figura 3.2.

a ____________ am«11:17 AMI Helio

Has pulsado el botón

Botón

Figura 3.2. El texto cambia tras pulsar el botón.

3.2. Caso de dos botones

Para añadir un segundo botón basta definirlo en main.xml a continuación del primero.

<LinearLayout

android:id="@+id/linearLayoutl"

android:layout_width="fill_parent"

android: layout_height=" f i

ll__parent"

android:orientation="vertical">

Page 32: Android

34 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

<TextView android:id="@+id/myTextView"

android: textColor="#000 0 00 11

android:textSize="12sp"

android:layout_gravity="center"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Hola Android"

/ >

<Button android:text="Boton 1"

android:id="@+id/buttonl"

android:layout_width="f ill_parent"

android:layout_height="wrap_content">

</Button>

<Button android:text="Boton 2"

android:id="@+id/button2"

android:layout_width="fill_parent"

android:layout_height="wrap_content">

</Button>

</LinearLayout>

Igual que en el caso de un botón, hay que definir cada uno de los dos botones como

“escuchador” mediante setOnClickListener () .

View botonl=findViewByld(R.id.buttonl);

botonl.setOnClickListener(this);

View boton2=findViewByld(R.id.button2);

boton2.setOnClickListener(this);

Finalmente, se debe definir una acción dependiendo de cuál de los botones se liii pulsado

en el método ondick (view v) , donde v corresponderá a uno de los dos botones.

Basta entonces comprobar su “ID” mediante v .ge tJdí ) para dofinir la acción. En el siguiente

ejemplo haremos que se escriba un texto Indicando qué botón se ha pulsado.

public class HolaAndroid2 extends Activity implements

OnClickListener{

TextView myTextView;

@Override

public void onCreate(Bundle savedlnstanceState) [

super.onCreate(savedlnstanceState);

setContentView(R.layout.main];

View v=findViewByld(R.id.myTextView)

myTextView=(TextView) v;

myTextView.setText("Ejemplo de boton");

View botonl=findViewByld(R.id.buttonl>;

botonl.setOnClickListener(this);

View boton2=findViewByld(R.id.button2);

Page 33: Android

ANDROID: PROGRAMACIÓN DI DISPOSITIVOS MÓVILES A IKAVÉK 1)1 I II Ml*l OS 35

boton2.setOnClickListener(this);

}

public void onClick(View v){

if(v.getld()==R.id.buttonl) {

myTextView.setText("Has pulsado el boton 1");

} else if(v.getId()==R.id.button2){

myTextView.setText("Has pulsado el boton 2");

}

}

}

El resultado de pulsar el botón 2 se muestra en la figura 3.3.

3.3. Uso de Toast para mostrar un mensaje emergente

Se puede usar el método Toast .makeText () para crear un objeto Toast que

permite mostrar un texto en una pantalla emergente durante unos segundos

Toast.makeText(this, mensaje, duración).show();

donde mensaje es un objeto de tipo String y duración es un número entero, que se

puede especificar mediante las constantes Toast. LENGTH_SHORT (o) y

Toast.LENGTH_LONG (i). Ilustraremos el funcionamiento de un Toast usando los dos

botones del ejemplo anterior. Basta modificar el método onClick () de la siguiente

forma:

Page 34: Android

DE DISPOSITIVOS MÓVII I ■. A IRAVf:¡ HI I .11 MPI.0S

&!Í4«7 16 PM HolaAn<lroíd2

Has pulsado el ootor 2

i Boto'; 1

Figura 3.3. El texto cambia según el botón que se ha pulsado.

public void onClick(View v){

String mensaje=""; int duracion=l;

if(v.getld()==R.id.buttonl) {

mensaje="Has pulsado el boton 1";

duracion=Toast.LENGTH_SHORT; }

else if(v.getId()==R.id.button2){ mensaje="Has pulsado el

boton 2"; duracion=Toast.LENGTH_LONG; } mensaje=mensaje+" duración = "+duracion; Toast.makeText(this, mensaje, duración).show();

iut.ulUido después de pulsar el botón 2 se muestra en la figura 3.4.

r

Page 35: Android

36 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

Has:pulsado el boton 2'duration = 1

Figura 3.4. Un texto emergente con Toast tras pulsareI botón 2.

3.4. Cambiar el texto de un botón

Laclase Button es una extensión de la clase Textview. Por tanto, se pueden usar

todo sus métodos, por ejemplo setTex (), de la siguiente forma: ((Textview)

boton).setText("texto del boton"); nótese que para usar el método hay que

convertir el botón a tipo TextView mediante un cast.

En la siguiente aplicación, modificamos el ejemplo anterior para que cada botón muestre

el número de veces que se ha pulsado. Basta sustituir el método onClickO por lo siguiente:

int i1 = 0; int i 2 = 0;

public void onClick(View v){

String mensaje=""; int duracion=l;

if(v.getld()==R.id.buttonl) { i 1 + + ;

((Textview)v).setText("Pulsado "+il+" veces"); }

else if(v.getld()==R.id.button2){ 12 + + ;

mmm 9:26 AM I Hola And rotd2 Siemp'o de boto-i

'0,0n.2.; ..........................

Page 36: Android

ANDHOID: PROGRAMACIÓN DE DISPOSITIVOS MrtVIl I '.A I KAVf l: I >1 I II MINO!. 37

Figura 3.5. Cada botón muestra el número de pulsaciones usando setText.

3.5. Cambiar el color de los botones I '¡ira cambiar el color de un botón se utiliza el método:

boton.setBackgroundColor(Color.rgb(red,green,blue))

Como ilustración del uso de este método, en el ejemplo anterior añadiremos un tercer

botón y definiremos el método onClick () para que, al pulsar sobre el Iirimer botón,

cambie la componente red, el segundo la green y el tercero la 111 ue. Pulsando sobre

los distintos botones estos cambian de color. El programa permite explorar la gama de

colores avanzando de cinco en cinco. Este es el código que sustituye a onClick ():

int i1=0; int

i 2 = 0; int

i 3 = 0; int

dcolor=5; int

cmax=25 5;

US!® 10:18 AM KolaAndroid2 Éjeinpío de feoton

( (TextView)v) . setText (11 Pulsado "+Í2 + " veces") ;

}

}

El resultado se muestra en la figura 3.5.

Page 37: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

int red=cmax; int green=cmax;

int blue=cmax;

public void onClick(View v){

if(v.getld()==R.id.buttonl) {

il++ ;

red=dcolor*il%cmax;

} else if (v.getld()==R.id.button2){

i 2 + + ;

green=dcolor*i2%cmax;

} else if(v.getld()==R.id.button3){ i 3

+ + ;

blue=dcolor*i3%cmax;

}

((TextView)v).setText("color "+red+","+green+","+blue);

v.setBackgroundColor(Color.rgb(red,green,blue));

}

El resultado se ve en la figura 3.6.

Figura 3.6. Pulsando los botones, cambian de color con setBackgroundColor().

Page 38: Android

ANDROID: PROGRAMACIÓN DI. DISPOSITIVOS MÓVII I :. A 1UAVÉ DI I Jf Ml'I OS

Page 39: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS OF I .11 MPI.OS

3.6. Calculadora

I’;ira ¡lustrar el uso de botones en Android presentamos una sencilla aplicaciór una

calculadora con botones para números y operaciones. Esto nos permitir l.imbién introducir

el uso de tablas en Android. Primero definimos los botones ei main.xml dispuestos en

una tabla, usando un TableLayout. Cada fila SÍ (ispecifica con TableRow. Las dos

primeras filas incluyen sólo texto. La primer^ fila es un título. La segunda fila mostrará los

números que vamos introduciendo. Ls lurcera fila es un texto para el resultado de los

cálculos, que expande tre^ columnas, y el botón "=" . Las siguientes filas contienen

botones para las teclas numéricas, las operaciones aritméticas, el punto decimal y la tecla

de borrado.

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

<TableLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/tableLayoutl"

android:background="#ffffff" android:stretchColumns="*"

android:layout_gravity="center"

android:layout_width="fill_parent"

android:layout_height="fill_parent">

<TextView

android:textColor="#000000"

android:background="#ffaa3 3"

android:textSize="24sp"

android:layout_gravity="center"

android:layout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="Android Calculator" />

cTextView

android:id="@+id/myTextView"

android:textColor="#000000"

android:textSize="24sp"

android:layout_gravity="left"

android:1ayout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="Pulse para empezar a calcular" />

<TableRow>

<TextView

android:layout_span="3" android:id="@+id/myTextView2"

android:background="# f faa3 3" android:textColor="#000000"

android: textSize = ,,24sp,,

android:layout_gravity="left" android:

layout_width="f ill jarent"

android:layout_height="wrap_content"

android:text="Resultado"

Page 40: Android

ANDROID: PROGRAMACIÓN DI. DISPOSITIVOS MÓVII I :. A 1UAVÉ DI I Jf Ml'I OS

/>

<Button

android:text="=" android:textSize="24sp"

android:layout_span="1"

android:id="@+id/buttonIgual" /> </TableRow>

<TableRow>

<Button

android:text="1" android:textSize="24sp"

android:id="@+id/buttonl" />

<Button

android:text="2" android:textSize="24sp"

android:id="@+id/button2" />

<Button

android:text="3" android:textSize="24sp"

android:id="@+id/button3" />

<Button

android:text="+" android:textSize="24sp"

android:id="@+id/buttonSuma" /> </TableRow>

<TableRow>

<Button

android:text="4" android:textSize="24sp"

android:id="@+id/button4" />

<Button

android:text="5" android:textSize="24sp"

android:id="@+id/button5" />

<Button

android:text="6" android:textSize="24sp"

android:id="@+id/button6" />

<Button

android:text="-" android:textSize="24sp"

Page 41: Android
Page 42: Android

ANDROID PROGRAMAClON DE DISPOSITIVOS MOVIII '.A IKAVI'MDI I II Ml’I OS 41

android:id="@+id/buttonResta" />

</TableRow>

<TableRow>

<Button

android:text="7" android:

textSize=1124sp"

android:id="@+id/button7" />

<Button

android:text="8"

android:textSize="24sp"

android:id="@+id/button8" />

<Button

android:text=" 9"

android:textSize="24sp"

android:id="@+id/button9"/>

<Button

android:text="x"

android:textSize="24sp"

android:id="@+id/buttonMultiplica" />

</TableRow>

<TableRow>

<Button

android:text="0"

android:textSize="24sp"

android:id="@+id/buttonO" />

<Button

android:text="."

android:textSize="24sp"

android:id="@+id/buttonPunto" />

<Button

android:text="C"

android:textSize="24sp"

android:id="@+id/buttonBorra" />

<Button

android:text="/"

android:textSize="24sp"

android:id="@+id/buttonDivide" />

</TableRow>

</Tab1eLayout >

I ste layout se muestra en la figura 3.7.

Page 43: Android

Mili i'HOORAMACIÓNDE DISPOSITIVOS MÚVILI iA IHAVÉS DE EJEMPLOS

iililMíltlTirtífi♦

Hfly8 9 im M

Figura 3.7. Diseño de una calculadora con TableLayout.

La actividad Calculadora.java primero define todos los botones en onCreateO .

Seguidamente se define la acción de cada botón en el método onClickO . Para los botones

numéricos, esta consiste en añadir la cifra correspondiente al número que se va almacenando

en myTextview. Al pulsar un operador, "+, - ,x, / ,=" , se invoca el método calcula () que realiza

la operación anterior y actualiza las variables. Los números que se van introduciendo se

almacenan en las variables de clase mi, m2 . El operador anterior introducido se guarda en la

variable char opl. He aquí el listado. La calculadora es muy rudimentaria, pero realiza

perfectamente las operaciones indicadas.

public class Calculadora extends Activity implements

OnClickListener{

TextView myTextview,myTextView2;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

View vl=findViewByld(R.id.myTextview);

myTextView=(TextView) vi; myTextview. setText (" 11) ;

View v2 = f indViewByld (R. id . myTextVie'w2) ;

myTextView2=(TextView) v2; myTextView2 . setText

("11) ;

View botonl=findViewByld(R.id.buttonl);

botonl.setOnClickListener(this);

View boton2=findViewByld(R.id.button2);

boton2.setOnClickListener(this);

View boton3=findViewByld(R.id.button3);

Page 44: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

boton3.setOnClickListener(this);

View boton4=findViewByld(R.id.button4);

boton4.setOnClickListener(this);

View boton5=findViewByld(R.id.button5);

boton5.setOnClickListener(this);

View boton6=findViewByld(R.id.button6);

boton6.setOnClickListener(this);

View boton7=findViewById(R.id.button7);

boton7.setOnClickListener(this);

View boton8=findViewByld(R.id.button8);

boton8.setOnClickListener(this),- View

boton9=findViewByld(R.id.button9);

boton9.setOnClickListener(this);

View botonO=findViewById(R.id.buttonO);

botonO.setOnClickListener(this);

View botonSuma=findViewByld(R.id.buttonSuma);

botonSuma.setOnClickListener(this);

View botonResta=findViewByld(R.id.buttonResta);

botonResta.setOnClickListener(this);

View botonMultiplica=

findViewByld(R.id. buttonMultiplica);

botonMultiplica.setOnClickListener(this);

View botonDivide=findViewByld(R.id.buttonDivide)

botonDivide.setOnClickListener(this);

View botonPunto=findViewByld(R.id.buttonPunto);

botonPunto.setOnClickListener(this);

View botonBorra=findViewById(R.id.buttonBorra);

botonBorra.setOnClickListener(this);

View botonIgual=findViewByld(R.id.buttonlgual);

botonlgual.setOnClickListener(this);

double result,11(11=0, m2 = 0; i 'har opl= 1 + ' ;

public void onClick(View v){

I I (v.getld()==R.id.buttonl)

myTextView.append ("1") ; else if (v.getldO

==R. id.button2 ) myTextView.append("2");

else if(v.getld()==R.id.button3)

myTextView.append("3"); else

if(v.getld()==R.id.button4)

myTextView.append("4"}; else

if(v.getld()==R.id.buttons)

myTextView.append("5"); else

if(v.getld()==R.id.button6)

myTextView.append("6"); else

if(v.getld()==R.id.button7)

Page 45: Android

Mili i'HOORAMACIÓNDE DISPOSITIVOS MÚVILI iA IHAVÉS DE EJEMPLOS

myTextView.append("7"); else if (v.getldO

==R. id.buttons) myTextView.append("8"); else

if(v.getldO==R.id.button9) myTextView.append(

" 9"); else if (v.getldO ==R. id.buttonO)

myTextView.append("0"); else

if(v.getld()=?R.id.buttonPunto)

myTextView.append("."); else

if(v.getld()==R.id.buttonBorra){

myTextView.setText("");

myTextView2.setText(""); ml = 0 ; opl='+1; }

else if(v.getldO==R.id.buttonSuma) calcula('+'); else

if(v.getldO==R.id.buttonResta) calcula('-'); else

if(v.getld()==R.id.buttonMultiplica) calcula('*'); else

if(v.getld0==R.id.buttonDivide) calcula('/'); else

if(v.getldO==R.id.buttonlgual) calcula('=');

}

public void calcula(char op){ double result=ml;

String cadena= myTextView.getText().toString(); try {

m2=Double.parseDouble(cadena) ;

if(opl=='+') result=ml+m2; else

if(opl=='-') result=ml-m2; else

if(opl=='*') result=ml*m2; else

if(opl=='/') result=ml/m2; ml=result;

Opl=Op;

if(op == '='){

Page 46: Android

■luili l'UOGHAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉH 1)1 I II MI’IOS 45

myTextVíew.setText(""+ml);

myTextView2.setText(""+ml);

}else{

myTextVíew.setText("");

myTextView2 . setText {" "+ml+opl)

;

}

} catch(NumberFormatException nfe){

Toast.makeText(this,"numero incorrecto",1).show( }

l n i nlciiladora en funcionamiento se muestra en la figura 3.8.

Figura 3.8. Resultado de una operación con la calculadora.

Ilninos previsto que se puedan cometer errores al introducir los datos (por ii!|iin pulsar

varios operadores seguidos). Para evitar que la aplicación Android «bullo en caso de error,

Java permite realizar el cálculo dentro de un bloque y ' Mtch.

M produce un error sería una excepción de tipo NumberFormatException it'iiiii ilii

transformar en un número la cadena introducida. En caso de error, se

C a l c ui a d o rc

Androic I Calculator

6 8

1 . 3 0 8 4 6 -

£

1 ¡21 * 3 ú M

k 4 J i 5 i 6 1

7 8 1 * I x i

0

1 i

Page 47: Android

46 ANDROIO: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A IHAVÉS I)F F.ll MPI.OS

muestra un mensaje en la pantalla mediante un Toast, pero se puede seguir calculando. Un

ejemplo de mensaje de error se muestra en la figura 3.9.

m ........

Mwk 5 ; 6 tüÉfl 8 9 *

L • _ _£ i :

Figura 3.9. Mensaje de error tras una operación inválida con la calculadora.

4. INTRODUCCIÓN DE TEXTOS

4.1. TextField

í>e puede introducir texto interactivamente en una aplicación Android usando un i .irnpo de

texto editable EditText, que se coloca dentro del Layout en el fichero main.xml, de

la siguiente forma:

< EditText android:id="@+id/editText1"

android:layout_width="f ill_parent"

android:layout_height="wrap_content"

android:text="EditText">

•/EditText>

Para acceder al texto introducido desde Java primero definimos el objeto i 'll t.Text

asociado al campo de texto editable y luego lo transformamos en ni i i.ng:

KditText textField=(EditText) findViewByld(R.id.editTextl);

Mtring texto = textField.getText().toString();

I ’or ejemplo, la siguiente aplicación permite introducir un nombre que luego se mi i« tira

en pantalla cuando se pulsa un botón.

public class InputText extends Activity implements OnClickListener{

Page 48: Android

DE DISPOSITIVOS MÓVII ISA IKAVI'SIII I IIMPl (IS 47

KditText textField;

fitring nombre;

TextView tv;

/** Called when the activity is first created. *)

«»Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

textField=(EditText) findViewByld(R.id.editTextl);

View boton=f indVí ewByld (R. id. button.1) ;

boton.setOnClickListener(this);

tv=(TextView) fIndViewByld(R.id.text2);

}

@Override

public void onClick(View v){

nombre = textField.getText().toString();

tv.append("\nBienvenido, "+nombre);

} }

El resultado se ve en la figura 4.1.

[ _ ü® 12:17PM]

Introduzca su nombre

pepej _ _

Bienvenido, amaro Bienvenido, pepe

Figura 4.1. Introducir texto con Edi t Text.

En este ejemplo se ha utilizado el siguiente fichero main. xml:

Page 49: Android

48 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

<?xml version="l.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android”

android:background="# f f f f dd"

android:orientation="vertical"

android:layout_width="fill_parent"

Page 50: Android

• IIHl' ill) PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVI" K DI I II Ml’108 4C)

android:layout_heigh.t="Eill_parent"

android:id="@+id/layoutl"

>

«■TextView

android:textSize="24sp" android:t

extColor="#000000"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Introduzca su nombre"

android:id="@+id/textl" />

■EditText android:id="@+id/editTextl"

android:layout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="EditText">

•/EditText>

•Button android:text="Aceptar"

android:id="@+id/buttonl"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

•/Button>

• TextView

android:textSize="24sp"

android:textColor="#000000"

android:layout_width="fill_parent"

android:layout_height="wrap_content

" android:text=""

android:id="@+id/text2" />

•/LinearLayout>

i 1 OnKeyListener

!'iti.i lorminar de introducir texto al pulsar la tecla ENTER se debe implementar la lnlmlaz

OnKeyListener. Esto implica que hay que definir el método onKey (), i'n i que se

realice una determinada acción al pulsar la tecla ENTER. Se definiría *1« In Blguiente forma:

• ' I. i lis MyKeyListener implements OnKeyListener{

I public boolean onKey(View v, int keyCode, KeyEvent event){

II ((event.getAction() == KeyEvent.ACTION_DOWN) &&

(keyCode == KeyEvent.KEYCODE_ENTER)) {

// acción a realizar

Page 51: Android

return true;

} return false;

} }

Nótese que, al pulsar una tecla, se recoge un evento:

KeyE ven t_AC TI ON_DOWN y que la tecla ENTER envía un código:

KeyEvent.KEYCODE_ENTER

Seguidamente hay que crear un objeto “oyente” (listener), es decir, de la clase anterior:

OnKeyListener listener= new MyKeyListener();

y finalmente llamar al método setOnKeyListener () de la clase EditText:

edittext.setOnKeyListener(listener);

Esta implementación se ilustra en la siguiente actividad, donde se introduce un nombre

que luego se muestra en pantalla y también en un Toast:

public class InputText extends Activity{

EditText edittext; TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

tv=(TextView) findViewByld(R.id.text2); edittext =(EditText) findViewByld(R.id.editTextl);

class MyKeyListener implements OnKeyListener{

public boolean onKey(View v, int keyCode,

KeyEvent event) {

// si se pulsa la tecla enter if ((event.getAction()

== KeyEvent. ACTION_DOWN) && (keyCode ==

KeyEvent.KEYCODE_ENTER)) {

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS Móvil I '.A INAVÍ'.IM I JEMPL0850

Page 52: Android

Himuill PROGRAMACIÓN DE DISPOSITIVOS MÓVII i :IA IKAVI M>l I II MPL09

Toast.makeText(InputText.this,

ed i t t ex t . ge tText ( ) ,

Toas t.LENGTH_SHORT) .show <)

tv.setText["Bienvenido "

+edittext.getText <));

return true;

} return false;

} }

OnKeyListener listener= new MyKeyListener() ;

edittext.setOnKeyListener(listener);

} }

I 11> ’sultado se muestra en la figura 4.2.

Figura 4.2. Introducir texto con OnKeyListener.

I I fichero main .xml correspondiente al anterior ejemplo es el siguiente:

l?xml version="l.0" encoding-"utf-8"?>

■ ü® 1 48 PM MÈËSKÊUÊÊÉÊËm Introduzca su nombre

Martin Martinez Martinedoj

Bienvenido Martin Martinez Martinedo

Page 53: Android

52 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I ' i A IRAVÉ-HDI I Jl- M(*l <)!■

<LinearLayout

xmlns : andró i d= "http : // schemas. android.

com/apk/res/andróid" android:background="#ffffdd"

android:orientation="vertical"

android:layout_width="fill_parent" andr oid:layout_heí ght

= "f i11_pa rent" android:id="@+id/layoutl"

>

<TextView

android:textSize="24sp"

android:textColor="#000000"

android:layout_width="fill_parent"

android:layout_height= "

wrap__content"

android:text="Introduzca su nombre"

android:id="@+id/textl" />

<EditText android:id="@+id/editTextl"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="EditText">

</EditText>

<TextView

android:textSize="24 sp"

android:textColor="#000000"

android:layout_width="fill_parent"

android: layout_height = "

wrap_content11 android:text=""

android:id="@+id/text2" />

</LinearLayout>

4.3. Forma alternativa de implementar OnKeyListener

El siguiente código es equivalente al del ejemplo anterior. Presentamos aquí esta forma

alternativa para ilustrar la flexibilidad del lenguaje Java. En el caso anterior la interfaz

OnKeyListener se implementaba definiendo una clase interna dentro del método

onCreate (). En este caso la implementamos en la clase principal de l;i actividad, de

forma totalmente análoga a como hemos hecho para definir el método onClick () con los

botones. Esto es consecuencia de que en Java, en principio, cualquier clase puede

implementar una interfaz y se puede hacer según convenga.

public class InputText extends Activity implements

OnKeyListener{

Page 54: Android

AN! IKOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII 3 A tUAVI'Mil I ,11 MIMOS 53

EdìtText edittext;

TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

tv=(TextView) findViewByld(R.id.text2);

edittext =(EditText) findViewByld(R.id.editTextl);

edittext.setOnKeyListener(this); }

public boolean onKey(View v, int keyCode, KeyEvent event) {

// si se pulsa la tecla enter if

((event.getAction() == KeyEvent.ACTION_DOWN) &&

(keyCode == KeyEvent.KEYCODEJENTER)) {

Toast.makeText(InputText.this,

edittext.getText(),

Toast.LENGTH_SHORT).show();

tv.setText("Bienvenido "+edittext.getText());

return true; } return false;

}

El presente método nos permite entender más fácilmente el código, pues nos

ahorramos definir una clase y un objeto internos, lo que dificulta la lectura lineal del

l'ingrama. Nótese que, puesto que ahora es la clase principal la que implementa 1'iiKeyListener, la llamada a setOnKeyListener() se realiza con el .n(|umento

this, el objeto asociado a la clase de nuestra actividad:

edittext.setOnKeyListener(this);

5. GUARDAR DATOS CON SharedPreferences

SharedPreferences es una clase para leer y modificar datos. El código para abrir un

fichero de datos asociado a la variable misDatos sería:

SharedPreferences misDatos =

getSharedPreferences(fichero,acceso);

donde fichero es el nombre del fichero donde queremos guardar las preferencias, sin

extensión. Si el fichero no existe, se crea uno nuevo. El número entero acceso es

usualmente 0, indicando fichero privado. Para leer las preferencias se usa el método

getStringO o también getFloat () , getlnt () para leer números.

Para modificar las preferencias se utiliza un Editor, un objeto de la clase

SharedPreferences .Editor, que permite escribir datos con sus etiquetas (entre

comillas) y salvar el fichero de la siguiente forma:

Page 55: Android

54 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '• A TRAVÉS DE EJEMPLO!)

SharedPreferences.Editor miEditor=misDatos.edit();

// escribe los datos

miEditor.putString("nombre",nombre);

miEditor.putFloat("x",x); miEditor.putFloat("y",y);

// salvar miEditor.commit();

Para leer las preferencias se utilizaría el siguiente código:

// Lee en el fichero de preferencias

nombre=misDatos.getString("nombre","Valor por defecto");

x=misDatos.getFloat("x", 0); y=misDatos.getFloat("y", 0) ;

donde el segundo parámetro de los métodos getStringO y getFloat () es el

valor que se devuelve por defecto si el dato no existe.

La siguiente actividad define tres campos para introducir un nombre y do» coordenadas

que se guardan en un fichero de preferencias. El fichero se lee al

"|(.'cutar la actividad y muestra ios valores er los campos de texto. Los datos se i|ii;irdan en

el método onPause(), que se ejecuta cuando la actividad pasa a M'ijundo plano o

finaliza. Usamos un Toast para indicar que las preferencias se luin guardado.

public class Preferencias extends Activity {

SharedPreferences mísDatos;

EditText editNombre,editX,editY;

String nombre;

Float x,y;

SíOverride

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

editNombre=(EditText) findViewByld(R.id.nombre);

editX=(EditText) findViewByld(R.id.coordenadaX);

editY=(EditText) findViewByld(R.id.coordenadaY);

//Abre un fichero de preferencias.

// El parámetro 0 indica privado

misDatos= getSharedPreferences("preferencias", 0) ;

// Lee en el fichero de preferencias

nombre=misDatos.getString("nombre",

"Valor por defecto");

x=misDatos.getFloat("x", 0);

y=misDatos.getFloat("y" , 0) ;

// escribe las preferencias en los campos de texto

editNombre.setText(nombre); editX.setText(""+x);

editY.setText(""+y);

}

(«Override

Page 56: Android

<\NI lUOIIJ: PROGRAMACIÓN DE DISPOSITIVOS MÓVILI: K A I HAVÉSOE I JEMPLOS 55

protected void onPause(){ super.onPause();

// extrae el contenido de los campos de texto

nombre=editNombre.getText().toStringO ; x=Float.

parseFloat (editX. getText () .toStringO) ; y=Float

.parseFloat (editY. getText () .toStringO) ;

// define un editor para misDatos

SharedPreferences.Editor miEditor=misDatos.edit();

// escribe los datos

miEditor.putString("nombre",nombre);

Page 57: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRftVÍ S DI IIJEMPLOS

mxaaiuor.puifioat("X", xj ; miEditor.putFloat("y", y) ;

// salvar

miEditor.commit();

Toast.makeText(this,"Preferencias guardadas"r1).showO;

ü« IOS AM I

ntroduzca sus preferencias 'Jombre

:oordenada X:

100.1

Coordenada Y: 200.1

Figura 5.1. Guardar datos con SharedPreferences.

El fichero main;xml correspondiente a esta aplicación es el siguiente:

<?xml version="l.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#f f f f dd"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/layoutl"

>

<TextView

android:textSize="24sp"

android:textColor="#00 0 000"

android:layout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="Introduzca sus preferencias"

android:id="@+id/textl" / >

Page 58: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVIL I .A ll<AVI-M>l I Jf Ml'I OS

*TextView

android: textSize= "24sp'' android:textColor="#000000"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Nombre" />

■EditText android:id="@+id/nombre"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="EditText">

</EditText>

•TextView

android:textSize="24sp" android:textColor="#00000 0"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Coordenada X:" />

■EditText android:id="@+id/coordenadaX"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="EditText">

■: /EditText>

<TextView

android:textSize="24sp" android:textColor="#000000"

android:layout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="Coordenada Y:" />

•EditText android:id="@+id/coordenadaY"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="EditText">

</EditText>

</LinearLayout>

El resultado se muestra en la figura 5.1. Los datos se guardan cuando se sale de la

aplicación, pulsando la tecla home o la tecla de llamada telefónica, por ejemplo. Cuando se

vuelve a ejecutar la aplicación los datos guardados se leen y muestran en la pantalla. El

fichero con los datos se escribe físicamente en el directorio local de datos de la aplicación.

En el caso del dispositivo virtual, desde ECLIPSE este fichero se puede ver abriendo la

perspectiva DDMS. La ruta del fichero de preferencias en mi caso es:

/data/data/es.ugr.amaro.preferencias/shared_prefs/

y el fichero con los datos se llama preferencias .xml.

Page 59: Android

■Mil Hll PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVIr SUS I II MPLOS 59

Este fichero tiene extenxión xml y se puede copiar pulsando la opción “pulí a file from

the device". Su contenido es el siguiente:

<?xml version=11.01 encoding=1utf-8' standalone=1 yes 1 ?> <map>

<string name="nombre">amaro</string>

<float name="y" value="200.1" />

<float name="x" value="100.1" />

</map >

Aquí vemos que los valores float, en realidad, se almacenan también como cadenas, lo

que manifiesta la relativa utilidad de putFloat(). Es preferible almacenar con putstring () y

luego convertir las cadenas en números.

n ACTIVIDADES

0 I Uso de Intent para iniciar actividades

Mi plicación Android puede contener varias actividades. Cada actividad es una

ttftiiii de Java. Para abrir una nueva actividad se define un objeto intent de la HUUl'mte

forma:

ImIent intencion=new

Intent(this,Actividad2.class); mI . 1 1 tActivity

(intención) ;

i ii nueva actividad debe declararse en el fichero . manif est de la aplicación Hi*m

liante:

Page 60: Android

60 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

■ m a < 'i ivity

, mdroid:name=".Actividad2"

■ indroid: label="Otra actividad">

! ► /.ic:tivity>

l.imbién se pueden pasar datos “extra" de una actividad a otra usando el fnélndo putExtra():

Inl i'ncion.putExtra(Actividad2.datoExtra, valor);

ilunde datoExtra es una variable String definida en la actividad 2. Para h< . mli >r a

variable string valor desde la actividad 2 se utiliza:

1 MI i Ing valor=getIntent() .getStringExtra(datoExtra) ;

ludo esto está ilustrado en el siguiente ejemplo. La actividad principal (Fig. í 11 llnne un

botón para abrir una segunda actividad y le pasa un dato extra que pi nncrlbe en pantalla

(Fig. 6.2).

Figura 6.1. Actividad con un botón para abrir otra actividad usando intent.

|G 2:29 l>M I

m ¡Bienvenido a la actividad 2, Gerardo

Page 61: Android

■Mil Hll PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVIr SUS I II MPLOS 61

Figura 6.2. Actividad 2 llamada desde la actividad anterior con un parámetro extm

■fclic class Actividades extends Activity implements

OH1'! ickListener{

String nombre; uuOverride

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

View boton=findViewById(R.id.buttonl);

boton.setOnClickListener(this);

nombre="Gerardo"; }

uuOverride

public void onClick(View v) {

Intent intencion=new Intent(this,Actividad2.class) ;

intención.putExtra(Actividad2.datoExtra, nombre);

startActivity(intención);

Toast.makeText(this,

"Abriendo la segunda actividad",1).show();

Pli-haro main.xml

H1 Kin I version= " 1. 0 " encoding= "utf - 8" ? >

I »1.1 nr.jrLayout

ptnlim :android="http://schemas.android.com/apk/res/android"

, i iidroid: orientation= " vert ical" iindroid:

layout_width=" f ill_parent"

. t nd ro i d:1ayout_he ight="fill_parent"

.«ndroid: background=" #f f f f cc"

■►TnxtView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Actividad 1"

android:textColor="#000000" android:textSize="24sp" />

l tut ton

android:text="Abrir actividad 2" android:textSize="24sp"

android:id="@+id/buttonl"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</Buttons

</LinearLayout>

r

Page 62: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII K A I HM‘ MU I .11 MPI..0S

Actividad2.java

public class Actividad2 extends Activity{ public static final String datoExtra="datol";

@Override

public void onCreate(Bundle savedlnstanceState){

super.onCreate(savedlnstanceState);

setContentView(R.layout.actividad2) ;

TextView texto=

(TextView)findViewByld(R.id.textViewl);

String nombre=getIntent().getStringExtra("datol");

texto.append(nombre); }

\

i’ichero actividad2.xml

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

:LinearLayout

:mlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="f i1l_parent"

android:background="#ffccff"

>

TextView android:text="Bienvenido a la actividad 2, "

android:id="@+id/textViewl"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textSize="24sp" android:textColor="#000000">

/TextView>

/LinearLayout>

.2. Pasar valores numéricos entre actividades

n el ejemplo anterior pasamos una variable extra string nombre a la sgunda

actividad usando putExtra(). También se pueden pasar variables jméricas int,

float, double e incluso arrays. Para recuperar estos valores i la segunda actividad

hay que usar los métodos getlntO , getFLoatO ,

Page 63: Android
Page 64: Android

Allí H'OIIT PROGRAMACIÓN DE DISPOSITIVOS MÓVIII '• A IRAVp.Dt I II MIMOS 6 3

• ii'tDouble () y getDoubleArray (). Por ejemplo, para pasar un array habría

i|ii(i modificar el ejemplo anterior para que incluyera las líneas.

double[] nombre= new double[10]; for(int i=0;i<10;i++)

nombre [i]=2*i;

Intent intencion=new Intent(this,Actividad2.class);

intención.putExtra(Actividad2.datoExtra, nombre);

y para recuperar el array en Actividad2 . j ava pondríamos:

double [] nombre=getIntent() .getDoubleArrayExtra("datol") ;

for (int i=0;i<10;i++) texto.append("\n''+nombre [i] )

La actividad 2 escribe ahora los valores del array como se ve en la figura 6.3.

Figura 6.3. Actividad 2 llamada desde la actividad anterior con un array como parámetro

extra.

7. MANEJO DE FICHEROS

Los dispositivos Android suelen tener una unidad de almacenamiento externo, como una

tarjeta micro SD. En esta sección veremos cómo se puede acceder a la tarjeta SD de

almacenamiento externo del dispositivo Android para crear directorios y ficheros donde

escribir los datos del programa. También trataremos la lectura de ficheros, tanto externos

como internos.

7.1. Escribir datos en un fichero en la tarjeta SD

Para manejar ficheros usamos la clase File del paquete java. io. Para escribir usamos

FileOutputStream y PrintWriter. La clase Environment de Android proporciona

fflía 5:21 PM

Bienvenido a la actividad 2,

0.0

2.0

4.0

6.0

8.0

10.0

12.0

14.0

16.0

18.0

Page 65: Android

64 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DI I .II Ml’l (>h

información acerca del dispositivo de almacenamiento.

El siguiente programa escribe datos en un fichero en la tarjeta SD. Concretamente:

1) Utiliza Environment. getExternalStorageState () para determinar si

existe tarjeta SD y está disponible (mounted).

2) Luego usamos Environment. getExternalStorageDirectory () para

identificar el directorio correspondiente a la tarjeta SD.

3) Crea un subdirectorio datos en la tarjeta (si no existe ya)

4) Abre un fichero datos i. txt en el subdirectorio datos

5) Escribe una cadena en el fichero datos i. txt

6) Cierra el fichero.

import java.io.File;

public class CheckStorage extends Activity {

TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Page 66: Android

tv=(TextView) fíndViewByld(R.id.texto);

'II > l'HOGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

String state=Environment.getExternalStorage State();

tv.append("\nEstado:"+state);

File root=Environment.getExternalStorageDiiectory(); File

dir=new File (root.getAbsolutePath()+"/datos");

dir.mkdirs();

tv.append( "\n\nNuevo directorio: "-i-dir);

tv.append( "\n\nContenido del directorio "+xoot+-" :">

String[] fichero=root.list();

for(int i=0;i<fichero.length;i++) tv.append

("\n"+fichero[i]);

File file=new File(dir,"datosl.txt"); try {

FileOutputStream fos = new FileOutputStream(file)

PrintWriter pw= new PrintWriter(fos); pw.println("Primera

linea del fichero"); pw.flush(); pw.close();

tv.append("\n\n Fichero grabado");

} catch (FileNotFoundException e){

e.printStackTrace(); tv.append("\n\n "+e)

; }

• li'tro main.xml:

Mill I, version=" 1. 0" encoding="utf-8"?>

I im.irLayout

I tin:android="http://schemas.android.com/apk/res/android" .

mdroid:orientation="vertical"

■ 1 1 idroid:layout_width="f ill_parent"

. i udroid:layout_height ="f i1l_parent"

, 1 1 idroid:background="#f fccaa"

■ Hi View

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Comprueba almacenamiento"

mdroid:textSize="24sp"

android:textColor="#0000 00"

mdroid:id="@+id/texto" />

</LinearLayout>

La figura 7.1 muestra la salida de este programa. Como vemos, el directorio datos que

queríamos crear no aparece en la lista y se produce un error FileNotFoundException al

intentar escribir en el fichero datosi. txt. Esto se debe a que la actividad no tiene

permiso para escribir. Este permiso debe declararse en el fichero .manifest añadiendo lo

siguiente:

Page 67: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII ES A TRAVÉS DE EJEMPLOS

<uses-permission

android:name="android.permission.WRITE_EXTERNAL_STORAGE">

</uses-permission>

I ~~ ~ 12:11 fM I

Comprueba almacenamiento

Estado:mounted

Nuevo directorio: /sdcard/datos

Contenido del directorio /sdcard :

LOST.DIR

download

java,io,FileNotFoundException:/sdcard/

datos/datosttxt

Figura 7.1. Información sobre el contenido de la tarjeta SD.

Una vez declarado este permiso de escritura, el programa crea el directorio y cribe el

fichero. La salida se muestra en la figura 7.2. El contenido de la tarjeta ) se puede

comprobar en Eclipse abriendo la perspectiva DDMS, y examinando ventana File Explorer.

El fichero datosl.txt se puede copiar localmente en estro ordenador para examinarlo

pulsando el botón “pulí from device” (nota: si produce un error al transferir el fichero, puede

arreglarse reiniciando Eclipse).

Page 68: Android

INIIUOID PROGRAMACIÓN DE DISPOSITIVOS MÓVIL I ¡A IHAVI r. OI I .11 M PIOS 67

Figura 7.2. Información sobre el contenido de la tarjeta SD y mensaje de escritura exitosa

de un fichero.

l i Leer un fichero en el directorio res

1« siguiente aplicación lee un fichero de datos datosi.txt que hemos copiado

|nnvi«imente en el directorio res/raw de la aplicación (desde Eclipse crear el ■ lii ni torio

res/raw si éste no existe). El fichero contiene las siguientes lineas:

0 o.o

1

0 . 0 9 9 8 3 3 4 1 6 6 4 6 8 2 8 1 5 I 2

0 . 1 9 8 6 6 9 3 3 0 7 9 5 0 6 1 2 2

1 0 . 2 9 5 5 2 0 2 0 6 6 6 1 3 3 9 5 5 ' 1

0 . 3 8 9 4 1 8 3 4 2 3 0 8 6 5 0 5 I

0 . 4 7 9 4 2 5 5 3 8 6 0 4 2 0 3 f ,

0 . 5 6 4 6 4 2 4 7 3 3 9 5 0 3 5 4 7

0 . 6 4 4 2 1 7 6 8 7 2 3 7 6 9 1 I

0 . 7 1 7 3 5 6 0 9 0 8 9 9 5 2 2 8 ‘ i

0 . 7 8 3 3 2 6 9 0 9 6 2 7 4 8 3 4

I o esencial en este programa es que el fichero datosl. txt debe asociarse a mi l

uputstream mediante la instrucción:

Iuputstream input=

getResources().openRawResource(R.raw.datosl);

ÜS ta mi fw

Comprueba almace

Estaco:rnounted narmenlo

Nuevo directorio:/:

Contenido de] dírec

>dcard/datos

»,:o

L05TDIR downloati datos

Fichero grabado

Page 69: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 68

Usamos el mismo main.xml de la aplicación anterior. El programa Java de nuestra

actividad es el siguiente:

public class LeerFichero extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState); setContentView(R.layout.main);

TextView tv=(TextView)fìndViewByld(R.id.texto);

tv.append("\nLeer datos de res/raw/datosl.txt:" ) ; InputStream input=

getResources().openRawResource(R.raw.datosi); InputStrearaReader

stream=

new InputStreamReader(input);

BufferedReader buffer =

new BufferedReader(stream,8192);

try {

String linea; while(true)

{

linea=buffer.readLine() ; if(linea==null)

break; tv.append("\n"+linea); }

input.close();

stream.close();

buffer.close();

}catch(Exception e) { tv.append("\n "+e);

} tv.append("\nEnd of file");

} }

El resultado tras leer el fichero se muestra en la pantalla de la figura 7.3.

Page 70: Android

g|«3 2:C2m I

ANHKOID PROGRAMACIÓN DE DISPOSITIVOS MÓVIII '.A IHAVI'Mil I II MCI OS 69

Comprueba almacenamiento leer

datos de res/raw/datosl.txt: 0 0,0

1 0.09983341664682815

2 0.19866933079506122

3 0.2«S52020666:133955

4 0.3894183423086505

5 0.479425538604203

6 0.5646424733950354

7 0.644217687237691

8 0.7173560908995228

9 0.7833269096274834

End of file

Page 71: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 70

Figura 7.3. Lee un fichero de datos en el directorio res/raw de la aplicación.

Page 72: Android

71 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

8. GRÁFICOS

El paquete android.graphics proporciona herramientas gráficas para dibujar directamente en

la pantalla. Ilustraremos cómo se dibuja sobre un objeto de la clase Canvas (que

correspondería al lienzo sobre el que se pinta) utilizando un objeto de tipo Paint (herramienta

que contiene los colores y estilos de dibujo).

8.1. Dibujando en un Canvas

La siguiente aplicación muestra en pantalla un objeto gráfico de tipo View. No se necesita

el fichero main.xml. Todo está definido en código Java.

La parte gráfica se define en el método onDraw(Canvas canvas). Primero se crea un

objeto Paint:

Paint paint = new Paint ();

y luego usamos sus métodos para cambiar el color, tamaño de texto, etc. Por ejemplo,

para pintar de blanco:

paint.setColor(Color.WHITE);

El canvas se pinta entero de este color llamando al método:

canvas.drawPaint(paint)

Para dibujar algo sobre el canvas se dan las coordenadas, (x,y) , y el objeto paint. Por

ejemplo, para dibujar un texto:

canvas.drawText("texto",x,y,paint)

y para dibujar una línea uniendo los puntos (xi,yi) y (x2,y2):

canvas.drawLine(xl,yl,x2,y2,paint);

I ii este ejemplo escribimos en las coordenadas (20,40) la anchura y la altura ni i nnvas.

Dibujamos también una linea horizontal y otra vertical que pasan por ■ i punto.

publ i c c lass Graf icosl ex tends Act ivi ty {

^Override

publ i c void onCreate(Bundle savedlnstanceState) {

super.onCreate (savedlns tanceState );

Graf icoView gráf ico =new Graf i coView (thi s) ;

setContentView (gráf i co) ; )

private c lass Graf i coView ex tends View {

publ i c Graf icoView (Contex t contex t) {

super(contex t) ;

Page 73: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 72

}

uuOverr ide protected void onDraw (Canvas canvas ) {

super.onDraw (canvas );

Paint paint=new Paint( ) ;

paint . setColor(Color.WHITE);

canvas.draw Paint (paint) ; int

w idth=canvas.getw i dth() ; int

heig ht=canvas.getHeig ht ( ) ;

paint . setColor(Color.BLACK);

paint . setTex tSize(30) ;

paint . setAntiAl ias ( true) ;

canvas.draw Tex t("w idth= "+w idth+", heig ht= "+heig ht ,

20 ,40 ,paint) ;

paint . setColor(Color. rg b(100 ,20 ,0)) ;

canvas.draw Line(0 ,40 ,w idth,40 ,paint) ;

paint . setColor(Color. rg b(0 ,100 ,20)) ;

canvas.draw Line(20 ,0 ,20 ,heig ht ,paint) ; }

I I lesultado lo vemos en la figura 8.1.

Figura 8.1. La anchura y altura del canvas.

Page 74: Android

mIMI ill) l'l-tOGRAMACIÓN DE DISPOSITIVOS MÓVII I A IMAVI'MII I II WPLOS 73

8.2. Formato del texto

En la siguiente actividad ilustramos distintos métodos de Paint para cambiar las

propiedades del texto: alineamiento, inclinación, escalado, estilo de fuente y antialias. El

resultado se ve en la figura 8.2.

public class Graficos2 extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

GraficoView gráfico =new GraficoView(this);

setContentView(gráfico); }

private class GraficoView extends View{

public GraficoView(Context context) {

super(context); }

@Override protected void onDraw(Canvas canvas){

super.onDraw(canvas);

Paint paint=new Paint ()

paint.setColor(Color.WHITE);

canvas.drawPaint(paint);

int width=canvas.getWidth(); int

height=canvas.getHeight(); paint.setTextSize(30);

paint.setAntiAlias(true);

paint.setColor(Color.rgb(0,100,20));

canvas.drawLine(width/2,0,width/2,height,paint);

paint.setColor(Color.BLACK);

paint.setTextAlign(Align.RIGHT);

canvas.drawText("Align.RIGHT",width/2, 160, paint);

paint.setTextAlign(Align.CENTER);

canvas .drawText ("Align. CENTER11, width/2 , 12 0,

paint) paint.setTextAlign(Align.LEFT);

canvas.drawText("Align.LEFT",width/2, 80, paint);

paint.setTextSkewX(0.2f);

canvas.drawText("SkewX 0.2",20, 210, paint);

paint.setTextSkewX(-0.2f);

canvas.drawText("SkewX - 0.2 ", width/2, 210, paint);

paint.setTextSkewX(Of);

paint.setTextScaleX(2 f);

canvas.drawText("TextScaleX 2",10, 250, paint);

Page 75: Android

ANDROID: PROGRAMACI6N DE DISPOSITIVOK MtlVII I ’. A IHAVI Mil II Ml<l OB

paint.setTextScaleX(-2 f);

canvas.drawText("TextScaleX -2",width, 290, paint);

paint.setTextSize(60); paint.setTextScaleX(0.5f);

canvas.drawText("TextScaleX 0.5",width/2, 360, paint)

paint.setTextScaleX(If); paint.setTextSize(3 0);

paint.setTypeface(Typeface.SANS_SERIF);

canvas.drawText("Sans serif",20, 330, paint);

paint.setTypeface(Typeface.DEFAULT_BOLD);

canvas.drawText("Default bold",20, 370, paint); paint.

setTypeface (Typeface .MONOSPACE) ,-

canvas.drawText("Monospace",20, 410, paint);

paint.setTypeface(Typeface.SERIF);

canvas.drawText("Serif ", 20, 450, paint);

paint.setTypeface(Typeface.DEFAULT);

paint.setTextSize(50); paint.setAntiAlias(false);

canvas.drawText("Antialias false",2D, 500, paint);

paint.setAntiAlias(true);

Page 76: Android
Page 77: Android

74 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

canvas.drawText ("Antialias true",20, 550, paint) }

Ü8S4S S*X?M]

Align.1

Align. RIGHT

SV.ewXO.2 T

extSca I X

Sans serif Default

bold

Monospace

Seri f

Antialias Antialias

Figura 8.2. Controlando propiedades del texto con Paint.

8.3. Altura del canvas

El siguiente ejemplo demuestra que la coordenada y la parte inferior del canvas no

coincide con canvas .getHeight (). Esto se debe a que la altura total del canvas es

igual a la altura de la pantalla completa, que incluye las barras superiores de notificación y

del título de la actividad, cuya altura habría que restar. En el ejemplo de la figura 8.3 esa

diferencia valdría alrededor de 80.

Align.LEFT

ENTER

SkewX-0.2

eX 2 IBD2JX9T

TextScaleX0.5

false true

Page 78: Android

TSÍÜ®

S:Z8PM1

Nl H(( )ll): PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '.A IKAVI' III I II MI'I Oí;

Gráficos 3

lSff _____

—2JJL

height= 800

Figura 8.3. Examinando la altura efectiva del canvas.

public class Graficos3 extends Activity {

/** Called when the activity is first created.

@0verride

public void onCreate(Bundle savedlnstanceState)

super.onCreate(savedlnstanceState);

SpecialView myView= new SpecialView(this);

setContentView(myView);

private class SpecialView extends View{

public SpecialView(Context context) {

super(context); }

©Override protected void onDraw(Canvas canvas){

int width=canvas.getWidth(); int

height=canvas.getHeight();

canvas.drawColor(Color.WHITE);

Paint paintBlack=new Paint();

Paint paintGray=new Paint();

paintBlack.setColor(Color.BLACK);

paintGray.setColor(Color.GRAY);

—-

San

420__

Page 79: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 76

for(int i = 3O;í<height;i+=3O){

canvas.drawLine(0,i, width,i, paintGray);

canvas . drawText (""+1,30,1, paintBlack)

-r }

paintBlack.setTextSize(40) ;

paintBlack.setAntiAlias(true);

canvas.drawText("height= "+height,

100,height/2,paintBlack);

}

}

}

8.4. Dimensiones del canvas

En el siguiente ejemplo demostramos que las dimensiones correctas del canvas pueden

obtenerse con los métodos de la clase View: getMeasuredWidth () ;

getMeasuredHeight () ; o alternativamente con getBottom () ; getRight ()

;

Figura 8.4. Examinando la altura efectiva del canvas.

En la figura 8.4 vemos que onDraw() dibuja dos líneas uniendo las esquinas opuestas

del canvas y escribe los valores obtenidos con los anteriores métodos:

public class Formas extends Activity \

/** Called when the activity is first created. */

H« 9:33 AM Formas

Page 80: Android

ANUROID: PROGRAMACIÓN DE DISPOSITIVOS MOVII I HA INAVÉ'i IJI- I .II MI'IOS 77

(©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

SpecialView myView = new SpecialView(this);

setContentView(myView); }

class SpecialView extends View{

public SpecialView(Context context) {

super(context);

// TODO Auto-generated constructor stub }

@Override

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.WHITE);

Paint paint=new Paint();

paint.setColor(Color.BLACK);

paint.setTextSize(30);

paint.setAntiAlias(true);

int width=getMeasuredWidth();

int height=getMeasuredHeight();

int bottom=getBottom();

int right=getRight();

paint.setTextAlign(Align.CENTER);

canvas.drawText("Width "+width, width/2,40,paint);

canvas.drawText("Height "+height, width/2,80,paint)

canvas.drawText("Right "+right, width/2,120,paint);

canvas . drawText ("Bottom-' "+bottom,

width/2,160,paint);

paint.setColor(Color.BLUE);

canvas.drawLine(0,0,right,bottom, paint);

canvas.drawLine(right,0,0,bottom, paint);

} }

Page 81: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 78

En la figura 8.5 vemos cómo cambian las dimensiones cuando giramos el ■ Ir.positivo.

Esto se puede hacer en el emulador mediante las teclas Ctrl-F11.

8.5. Formas geométricas

En la siguiente aplicación mostramos cómo dibujar círculos y cuadrados de varios colores y

luego pintamos su perímetro de color negro con distintas anchuras de trazo. El canvas lo

enmarcamos dibujando un rectángulo. El resultado se ve en la figura 8.6.

Figura 8.6. Formas geométricas.

li H« 95?AM ••, Í :s:• ; - •

IMS «1:48 PM Formas2

8 ■

• ■

Page 82: Android

-M JIIHOID PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

public class Formas2 extends Activity {

©Override

public void onCreate{Bundle savedlnstanceState)

super.onCreate(savedlnstanceState); SpecialView myView=new

SpecialView(this); setContentView(myView); )

class SpecialView extends View{ public SpecialView(Context

context) { super(context); }

©Override protected void onDraw(Canvas canvas){

int bottom=getBottom();

int right=getRight();

canvas.drawColor(Color.WHITE);

Paint paint=new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.FILL);

paint.setColor(Color.RED);

canvas.drawCircle(50,50,30,paint);

canvas.drawRect(150,50,200,100, paint);

paint.setColor(Color.BLUE);

canvas.drawCircle(50,100,30,paint);

canvas.drawRect(150,150,200,200, paint);

paint.setColor(Color.GREEN);

canvas.drawCircle(50,150,30,paint);

canvas.drawRect(150,250,200,300, paint)

paint.setColor(Color.MAGENTA);

canvas.drawCircle(50,200,30,paint);

canvas.drawRect(150,350,200, 400, paint);

paint.setColor(Color.BLACK);

paint.setStyle(Paint.Style.STROKE);

canvas.drawCircle(50,50,30,paint); canvas . drawCircle

(50,100, 30,paint) canvas.drawCircle(50,150,30,paint);

canvas.drawCircle(50,200,30,paint);

canvas.drawRect(150,50,200,100, paint);

paint.setStrokeWidth(2);

canvas.drawRect(150,150,200,200, paint);

paint.setStrokeWidth(4); canvas.drawRect(150,250,200,300,

paint); paint.setStrokeWidth(6);canvas.drawRect(150,350,200,400, paint);

canvas.drawRect(10,10,right-10rbottora-10r paint);

}

}

}

Page 83: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 81

8.6. Curvas

En el siguiente ejemplo mostramos cómo se define una curva mediante un objeto de tipo

Path compuesto de muchas lineas, que se añaden al path mediante path.lineTo(). Esta

curva se puede trasladar mediante path.offset () y dibujar con distintos estilos de línea:

discontinua, puntos y trazos, puntos, etc. Para ello se usa paint.setPathEffect(). En este

ejemplo dibujamos la función sin(x). El resultado se ve en la figura 8.7.

Figura 8.7. Curvas. Representación gráfica de la función sin(x).

public class Curvas extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super . onCreate (savedlnstanceState) ,-

SpecialView myView = new SpecialView(this);

setContentView(myView); }

public SpecialView(Context context) {

super(context); }

@Override

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.WHITE);

Paint paint=new Paint ();

paint.setColor(Color.BLACK);

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(2);

paint.setAntiAlias(true);

int width=getMeasuredWidth();

int height=getMeasuredHeight();

»««12:39PM Curvas

Page 84: Android

class SpecialView extends View{

iHOIt) PROGRAMACIÓN DE DISPOSITIVOS MÓVILI SA FRAVI ' . 1)1 I ,11 MIM OS

Path path=new Path(); path.moveTo(0

, 0) ; for(int i=l;i<width;i++){

path.lineTo(i, (float) Math.sin(i/20f)*(-50f)) } path.offset(0,100);

canvas.drawPath(path,paint);

float [] intervalos={lO, 10} ;

DashPathEffect dash =

new DashPathEffeet(intervalos,1);

paint.setPathEffeet(dash); path.offset(0,100) ;

canvas.drawPath(path,paint);

float[] intervalos2={10 ,10,2,10};

DashPathEffeet dash2 =

new DashPathEffeet(intervalos2,0)

paint.setPathEffeet(dash2); path.offset(0,100);

canvas.drawPath(path,paint);

float [] intervalos3={2 , 4};

DashPathEffeet dash3 =

new DashPathEffeet(intervalos3,0)

paint.setPathEffeet(dash3); path.offset(0,100);

canvas.drawPath(path,paint);

}8.7. Traslaciones y rotaciones

El canvas puede sufrir traslaciones y rotaciones aparte de otras transformaciones más

generales. En el siguiente ejemplo realizamos una traslación y una rotación. La rotación se

realiza con respecto al punto medio de un texto que se va a rotar. El rectángulo que limita al

texto (bounding box) se dibuja en rojo antes de la rotación. El canvas vuelve a su posición

inicial con canvas . restore (). El resultado se ve en la figura 8.8.

Tras la rotación

5:08 PM Rotaciones

Page 85: Android

83 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

Figura 8.8. Rotación del canvas.

public class Rotaciones extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

SpecialView myView = new SpecialView(this);

setContentView(myView); }

class SpecialView extends View{

public SpecialView(Context context) {

super(context); } @0verride protected void onDraw(Canvas canvas){

Page 86: Android
Page 87: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVIL! 8 A IUAVI- 1)1 I II MPl OS 84

canvas.drawColor(Color.WHITE);

Paint paint=new Paint(); paint.setTextSize(40); paint.setAntiAlias(true);

// Traslada el origen del canvas int x= 50; int y=150; canvas.translate(x,y);

// Rectangulo bounding-box de un texto String texto="Rotacion del canvas";

Rect bounds= new Rect();

paint.getTextBounds(texto,0,texto.length(),bounds);

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.STROKE);

canvas.drawRect(bounds,paint);

//centro del rectangulo

float centerX=bounds.exactCenterX();

float centerY=bounds.exactCenterY();

//rotacion del canvas

canvas.rotate(-45,centerX,centerY);

paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.FILL);

canvas.drawText(texto,0,0,paint);

// restablece el canvas canvas . restore () ,- canvas.drawText("Tras la rotacion",100,300,paint);

} }

H.8. Texto siguiendo una curva

l l siguiente ejemplo define una curva Path conteniendo un círculo y luego escribe un texto

siguiendo la curva con canvas .drawTextOnPath (). El parámetro >1 fset define la distancia

vertical del texto (perpendicular a la curva), mientras '|in> hoffset define la distancia

horizontal del texto (a lo largo) al origen de la i urva. Este método nos da total control sobre

la dirección que sigue un texto. El nfecto se ve en la figura 8.9.

Page 88: Android

ANt)!«ÍID PROGRAMACIÓN DE DISPOSITIVOS MOVIII '.A IHAVffllll I II MPL0S 8 5

Figura 8.9. Texto en una curva.

public class TextOnPath extends Activity {

(»Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState); SpecialView myView

= new SpecialView(this); setContentView(myView);

class SpecialView extends View{

public SpecialView(Context context) {

super(context); }

@Override

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.WHITE);

Paint paint=new Paint();

paint.setTextSize(60);

paint.setAntiAlias(true); int

width=getWidth();

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.STROKE) ;

Path path=new PathO ;

Direction dir=Direction.CW; float radio=10 0;

path. addCircle (width/2, 20 0, radio, diz-) ;

path.offset (0, 0);

float h0ffset=0;

float v0ffset=-20;

canvas.drawPath(path, paint) ,■

paint.setColor(Color.BLACK);

canvas.drawTextOnPath("texto en path externo",

path, hOffset, vOffset, paint);

v0ffset=20; hOf f set=100 ,-

paint.setStyle(Paint.Style.FILL);

paint.setTextSize(20);

canvas.drawTextOnPath("texto interior comenzando a "

+hOffset+" del punto inicial",

path, hOffset, vOffset, paint);

}

}

}

Page 89: Android

86 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

H.9. Caracteres Unicode

Muchos caracteres especiales pueden escribirse usando el código Unicode. El Mliuiente

programa escribe algunos de ellos. Nótese que algunos códigos no nNlán soportados en

nuestro emulador, figura 8.10.

class SpecialView extends View{

public SpecialView(Context context) {

super(context); }

@Override

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.WHITE);

Paint paint=new Paint(); paint.setTextSize(30) ;

paint.setAntiAlias(true); int width=getWidth(); int

height=getHeight();

paint.setColor(Color.BLACK); canvas.drawText("Unicode ", 4 0,40,paint);

Page 90: Android
Page 91: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

canvas . drawText ("http: //ww. Unicode

. org", 2 0 rheigh.t-10,paint) ;

paint.setTextSiz

canvas.drawText(

canvas.drawText(

canvas.drawText[

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

canvas.drawText(

(20) ;

\u222B \\u222B"

\u2202 \\u2202"

\u22 06 \\u2207

™ \u22 0A

\\u220A" \u2297

\\u2297" \u22S4

\\u2264" \u2265

\\u2265" \u2218

\\u2218" \u2243

\\u2 243"

\u221A \\u221A"

\u221B \\u2

21B" \u222C

\\u222C" \u222D

\\u222D"

20,70,paint);

20,100,paint)

20,13

0,paint)

20,160,paint)

20,190,paint)

20,210,paint)

20,240,paint)

20,270,paint)

20,300,paint)

20,33

0,paint)

20,36

0,paint)

20,39

0,paint)

20,420,paint)

int w=width/3;

canvas.

drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

canvas.drawText

"\u03Bl

\\u03Bl"

"\u03B2 \\u03B2"

"\u03B3 \\u03B3"

"\u03B4 \\u03B4

" "\u03B5

\\u03B5" "\u03B6

\\u03B6" "\u03B7

\\u03B7" "\u03B8

\\u03B8" "\u03B9

\\u03B9" "\u03BA

\\u03BA" "\u03BB

\\u03BB" "\u03BC

\\u03BC" "\u03BD

\\u03BD" "\u03BE

\\u03BE" "\u03BF

\\u03BF" w, 70

,paint) ,- w,

100,paint)

w,130,paint)

w,16 0,paint)

w,190,paint

)

w,210,paint

) w,24

0,paint)

w,270,paint

)

w,300,paint

) w,33

0,paint)

w,360,paint

) w,3

90,paint)

w,420,paint

)

w,450,paint

) w,4

80,paint)

Page 92: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

w=2*width/3;

canvas.drawText "\u03Cl \\u03Cl" ,

w.

7 0,paint) ;

canvas.drawText "\u03C2 \\u03C2", w.

100,paint)

canvas.drawText "\u03C3 \\u03C3", w,

130,paint)

canvas.drawText 11

\u03C4 \\u03C4", w

, 160,paint)

canvas.drawText "\u03C5 \\u03C5", w,

190,paint)

canvas.drawText "\u03C6 \\u03C6", w

, 210,paint)

canvas.drawText "\u03C7 \\u03C7", w

. 240,paint)

canvas.drawText "\u03C8 \\u03C8", w.

2 70,paint) canvas.drawText "\u03C9 \\u03C9", w

. 3

00,paint) canvas.drawText "\u03CA \\u03CA", W,

330,paint)

Page 93: Android
Page 94: Android

ANIlROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII .A 1HAVÍ ' • OI • »1 MIMOS 87

canvas.drawText("\u03CE

canvas.drawText{"\u03CC

canvas.drawText("\u03CD

canvas . drawText (

"\u.03CE canvas .

drawText ( M\u.03CF

canvas.drawText("\u03a3

canvas.drawText("\u03aS

canvas.drawText("\u03a8

canvas.drawText("\u03a9

\\u03CB", w,360,paint)

\\u03CC", w, 3 90,

paint ) \\u0 3CD",

w,420,paint) \\u03CE",

w,4 50,paint) \\u0

3CF", wr4 80,paint)

\\u03a3", 10,520,paint)

\\u03a6", 10,560,paint)

\\u03a8", 10,600,paint)

\\u03a9", 10,640,paint)

http://www.unicode.org

Figura 8.10. Texto Unicode.

H 10. LayoutParams

I Insta ahora en este capítulo las dimensiones de nuestros objetos gráficos de tipo Vluw han

sido controladas por el sistema, ocupando toda la parte disponible de la puntada. Estas

dimensiones pueden controlarse externamente para añadir objetos v/iow de un tamaño

determinado a un layout. Para ello primero creamos un objeto iUi tipo LayoutParams, que

almacena las dimensiones de anchura y altura, y luego .dignarnos esa geometría a nuestro

gráfico mediante el método ■i)tLayoutParams(params) de la clase View: Layout Pa raras par arris=

new LayoutParams{int anchura,int altura);

viewl.setLayoutParams(params);

iCl ffl 4Ü 7:32 PM I Unicode

J \u2226 a\u03B1 p\u03C1 d\U2202 ß \uQ3B2 <; \u03C2 AVu2207 y \u03B3 O \U03C3 D 'OJ220A 5 \u03B4 X \u03C4 ®\u2297 E \u03B5 U\U03C5 á\u2264 t, \u03B6 tp \u03C6 â\U2265 H\u03B7 X \U03C7 0\U2218 0 UJ03B8 ^\u03C8 0\U2243 i \u03B9 u\U03C9 V\u221A K \U03BA i\U03CA D\U221B X\U03BB ü \u03CB // \U222C |J \u03BC ó \U03CC Ö \U222D V \U03BD ú \u03CD

Ç \U03BE ib \u03CE 0 \u03BF D\u03CF

I\u03a3 cp \u03a6 ^\u03a8 Q\u03a9

Page 95: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 88

En el siguiente ejemplo añadimos tres gráficos a un layout con tres geometrías distintas.

Cada gráfico contiene un texto con sus dimensiones y un color de fondo. Utilizaremos la

siguiente interfaz de usuario:

<?xml version="l.0" encoding="utf-8"?>

<LinearLayout

xmlns : android= "http : //schemas . android.

com/apk/res/android11 android:orientation="vertical"

android:layout_width="f ill_parent" android:

layout_height= "f ill_parent11 android:id="@+id/layout"

android:background="#ffffff">

<TextView android:text="LayoutParams"

android:id="@+id/textViewl"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</TextView>

</LinearLayout>

El programa Java para dibujar tres gráficos con distintas anchuras y alturas y añadirlos

a un layout es el siguiente:

package es . amaro. ugr.. layoutparametros ;

import android.app.Activity;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Rect;

import android.os.Bundle; import

android.view.View;

import android.view.ViewGroup.LayoutParams;

import android. widget. LinearLayout ,-

public class LayoutParametros extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

LinearLayout 11=

(LinearLayout)findViewByld(R.id.layout);

Page 96: Android

ANl ll*i >11) PROGRAMACIÓN DE DISPOSITIVOS MÓVII I ü A IKAVI'u 01 I .11 MPLOS

// obtiene dimensiones del layout en un rectángulo. // en este

caso, las dimensiones de la pantalla Rect window=new Rect()¡

11.getWindowVisibleDisplayFrame(window)

// define un objeto View con anchura w y altura h // En este

caso la anchura de la pantalla int w = window.width(); int

h=l00;

String texto="Anchura "+w+", Altura "4h; int

color=Color.argb(100 , 100 , 0 , 0) ;

SpecialView viewl=new SpecialView(this,color,texto)

LayoutParams params= new LayoutParams(w,h);

viewl.setLayoutParams(params);

11.addView(viewl);

// define segundo objeto View w=4 0 0; h=2 0 0;

texto="Anchura "+w+", Altura "+h;

color=Color.argb(100,0,100,0);

SpecialView view2=new SpecialView(this,color,texto) params=new

LayoutParams(w,h); view2.setLayoutParams(params);

11.addView(view2) ;

// define tercer objeto view w=350; h=350;

texto="Anchura "+w+", Altura "+h;

color=Color.argb(100,0,0,100);

SpecialView view3=new SpecialView(this,color,texto) params=new

LayoutParams(w,h); view3.setLayoutParams(params);

11.addView(view3);

}

// clase que extiende a View.

//Escribe un texto y un color de fondo class

SpecialView extends View{

int color;

String texto;

public SpecialView(Context context,

int color,String texto) {

super(context);

Page 97: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 90

this.color=color; this.texto=texto; }

protected void onDraw(Canvas canvas){

canvas.drawColor(color) ;

Paint paint=new Paint();

paint.setAntiAlias(true);

paint.setColor(Color.BLACK);

paint.setTextSize(25) ;

canvas.drawText(texto, 50, 50, paint);

}

}

}

El resultado se ve en la figura 8.11. El primer objeto view tiene una anchura de 480

pixeles, igual a la de la pantalla. Esta anchura la hemos obtenido a partir de las dimensiones

del layout (en este caso, de la pantalla completa), almacenándolas en un rectángulo usando

el método getwindowVisible DisplayFrame(Rectwindow):

Rect window=new Rect();

11.getWindowVisibleDisplayFrame(window);

int w = window.width();

Page 98: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 91

Los otros dos objetos tienen anchuras de 400 y 300 pixeles, respectivamente, y

distintas alturas.

Figura 8.11. Controlando anchura y altura de los gráficos con LayoutParams.

Page 99: Android
Page 100: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII FUA IRAVI' MJI I Jl Ml'l OS

<> GRÁFICOS INTERACTIVOS

i . 1 pantalla táctil es una parte esencial de los dispositivos móviles, que U"iieralmente no

tienen teclado. Android “escucha” o “siente” los eventos que ocurren cuando tocamos la

pantalla o cuando arrastramos los dedos por ella. Ya liónos visto ejemplos de ello al definir

el método onClick() para los botones. En nulo capítulo introduciremos el método

onTouchEvent () de la clase View. Este un «lodo nos permite ir más allá de los botones

e interaccionar directamente con los

0 ificos, mover objetos e incluso dibujar nosotros mismos en la pantalla.

11.1. Evento ACTION_DOWN

1 . 1 siguiente actividad ilustra el uso del método onTouchEvent (Event). Este

un-lodo se ejecuta cada vez que tocamos la pantalla. Su argumento es un Evento, un

objeto que “la pantalla le pasa” a nuestra actividad con la información de las

■ oordenadas donde ha tenido lugar el evento. Los valores de las coordenadas se

"hllenen ejecutando los métodos getx() y getY() del objeto Event. En este n|iimplo definimos

un objeto View, dibujamos un círculo rojo en el punto donde la l'.intalla ha sido tocada y

escribimos en la pantalla los valores de las coordenadas

■ i" ese punto. La pantalla debe volver a dibujarse cada vez que hay un evento. I',na

ello ejecutamos el método invalídate O. Una captura de pantalla se muestra en la

figura 9.1.

public class ActionDownActivity extends Activity {

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState) ;

SpecialView myView=new SpecialView(this);

setContentView(myView); }

class SpecialView extends View{ float x=50; float y

= 50;

public SpecialView(Context context){

super(context); }

(©Override

protected void onDraw(Canvas canvas){ canvas . drawColor

(Color.LTGRAY) ;

Paint paint=new Paint();

paint.setAntiAlias(true);

paint.setColor(Color.RED);

canvas.drawCircle(x,y,20, paint);

paint.setColor(Color.BLACK);

paint.setTextSize(35);

canvas.drawText("x= "+x, 100, 50, paint);

canvas.drawText("y= "+y, 100, 90, paint); }

Page 101: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

(©Override

public boolean onTouchEvent(MotionEvent evento) {

if(evento.getAction()==MotionEvent.ACTION_DOWN){

x=evento.getX(); y=evento.getY(); invalidate(); } return true; }

}

Figura 9.1. Uso de onTouchEventQ en un evento action down.0 2. Evento ACTION UP

i uando levantamos el dedo de la pantalla, esta recoge el evento action up. I -.lo puede

suceder en el mismo punto en el que pulsamos inicialmente o en otro 'li'.Unto, si arrastramos el

dedo antes de levantarlo. En el siguiente ejemplo se ilii'.tra cómo se controlan estos eventos.

Hemos modificado la actividad anterior .in.idiendo el caso ACTION_UP en el método

onTouchEvent (). Es ilustrativo i'incutar esta aplicación en el emulador, pulsando con el ratón

en un punto de la Imntalla, arrastrando el ratón con el botón pulsado y luego soltarlo. El

programa nmstrará las coordenadas de los puntos donde se pulsó con el ratón (o con el ■ li»lo

en una pantalla táctil) y donde se dejó de pulsar. En la figura 9,2 vemos una i iiptura de pantalla

del caso action up,

UH£3 8:57 AM ActíonDown

/v

y= 299.0 Action

up

là IH fi 8:21 AM ActionDown

x- 430.0 y=

477.0

Page 102: Android

MII iROID: PROGRAMACION DE DISPOSITIVOS MÓVIII ! ¡ A I NAVI' Mil I II Ml 'I OS

Figura 9.2. Uso de onTouchEvent() en un evento action up.

public class ActionDownActivity extends Activity {

©Override

public void onCreate(Bundle savedlnstanceState) {

super. onCreate (savedlnstanceState)

SpecialView myView=new SpecialView(this);

setContentView(myView); }

class SpecialView extends View{ float x= 50; float y=

50;

Page 103: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 94

String texto="Evento"; public

SpecialView(Context context){

super(context); }

@0verride

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.LTGRAY);

Paint paint=new Paint(); paint.setAntiAlias(true);

paint.setColor(Color.RED); canvas.drawCircle(x,y,20,

paint); paint.setColor(Color.BLACK);

paint.setTextSize(35);

canvas.drawText(texto, 100, 130, paint);

canvas.drawText("x= "+x, 100, 50, paint);

canvas.drawText("y= "+y, 100, 90, paint); }

@0verride

public boolean onTouchEvent(MotionEvent evento) {

if(evento.getAction()==MotionEvent.ACTI0N_D0WN){

texto="Action down"; x=evento.getX(); y=evento.getY();

invalidate(); }

if(evento.getAction()==MotionEvent.ACTI0N_UP){

texto="Action up"; x=evento.getX();

y=evento.getY(); invalidate(); }

return true;

}

}

}

9.3. Evento ACTION_MOVE

El evento ACTION_MOVE permite añadir dinámica a nuestra actividad, detectando y siguiendo el

movimiento del dedo cuando se arrastra por la pantalla. Para ilustrar su uso, en la actividad

del ejemplo anterior modificamos el método

onTouchEvent (), quedando asi:

@Override public boolean onTouchEvent(MotionEvent evento) {

Page 104: Android

x=evento.getX();

y=evento.getY();

if(evento.getActionO==MotionEvent.ACTION_DOWN){

texto= "Action down";

if(evento.getAction()==MotionEvent.ACTION_UP)[

texto="Action up";

if(evento.getActionO ==MotionEvent.ACTION_MOVE)

texto="Action move";

invalidate();

return true;

Al ejecutarlo en el emulador y arrastrar el ratón por la pantalla, aparecerá el I nmimuje “Action

move” y los valores numéricos de las coordenadas irán

i mnliiando dinámicamente, siguiendo el movimiento del dedo, así como el círculo l|ti|n

Tendremos pues la sensación de estar arrastrando el círculo por la pantalla. IfllJiii 11 9.3).

X=

132.0 y=

519.0

Action

move

Figura 9.3. Uso de onTouchEventQ en un evento action move.

I

9:19 AM

Page 105: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 96

■ HII">III I'ROGHAMACIÓN DE DISPOSITIVOS MÓVILES A IHAVI'S DI I II MPLOS

Page 106: Android

9.4. Dibujar en la pantalla

Usando la noción de evento en combinación con drawPath () es posible escribir ya una

sencilla aplicación para dibujar en la pantalla. El siguiente ejemplo permite dibujar en color

azul sobre un fondo color crema. En el emulador se dibuja con el ratón. En un dispositivo se

dibujaría con un dedo. Vemos una captura de pantalla en la figura 9.4.

Figura 9.4. Dibujando en la pantalla usando onTouchEvent() en combinación con

drawPatch ().

package es.ugr.amaro.dibujar;

import android.app.Activity; import

android.content.Context; import

android.graphics.Canvas; import

android.graphics.Color; import

android.graphics.Paint; import

android.graphics.Path; import android.os.Bundle;

import android.view.MotionEvent; import

android.view.View;

public class DibujarActivity extends Activity {

/** Called when the activity is first created. *)

@Override

S BE «¡10:11 AM I

Page 107: Android
Page 108: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE I II MI M OS

public void onCreate{Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState); SpecialView

myView=new SpecialView(this); setContentView

(tnyView) ;

class SpecialView extends View{ float x=50; float

y=50;

String accion=" accion"

Path path=new Path();

public SpecialView(Context context){

super(context); }

@Override

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.rgb (255,255,150)) ;

Paint paint=new Paint();

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(6);

paint.setColor(Color.BLUE);

if(accion=="downM){ path.moveTo(x, y); }

if(accion=="move"){ path.lineTo(x, y); } canvas.drawPath(path, paint);

}

@Override

public boolean onTouchEvent(MotionEvent evento) {

x=evento.getX(); y=evento.getY();

if(evento.getAction()==MotionEvent.ACTION_DOWN){

accion="down"; }

if(evento.getAction()==MotionEvent.ACTION_MOVE){

accion="move"; }

invalidate(); return true;

}

}

}

En el siguiente ejemplo usamos la misma técnica para mover dos círculos por la pantalla,

uno rojo y otro azul. El círculo que se debe mover se selecciona, al pulsar la pantalla,

evento action down. Se calcula la distancia al centro de cada círculo. Estamos en el interior

de un círculo si esa distancia es menor que su radio.

package es.ugr.amaro.moverobjetos;

import android.app.Activity; import

android.content.Context; import

android.graphics.Canvas; import

android.graphics.Color; import android. graphics .

Page 109: Android

9.5. Mover objetos

99 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

Paint import android.os.Bundle; import

android.view.MotionEvent; import android.view.View;

public class MoverObjetosActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

SpecialView myView=new SpecialView(this);

setContentView(myView); }

class SpecialView extends View{

float[] x={50,50};

float[] y={50,15 0};

float[] radio={40,60};

Paint paint[]=new Paint [2] ;

Paint p;

int seleccion=-l;

String texto="Mueva los circulos";

public SpecialView(Context context){

super(context); paint[0]=new

Paint(); paint [1] =new Paint();

paint [0] .setColor(Color.RED) ;

paint [1] .setColor(Color.BLUE);

p=new Paint(); p.setTextSize(30);

p.setColor(Color.BLACK); }

@Overríde

protected void onDraw(Canvas canvas){

canvas.drawColor(Color.WHITE);

canvas.drawText(texto,2 00,50,p);

for(int i=0;i<2;i++){

canvas.drawCircle(x[i],y[i],radio[i], paint[i]); } }

@0verride

public boolean onTouchEvent(MotionEvent evento) {

float newX= evento.getX(); float

newY=evento.getY();

if(evento.getAction()==MotionEvent.ACTI0N_D0WN){

// indice del circulo seleccionado // -1 si no

hay selección seleccion=-l; for(int

i=0;i<2;i++){

Page 110: Android

ANDROID: PROGRAMACION DE DISPOSITIVOS MÓVII ES A IRAVÉS DE EJEMPLOS

// Calcula la distancia al centro de cada

circulo

double dx=newX-x

[i]; double dy=newY-

y[i]; float

distancia= (float)

Math.sgrt(dx*dx+dy*dy);

if (distancia <= radio[i]){

// Si estamos dentro de algún circulo lo

seleccionamos

seleccion=i;

texto="Selección "+i;

invalidate();

}

}

}

if(evento.getAction()==MotionEvent.ACTION_MOVE){

if (selección > -1){

// si hay un circulo seleccionado lo trasladamos

al nuevo punto

x

[selección]=newX;

y

[selección]=newY;

invalidate(); }

} return true;

} }

Selección 1

Figura 9.5. Moviendo objetos por la pantalla con touchEvent () .

Page 111: Android
Page 112: Android

ANUHOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 1 0 1

10. IMÁGENES

10.1. Insertar una imagen en el layout

l I sistema Android soporta imágenes en formato png, jpg y gif. Para insertar una Imagen en

una aplicación hay que copiar el fichero con la imagen en la carpeta i f'ií/drawable. Por

defecto, hay tres carpetas, drawble-hdpi, drawable- lilpi y drawable-mdpi,

correspondientes a resolución alta, baja y media, rnspectivamente, que serán seleccionadas

por la aplicación dependiendo de la disolución de pantalla del dispositivo que se util ice. En el

siguiente ejemplo, mnamos una nueva aplicación y copiamos nuestra imagen portada.jpg

en la oarpeta res/drawable-hdpi. A continuación, modificamos el fichero main.xml,

nriiidiendo una etiqueta imageview de la siguiente forma:

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

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android: orientation=11 vertical"

android:background="#ddffdd"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#000000"

android:text="ANDROID ESENCIAL"

android:layout_gravity="center"/>

• ImageView

android:layout_height="wrap_content"

android:src="@drawable/portada"

android:layout_width="wrap_content"

android:id="@+id/imageViewl">

«. /ImageView>

*/LinearLayout>

Page 113: Android

I 02 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉ 9 DE EJEMPLOS

Con esta estructura, la imagen se añade al layout y no es necesario hacer nada más. Al

ejecutar la aplicación la Imagen se muestra en la pantalla como en la figura 10.1.

Figura 10.1. Imagen insertada en un layout.

10.2. Controlando las imágenes en Java

La siguiente actividad construye un album de fotos. Copiaremos cuatro fotos en la carpeta

res/drawable-hdpi. Diseñamos el layout en main.xml incluyendo la primera de las

fotos. Definimos dos botones para pasar las fotos adelante y atrás.

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

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#ddddbb"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent" >

<TextView

android:textColor="#000000" android:layout_width="f

i1l_parent" android:layout_height="wrap_content"

android:text="ALBUM DE FOTOS. Pulsa los botones para verlas" />

.une 4:48 PM

Page 114: Android

AIIIINOID PROGRAMACIÓN DE DISPOSITIVOS Móvil I 1 • A IUAVf ü 1)1 IJIIMPLOS 1 0 3

• 1,1 nearLayout

HID Ins:android="http://schemas.android.com/apky res/android"

android:background="#999999"

android:orientation="horizontal"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

>

<Button android:text="Anterior"

android:id="@+id/buttonl"

android:layout_width="wrap_content"

android:layout_height="wrap_content"></Button>

<Button android:text="Siguiente"

android:id="@+id/button2"

android:layout_width="wrap_content"

android: layout_height="wrap_content11 ></Button>

<TextView

android:textColor="#000000" android: id= "(S+id/textViewl"

android:layout_width="wrap_content"

android:layout_height="wrap_content" android:text="Mi bisabuelo" / >

■/LinearLayout>

•imageView android:layout_height="wrap_content" android:src="@drawable/bisabuelo"

android:layout_width="wrap_content"

android:id="@+id/imageViewl"></ImageView>

n/LinearLayout>

A continuación modificamos el fichero Java de la actividad. Cada fichero h'to.jpg tiene una

id llamada R. drawable. foto. Para modificar la foto mostrada primero se define una variable

ImageView y luego se define la imagen a unistrar mediante setlmageResource (id) :

foto=(ImageView) findViewByld(R.id.imageViewl);

foto.setlmageResource(id)

Las Ids de las cuatro fotos las introducimos en un array de enteros. Al pulsar un botón se

avanza o se retrocede el índice de la fotografía a mostrar. El programa i|imda como sigue:

Page 115: Android

UflMB 10:95 PM . llH « 1«« PM

104 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE E JEMPLOS

Figura 10.2. Controlando las imágenes en Java.

import android, app . Activity

; import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button; import

android.widget.ImageView; import

android.widget.TextView;

public class FotosActivity extends Activity implements

OnClickListener{

ImageView foto;

TextView tv; // para escribir el texto de la foto int[]

fotold = {R.drawable.bisabuelo,

R.drawable.farmacia,

R.drawable.fernando_amaro,

R.drawable.tres_damas};

String[] texto={"Bisabuelo","Abuelo","Tio","Abuela"};

int i = 0; // numero de foto

int total; // numero total de fotos

/** Called when the activity is first created. */

@0verride

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Button anterior^(Button) findViewByld(R.id.buttonl);

Page 116: Android

101 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

Button siguiente={Button} findViewByld(R.id.button2)

anterior.setOnClickListener(this);

siguiente.setOnClickListener(this);

tv=(TextView) findViewByld(R.id.textviewl);

foto={ImageView) findViewByld(R.id.imageViewl); total =

fotold.length;

}

public void onClick(View v) { int id=v.getld();

// boton2 adelanta el numero de foto

if(id==R.id.button2){

i++; if (i == total) i=0; }

// botonl atrasa el numero de foto

if(id==R.id.buttonl){

i-~; if (i == -1) i=total-l; }

foto.setlmageResource(fotold[i] ) ;

tv.setText("Mi "+texto[i]);

I I resultado del album de fotos se ve en las figuras 10.2 y10.3.

S U ® - 10:06 PM

L8UM DE FOTOS. Pulsa los botones para verías

Figura 10.3. Controlando las imágenes en Java.

Smm Siguiente Mi Tío

Page 117: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I S A TRAVÉS DE EJEMPLOS 106

10.3. Botones con imágenes

Un ImageButton es un tipo especial de view que es un botón con una imagen

superpuesta. La forma de definir un ImageButton en xml es la siguiente:

<ImageButton

android:background="#00000000"

android:scaleType="centerCrop"

android:layout_weight="1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/botonl"

android:id="@+id/imageButtonl"><JImageButton>

Al hacer el fondo transparente no se verá el botón de fondo. Sólo la imagen:

android:background="#00000000"

Existen distintos tipos de escala que se pueden aplicar a la imagen como center o

centerCrop. Esta última escalará la imagen a la anchura total disponible y cortará los

márgenes.

android:scaleType="centerCrop"

En el siguiente ejemplo definimos cuatro botones con cuatro fotografías.

Figura 10.4. Uso de ImageButton.

Niels Bohr (1885-1962). Contribuyó a la

comprensión de la estructura del

átomo.Premio Nobel 1922

Page 118: Android

llMoID PROGRAMACIÓN DE DISPOSITIVOS MÓVIl E::¡ AIHAVÍSIJI I II MI’IOS 1 0 7

Page 119: Android

1 0 8 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJE MI'I (III

• Vxml version=" 1.0" encoding="utf -8rl ? >

• T.jbleLayout

«in Lns : android="http : / /schemas . android . coin J apk/re

s/an droid" android: stretchColumns="*11

android:background="#ffeecc" android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

T.»bleRow>

■ TuxtView

android: layout__span=" 2 "

android:textSize="20sp"

android:textColor="#000000"

android:layout_gravity="center"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Forjadores de la Física Cuántica" / >

•/TableRow>

T,ibleRow>

■ ImageButton

android:background="#00000000"

android:scaleType="centerCrop"

android:layout_weight="1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/botonl"

android:id="@+id/imageButtonl"></lmageButton>

■ linageButton

android:background="#00000000"

android:scaleType="centerCrop"

android:layout_weight="1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/boton2"

android:id="@+id/imageButton2"></ImageButton>

•/TableRow>

'IMbleRow>

ImageButton

android:background="#00000000"

android:scaleType="centerCrop"

android:layout_weight="1" android: layout_width="

wrap__content" android:layout_height="wrap_content"

android:src="®drawable/boton3"

android:id="@+id/imageButton3"></lmageButton>

clmageButton

android: background = "#00 0 000 0 0''

Page 120: Android

llMoID PROGRAMACIÓN DE DISPOSITIVOS MÓVIl E::¡ AIHAVÍSIJI I II MI’IOS 1 0 9

android:scaleType="centerCrop"

android:layout_weight="1" andró i d:1ayout_w i dt

h="wrap_c ontent"

android:layout_height="wrap_content"

android:src="@drawable/boton4"

android:id="@+id/imageButton4"></ImageButton>

</TableRow>

<TableRow>

<TextView

android:id="@+id/caption"

android: layout_span=112 "

android:textSize="20sp"

android:textColor="#000000"

android:layout_gravity="center"

android: layout_width="wrap_content11

android:layout_height="wrap_content"

android:text="Toque una foto para más info" / >

</TableRow> </TableLayout>

La imagen a mostrar debe estar en una de las carpetas res/drawable y se especifica

mediante drawable/botoni, etc. Esta variable podría referirse a un fichero de imagen,

por ejemplo botonl.png. Pero, en este caso, se refiere a un fichero botonl.xml que hemos

creado en el directorio res/drawable-hdpl conteniendo un selector:

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

<selector

xmlns:android="http://schemas.android.com/apk/res/android"•

citem android:state_pressed="true"

android:drawable="@drawable/bohr_sepia" />

citem android:drawable="@drawable/bohr" />

</selector>

este selector a su vez enlaza con los ficheros bohr. jpg (la imagen mostrada por

defecto) y bohr_sepia.jpg (la imagen mostrada al pulsar el botón) Análogamente hemos

creado otros ficheros llamados boton2.xml, boton3.xml y boton4.xml,

conteniendo referencias a otros pares da imágenes que queremos mostrar.

La siguiente actividad utiliza el fichero main.xml anterior y muestra un mensaje al pulsar

cada botón.

import android.app.Activity;

import android.graphics.Color;

Import android.os.Bundle;

import android.view.View;

Ímport android.view.View.OnClickListener;

import android.widget.TextView;

Page 121: Android

I M'jkage es . ugr. amaro, f is icos cuánticos;

ANI »MOID I 'ROGRAMACIÓN DE DISPOSITIVOS MÓVIII 'lA IIIAVI1'.!)! I II MHOS

public class FisicosCuanticosActivity extends Activity

implements OnClickListener}

TextView caption;

String[] texto={" ",

"Niels Bohr (1885-1962)." +

"Contribuyó a la comprensión de la estructura del

átomo. "Premio Nobel 1922",

"Max Plank (1858-1947). " +

"Sentó las bases de la teoría Cuántica de la materia 11

"e introdujo la constante de Planck." +

"Premio Nobel 1918",

"Pauli. Principio de exclusión. Matrices de Pauli.",

"Schrödinger (1887-1961) Ecuación de Schrödinger, " ■

"Modelo atómico de Schrödinger y Efecto Túnel."+

"Premio Nobel 1933"};

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

caption=(TextView) findViewByld(R.id.caption);

View botonl=findViewByld(R.id.imageButtonl);

botonl.setOnClickListener(this);

View boton2=findViewByld(R.id.imageButton2);

boton2.setOnClickListener(this);

View boton3=findViewByld(R.id.imageButton3);

boton3.setOnClickListener(this);

View boton4=findViewByld(R.id.imageButton4);

boton4.setOnClickListener(this); }

©Override

public void onClick(View v) { int i = 0;

int id=v.getld(); if(id ==

R.id.imageButtonl) i=l; else if(id ==

R.id.imageButton2) i=2; else if(id ==

R.id.imageButton3) i=3;

else if(id == R.id.imageButton4) 1=4;

caption.setTextColor(Color.BLUE);

caption.setText(texto[i]); }

}

Vease captura de pantalla en la figura 10.4. En este caso, cada vez que se pulsa una

imagen, ésta cambia momentáneamente a color sepia y se muestra un texto explicativo

sobre el personaje de la fotografía.

Page 122: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 111

10.4. Insertar imágenes en un canvas

Otra forma de insertar imágenes es “dibujarlas” directamente en un canvas, dentro del

método onDraw() de una clase View. De esta forma, tenemos control total sobre el

posicionamiento, el tamaño y se pueden realizar manipulaciones gráficas. Para dibujar una

imagen primero se declara un objeto de tipo Drawable:

Drawable imagen;

y luego debe definirse la referencia al fichero con la imagen:

imagen=context.getResources().getDrawable(

R.raw.fichero_imagen);

Esto se hará en el constructor de la clase view que definamos. La imagen se dibuja

en el método onDraw (), pero antes es indispensable definir sus dimensiones:

imagen.setBounds(xl,yl,x2,y2); imagen.draw(canvas);

donde (xi,yi) y (x2,y2) son los vértices opuestos del rectángulo que contiene la

imagen. Si estos puntos no se definen, la imagen no se verá en pantalla, pues se le

asignarán dimensiones nulas. Para obtener las dimensiones reales de la imagen se usan

los métodos getintrinsicwidth () , getlntrinsicHeight (). En el siguiente

ejemplo ilustramos esto dibujando en un canvas una imagen jpg, con sus dimensiones

reales (ver figura 10.5).

Page 123: Android
Page 124: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII A IHAVÍS D! I .II Ml’I .OS

Figura 10.5. Insertar imágenes en un canvas.

irt android.app.Activity; irt

android.content.Context; irt

android.graphics.Canvas; irt

android.graphics.Color; irt

android.graphics.Paint;

>rt android.graphics.drawable.Drawable; irt

android.os.Bundle; irt android.view.View;

I'ublic class Dibujarlmagen extends Activity {

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate (savedlnstanceState)

Pintura miPintura = new Pintura(this);

setContentView(miPintura); }

public class Pintura extends View{

Drawable imagen;

public Pintura(Context context) {

super(context);

int indiceImagen=R.drawable.actor_small;

imagen=context.getResources().getDrawable(

indieelmagen);}

@Override

Page 125: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVIL! SA llíAVl N DI I JEMPL.Q!. 113

public void onDraw(Canvas canvas){

Paint p=new Paint();

p.setColcr(Color.WHITE);

canvas.drawPaint(p);

int anchura= imagen.getlntrinsicWidth();

int altura= imagen.getlntrinsicHeight();

imagen.setBounds <0,0,anchura,altura);

imagen.draw(canvas);

}

}

}

El rectángulo que contiene la imagen es arbitrario y la copia se ampliará o reducirá para

caber en él. La relación anchura/altura de la imagen sólo se mantendrá si aplicamos la

misma escala a las dos dimensiones. La misma imagen se puede dibujar múltiples veces

con distintas manipulaciones gráficas. Por ejemplo, en el anterior programa podemos

dibujar dos copias de la misma imagen con distintas dimensiones y posiciones,

sustituyendo el método onDraw() por el siguiente:

@Override public void onDraw(Canvas canvas){

Paint p=new Paint();

p.setColor(Color.WHITE) ;

canvas.drawPaint(p);

imagen.setBounds(0,0,400,200);

imagen.draw(canvas);

imagen.setBounds(100,200,300,700);

imagen.draw(canvas);

}

El resultado se ve en la figura 10.6.

Page 126: Android

ic class Pintura extends View{

114 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

Figura 10.6. Imágenes distorsionadas.

10.5. Ajustar imagen a las dimensiones de la pantalla

Las imágenes que pongamos en la carpeta res/drawable y dibujemos por el método

anterior no pueden tener cualquier tamaño, sino que este debe mantenerse inferior a cierta

cantidad que dependerá del dispositivo utilizado. En general, se recomienda que la imagen

no supere los 2 Megapixeles, lo que corresponde aproximadamente a una imagen de 1200

pixeles de ancho por 1600 de alto (que contiene unos 1.9 Megapixeles). Si se supera esta

cantidad, la línea de código:

Drawable image=getResources().getDrawable(R.drawable.file);

puede producir un error al ejecutarse de tipo NullPointerException. Conviene

pues reducir el tamaño de las imágenes lo más posible, teniendo en cuenta además que la

resolución de las pantallas de los dispositivos móviles, incluso tablets, todavía es inferior a

los 2 Megapixeles. Por ejemplo, el tablet Motorola Xoom con pantalla de 10 pulgadas, tiene

una resolución de 800 x 1280 pixeles, correspondiente a 150 pixeles por pulgada.

En cualquier caso, nuestra imagen siempre podrá reescalarse para ajustarse lo más

posible a la pantalla. En el siguiente ejemplo mostramos una forma de hacerlo. Modificamos

la clase Pintura del ejemplo anterior para leer una imagen que es mayor que la

resolución de la pantalla. La imagen se reescala dependiendo de la razón altura/anchura de

la imagen, comparada con la relación anchura/altura de la pantalla. Si la primera razón es

menor que la segunda, se ajusta el ancho de la imagen al de la pantalla y, en caso

contrario, se ajusta la altura de la imagen a la altura de la pantalla.int indiceImagen=R.drawable.j erry_garcialO 00; Drawable imagen=getResources[).getDrawabLe(indiceImagen);

public Pintura(Context context) { super(context);

Page 127: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVIL! SA llíAVl N DI I JEMPL.Q!. 115

}

@Override public void onDraw(Canvas canvas){

Paint p=new Paint();

p.setColor(Color.WHITE);

canvas.drawPaint(p);

int bottom=getBottom(); int

right=getRight();

float ratioScreen=(float) bottom/right;

int anchuralm= imagen.getlntrinsicWidth(); int

alturalm= imagen.getlntrinsicHeight(); float

ratio= (float) alturalm/anchuralm;

int anchura,altura;

// ajusta el ancho if(ratiocratioScreen){

anchura=right;

altura= (int) (anchura*ratio);

} else {

altura=bottom;

anchura=(int)(altura/ratio); }

imagen.setBounds(0,0,anchura,altura);

imagen.draw(canvas);

p.setColor(Color.RED); p. setTextSize(30);

p.setShadowLayer (1, -3, 2, Color.BLACK);

canvas.drawText(""+anchuralm+"x"+alturalm+" ratio:"+

ratio, 50, 50, p);

canvas.drawText(""+right+"x"+bottom+" ratio:"+

ratioScreen,50,90,p);

canvas.drawText(""+anchura+"x"+altura,50,130,p);

}

Page 128: Android
Page 129: Android

ANUMnil): PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 116

i I resultado se ve en la figura 10.7. Vemos también, en este ejemplo, que se IMitxIe dibujar

o escribir sobre la imagen como cualquier otro objeto gráfico. En este

escribimos en rojo las dimensiones de la Imagen, de la pantalla y de la imagen

mu neniada. Ilustramos también el uso del método setShadowLayer (blur, ■I*, i

[y, Color) de la clase Paint, que permite dibujar la sombra, en este caso del laxln,

para mejorar su contraste con la imagen de fondo. En la figura 10.8 vemos i hmki se ajusta

el alto automáticamente, en lugar del ancho, al girar el dispositivo i1 til 111 en el emulador).

Figura 10.7. Ajustar una imagen en la pantalla y escribir texto sombreado encima.

Figura 10.8. Ajustar una imagen en la pantalla en modo horizontal.

Page 130: Android

117 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I - A IHAVÍMII I .IFMPLOS

11. REPRODUCIR SONIDO

11.1. Uso de MediaPlayer

Los archivos de sonido se reproducen mediante un objeto de la clase MediaPlayer,

perteneciente al paquete android. media. Esta clase soporta varios tipos de formato

de audio, entre los cuales se encuentran los que tienen extensiones wav, mp3 y ogg. Los

archivos de sonido pueden incluirse en la aplicación copiándolos en la carpeta res/raw.

La carpeta raw puede crearse desde Eclipse pulsando con el botón derecho sobre la

carpeta res y seleccionando nueva carpeta. El siguiente paso es copiar nuestros ficheros de

sonido en la carpeta res/raw del proyecto. Es posible que necesitemos renombrar alguno

de estos ficheros, pues sólo son legales los caracteres en minúscula de la a a la z (sin

acentos), los números del 0 al 9 y el guión de subrayado (_). El resto de los caracteres

producirán un error en Eclipse al copiar los ficheros. Por ejemplo, en la siguiente actividad

hemos tenido que cambiar el nombre al fichero Black-Magic-Woman.mp3 por

black__magic_woman.mp3}, pues el guión (-) y las mayúsculas son caracteres

ilegales.

Para reproducir un fichero de sonido hay que crear un objeto de tipo MediaPlayer

mediante la siguiente secuencia de instrucciones:

MediaPlayer mplayer;

// libera el MediaPlayer

if (mplayer != nuil) mplayer. release ()

mplayer = MediaPlayer.create(this, R.raw.fichero);

mplayer.seekTo(0);

mplayer.start();

La segunda instrucción llama al método release (). Esto es esencial para evitar

sobrecargar el sistema con múltiples instancias simultáneas de objetos MediaPlayer, en

cuyo caso la aplicación se abortaría. Hay que tener la precaución también de llamar al método

release <) si la aplicación pasa al background (esto se hace en el método onPause ( ) ) .

La siguiente actividad, basada en el ejemplo “Hola Android”, define un método música

() que reproduce un archivo de música mp3 al ejecutarse. Cuando la actividad pasa al

background la reproducción se detiene.

Page 131: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I s A IKAVC'. Ill I .II MIMOS 118

import android.app.Activity; import android

.media.MediaPlayer ; import android.os.Bundle;

import android.view.View;

public class Reproducir extends Activity{

MediaPlayer mplayer;

@Override

public void onCreate(Bundle savedlnstanceState){

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); música();

}

void música(){

// libera el MediaPlayer if(mplayer !=

null) mplayer.release(); mplayer =

MediaPlayer.create(this,

R.raw.black_magic_woman);

mplayer.seekTo(0);

mplayer.start() ; }

@Override

public void onPause() { super.onPause();

// libera el mediaplayer if(mplayer !=

null) mplayer.release(); }

}

11.2. Reproducir efectos de sonido

l n el siguiente ejemplo utilizaremos varios ficheros de audio con efectos de Nonido, con los

formatos wav y mp3. Se pueden encontrar archivos con efectos de -lonido de libre distribución

que se pueden descargar gratuitamente de varias páginas web. Los archivos de nuestro

ejemplo los hemos descargado de:

http://www.pacdv.com/sounds/people_sounds.html

Como antes, copiamos estos ficheros en la carpeta res/raw de nuestro proyecto. Es

posible que necesitemos renombrar alguno de ellos si contienen

i (IKK:tares ilegales. En esta actividad definimos cuatro bolones para reproducer cuatro

ficheros de sonido.

public class Sonidos extends Activity implements

OnClickListener{

MediaPlayer mplayer;

Page 132: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS Móvil I SA IHAVÉS DE I .11 IMPI O S 1 1 9

/** Called when the activity is first created. */

©Override

public void onCreate(Bundle savedlnstanceState)

{ super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Button botonl=(Button)

findViewByld(R.id.botonl);

botonl.setOnClickListener(this);

Button boton2=(Button)

findViewByld(R.id,boton2);

boton2.setOnClickListener(this);

Button boton3=(Button)

findViewByld(R.id.boton3);

boton3.setOnClickListener(this);

Button boton4=(Button)

findViewByld(R.id.boton4);

boton4.setOnClickListener(this); }

@Override

public void onClick(View v) {

// libera el MediaPlayer

if(mplayer != null) mplayer.release();

int id=v.getld(); if(id ==

R.id.botonl)

mplayer = MediaPlayer.create(this,

R.raw.laugh_l); else if(id == R.id.boton2)

mplayer = MediaPlayer.create(this,

R.raw.laugh_4); else if(id == R.id.boton3)

mplayer = MediaPlayer.create(this,

R.raw.applause2); else

mplayer = MediaPlayer.create (this,

R.raw.peoplelaughingl);

mplayer.seekTo(0); mplayer.start(); }

@Override

public void onPause() { super.onPause();

// libera el mediaplayer en el background

if(mplayer != null) mplayer.release(); }

}

El layout correspondiente a esta aplicación contiene cuatro botones definidos en el

siguiente fichero main.xml de la forma usual (figura 11.1).

<?xml version="l.0" encoding="utf-8"?>

<•. LinearLayout

xmlns :android="http: //schemas .android.com/apk/res/andróid" andró i d:ba

ckground="#ffffff" android:orientation="vertical"

Page 133: Android

1 2 0 ANDROID: PROGRAMACIÓN DE DISPOSITIVAS MÓVILES A TRAVÉS DE EJEMPI ti"i

android:layout_width="fill_parent" android: layout_height=" f ill_parent11

>

<TextView

android:textSize="3Osp"

android:textColor="#000000"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="PULSAR LOS BOTONES PARA ESCUCHAR LOS SONIDOS" /

>

<Button android:text="Risal" android:id="@+id/botonl"

android: layout__width= "f ill_parent" andró i

d:1ayout_he ight="wrap_cont ent">

</Button>

■Button android:text="Risa2" android:id="@+id/boton2"

android:layout_width="fill_parent"

android:layout_height="wrap_content">

</Button>

«Button android:text="Aplausos" android:id="@+id/boton3"

android:layout_width="f i1l_parent"

android:layout_height="wrap_content">

</Button>

cButton android:text="Risas" android:id="@+id/boton4"

android:layout_width="fill_parent"

android:layout_height="wrap_content">

</Button>

</LinearLayout >

PULSAR LOS BOTONES PARA

ESCUCHAR LOS SONIDOS

........................ mi

Page 134: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPI <)B

Figura 11.1. Reproducir efectos de sonido.

12. APLICANDO TEMAS

Un estilo es algún tipo de formato o propiedad que se aplica a un objeto de tipo Viow, como

por ejemplo color del texto, color de fondo, etc. Un tema se aplica a una actividad completa

y permite controlar la apariencia de la pantalla en el fichero AndroidManifest .xml. Los

estilos pueden ser definidos por el usuario, pero Inmbién existen estilos y temas disponibles

en cada versión de Android. Se encuentran en el directorio del android-SDK:

android-SDK/platforms/android-version/data/res/valúes/

Los estilos están definidos en el fichero styles.xml y los temas en themes.xml. En este

capitulo aplicaremos algunos de los temas disponibles.

12.1. Tema por defecto

I lasta ahora hemos venido aplicando el tema por defecto, modificando nosotros a mano el

layout. Usaremos el ejemplo de la figura 12.1 para ilustrar el uso de los distintos temas

disponibles.

Para ello, primero copiaremos una imagen einstein3 0 0 . jpg, que tiene 300

pixeles de ancho en la carpeta drawable-hdpi. El fichero main.xml lo modificamos

como sigue:

Page 135: Android

122 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILS !' A TRAVÉ S DI I .ll-MRLOS

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

cLinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:textSize="2 Osp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Albert Einstein (1879-1955)"

android:layout_gravity="center" />

<ImageView android: layout_height="wrap_coiLtent"

android:layout_width="wrap_content"

android:layout_gravity="cent er"

android:src="@drawable/einstein300"

android:id="@+id/imageViewl"></ImageViews <TextView

android:textSize="20sp" android: layout_width=

"wrap_content11 android:layout_height="wrap_content"

android:text="Tema por defecto"

android:layout_gravity="center" android:id="@+id/texto" / >

</LinearLayout>

Figura 12.1. Tema por defecto.

Page 136: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I S A TRAVÉS DE EJEMPLOS 123

El siguiente fichero Temas . java es el creado por defecto:

import android.app.Activity; import android.os.Bundle;

public class Temas extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceSt ate);

setContentView(R.layout.main);

12.2. Tema NoTitleBar

Ahora editamos el fichero AndroidManifest .xml y aplicamos un tema a

nuestra alicación:

<?xml version="l.0" encoding="utf-8"?>

cmanifest

xmlns:android="http://schemas.android.com/apk/res/android"

package="es.ugr.amaro" android:versionCode="1"

android:versionName="1.0">

<uses-sdk android:minSdkVersion="7" />

<application android:icon="@drawable/icon"

android:label="@string/app_name"

android:theme="@android:style/Theme.NoTitleBar" >

<activity android:name=".Temas"

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>

</manifest>

El tema se aplica en la línea:

android:theme="@android:style/Theme.NoTitleBar" y modificamos

nuestra actividad añadiendo un texto.

public class Temas extends Activity {

/** Called when the activity is first created. */

Page 137: Android

124 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILS !' A TRAVÉ S DI I .ll-MRLOS

@0verride

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Page 138: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A IUAVÉS DF FJEMPLOS 125

TextView texto=(TextVíew) findViewByEd(R.id.texto);

texto.setText("Aplicando el Tema NoTitleBar">;

}

Vemos que este tema hace desaparecer la barra con el título de la actividad.

12.3. Tema Dialog

Para aplicar el tema Dialog volvemos a modificar el fichero

AndroidManifest .xml, sustituyendo NoTitleBar por Dialog, de la siguiente

forma:

android:theme="@android:style/Theme.Dialog" y modificamos la

última línea del fichero Tema. j ava por

texto.setText("Aplicando el Tema NoTitleBar");

El resultado se ve en la figura 12.3. La actividad aparece en una ventana flotante sin ocupar

toda la pantalla, como un cuadro de diálogo o de notificaciones.

USUO 2:20 PM

Figura 12.2. Tema NoTitleBar.

Page 139: Android

126 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

I2.4. Tema Light

I'iira aplicar el tema Light hacemos lo mismo que antes, modificando el fichero AndroidManifest.xml.

android:theme="@android:style/Theme.Light"

y la última línea de Tema. j ava por:

texto.setText("Aplicando el Tema Light");

El resultado se ve en la figura 12.4 (izquierda). El fondo aparece blanco y el Inxto negro,

lo que hasta ahora hemos hecho siempre cambiando a mano el color ile fondo y el color del

texto.

Otra variante sería la siguiente:

android:theme="@android:style/

Theme.Light.NoTitleBar.Fullscreen"

Y:

texto.setText("Aplicando el Tema");

Figura 12.3. Tema Dialog.

Page 140: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A IUAVÉS DF FJEMPLOS 127

texto.append("\nTheme.Light.NoTitleBar,FuLlscreen");

que muestra la actividad a pantalla completa, sin que aparezca la barra de estado del

teléfono como se ve en le figura 12.4 (derecha).

Albert Einstein

Albert Einstein (1879-1955)

Aplicando el Tema Light

Aplicando el Tema

Theme.Light.NoTitleBar.Fullscreen

Figura 12.4. Dos variantes del tema Light.

Page 141: Android
Page 142: Android

ANIIIMI): F’ROGRAMACIÓN DE DISPOSITIVOS MÓVII í S A IRAVÍS DI I .II MPLOS I27

13. RECURSOS

fin llaman resources a los recursos (como las constantes String, ficheros de im.igenes o

sonido, etc.) que pueden ser especificados fuera del código Java. Los i<" ursos se almacenan

en el directorio res del proyecto. Ejemplos de recursos «oil los ficheros xml, localizados en el

directorio res/layout, usados para especificar ni luyout, y que nosotros hemos utilizado también

para introducir constantes de ii| 'i i String, nombres de ficheros de imágenes, etcétera.

El recurso string

Ilu straremos aquí el uso del recurso @string. El símbolo @ indica que el nombre <|tm le

sigue es un recurso, almacenado en un fichero. Los recursos @string se ulnincenan en el

fichero res/values/strings .xml. Nótese que el nombre del in Imro termina en “s”,

mientras que el del recurso no. Este fichero es siempre ' t < i kío por Eclipse automáticamente

al crear un nuevo proyecto, conteniendo las ■ i«'(luiciones de dos cadenas: helio (la cadena

que contiene el texto “Helio Android” y app_name (que contiene el nombre de la aplicación).

•?xml version="l.0" encoding="utf-8"?>

I ■resources?

<string name="helio">Hello Android</string>

<string name="app_name">Hello Androide/string>

•/resources>

A este fichero se le puede añadir el contenido de cualquier cadena que se i illlli o luego en

el layout o en el programa Java. Esto permite cambiar fácilmente luí. contenidos de las

cadenas de texto sin necesidad de modificar el programa ni ni luyout, por ejemplo para variar el

idioma. Además este recurso admite escribir 1 i'n|i(|0 HTML simple para modificar la apariencia

del texto.

i sto se ilustra en el siguiente ejemplo. Creamos un nuevo proyecto Android y, "ii ul fichero

strings.xml, incluimos la definición de una cadena llamada lii ni l i conteniendo algunos

comandos HTML:

•Vxml version="l.0" encoding="utf-8"?>

»i miources>

■string name="hello">Hello World, RecursoStringActivity!

Page 143: Android

128 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '• A TRAVÉS DE EJEMPLO!)

</string>

<string name="app_name">RecursoStr±ng</string>

<string name="htmll">

<font size="24">

Este contenido ha sido definido en el fichero de recursos

<i>strings.xml</i>.

Se pueden escribir <b>coraandos HTML simples para formato

del texto.</b>

</font>

<font size="18">Se permite el comando font para cambiar el

tamaño de la fuente.

Esta tiene tamaño 18.</font>

<font size="15"> Esta tiene tamaño 15.</font>

<font color="OOff00">No Se permite font para cambiar el

color.</font >

<p>Tampoco se puede iniciar un nuevo párrafo.</p>

<hl>Ni poner encabezamientos</hl>

</string>

</resources>

r- su« 5:06 PM I RecursoStrtng

Helio World, RecursoStrlngActivity!

Este contenido ha sido definido en el fichero de recursos strings.xml. Se pueden escribir comandos HTML simples para formato del texto. Se

permite el comando font para cambiar el tamaño

de la fuente. Esta tiene tamaño 18. Esta tiene tamaño 15.

No Se permite font para cambiar el color. Tampoco se puede iniciar un

nuevo párrafo Ni encabezamientos

Figura 13.1. Utilizando recursos string en un layout para escribir comandos HTML.

En el fichero main.xml añadimos un Textview con una referencia

@string/htmll a la cadena anterior.

Page 144: Android

ANDKOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILE N A IRAVÉ'í Df I .11 MPLOS 129

<?xml version^ " 1. 0 11 encoding="utf -8 " ? >

<LinearLayout

xmlns:android="http://schemas.android.com/apkJres/android"

android:orientation="vertical"

android:layout_width="fill_parent" android:layout_he

ight="f i1l_parent" android:background="#f f f f f f"

>

cTextView

android:textColor="#000000"

android:layout_width="fill parent"

android:layout_height="wrap_content"

android:text="@string/hello"

/>

cTextView

android:textColor="#0 0000 0"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/htmll"

/>

</LinearLayout>

13.2. El recurso color

Do la misma forma, se pueden definir los colores típicos de la aplicación en el lichera de

recursos res/values/colors .xml. En el siguiente ejemplo definimos un color para el

fondo y cuatro colores para el texto:

<?xml version="l.0" encoding="utf-8"?>

<resources>

•--color name= "backgroundColor">#FFFFFF</color>

<color name="textColorí">#000000</color>

•:color name="textColor2 " >#FF00 0 0</color>

• color name="textColor3">#0000FF</color>

«color name="textColor4">#EEEE00</color> c/resources>

I 'ura referenciar uno de estos recursos en el fichero main.xml usamos su nombre procedido

por @color/:

• ?xml version="l.0" encoding="utf-8"?>

■LinearLayout

xmlns:android="http: / /schemas.android.com/apk/res/android"

android:background="@color/backgroundColor"

android:orientation="vertical" android:layout_width="f

ill_parent"

android:l ay ou.t_he i ght = " f i 1 l_p a rent "

>

<TextView

Page 145: Android

130 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

android :textColor="@color/textColorl" andrò id

: 1ayout_wi dth="f i1l_pa r ent " android :

1ayout_height ="wrap_content" android

:textSize="20sp"

android:text="Uso del recurso @color en colors.xml" />

cTextView

android :textColor="@color/textColori" android

:layout_width="fill_parent" android:layou t_he

i ght = "wrap_c ontent" android:textSize="20sp"

android:text="Texto de color textColorl" />

cTextView

android :textColor="@color/textColor2" android

:layout_width="fill_parent" android

:layout_height="wrap_content" android

:textSize="2 Osp"

android :text="Texto de color textColor2" / >

<TextView

android :textColor="@color/textColor3" android

:layout_width="fill_parent" android

:layout_height="wrap_content" android

:textSize="2 Osp"

android:text="Texto de color textColor3"

/>

cTextView

android :textColor="@color/textColor4" android

:layout_width="fill_parent" android

:layout_height="wrap_content"

android:textsize="2Osp"

android:text="Texto de color textColor4" />

c/LinearLayout>

El resultado se presenta en la figura 13.2.Uso del recurso @color en colors, xml

Texto de color textColorl

Texto de color

textColor2 Texto de

color textColor3

Texto de color texfCojcrt

Page 146: Android

116 5:18 PM

itmnOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILKS A IRAVÉS DE EJEMPLOS 131

Figura 13.2. Utilizando recursos de coloren un layout.

I i 3. Usando recursos en un Layout

I ii hI siguiente ejemplo veremos cómo se usa el recurso string en un layout. En caso el

recurso nos es útil para poder escribir sub-índices y super-índices en M I MI Creamos una

nueva actividad HandroidPhysics y modificamos el fichero Mt t Ings.xml de la

siguiente forma:

*i i Ings.xml:

«Vxml version="1.0" encoding="utf-8"?>

• 1 ti(iources> •ntring name="helio">

<b>Interacción Neutrón-Protón</b>

•/string>

•ntring name="potential">

V (<b>r</b>)=\u03a3<sub>i</sub>

\u03bb<sub>i</sub>/2\u03bc \u03b4(r-R<sub>i</sub>)

(Pulse para ajustar \u03bb<sub>i</sub> y R<sub>i</sub>)

«/string>

■Btring name="botonHe"><b>C)</b> <sup>4</sup>He</string>

•Btring name="Emax">E<sub>max</sub>(MeV)</string>

-Btring name="lambdaO">

\u03bb <sub> 0 </sub> [fm)<sup>-l</sup>

</string>

<string name="RO"> R <sub> 0 </sub> (fm)</string?

<string name="lambdal">

\u03bb <sub> 1 </sub> (fm)<sup>-l</sup>

</string>

<string name="Rl"> R <sub> 1 </sub> (fm)</strings

<string name="SO"><b>A)</b><sup>l</sup>S<sub>0</sub>

</string>

<string name="SI" ><b>B) </b> <sup>3</sup>S<sub>l</sub>

</string>

<string name="app_name">HandroidPhysics</string>

<string name="tolerancia">Tolerancia</string>

<string name="resolución">Resolución</string>

</resources>

Los colores están definidos en el fichero res/values/colors. xml siguiente:

colors.xml:

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

Page 147: Android

132 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

<resources>

<color name="backgroundColor">#FFFFAA</color>

<color name="textColor">#000000</color>

<color name="lineColor">#aa00 0 0</color>

</resources>

Finalmente, el layout está definido en el siguiente fichero main.xml. Cada cadena

se referencia por su nombre, precedido por el tipo de recurso, en este caso string O

color .

main.xml:

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

<TableLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background^1 @color/backgroundColor"

android:stretchColumns="*" android:layout_width="f

i1l_parent" android:layout_height="fill_parent"

android:padding="10 sp"

>

cTextView

android:textColor="@color/textColor"

android:layout_width="fill_parent"

android: layout_height=

"wrap_content11

android:text="@string/hello" />

•TableRow>

«Button

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/SO">

</Button>

<Button

android: id= "@+id/button3 11

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/Sl">

, </Button>

<Button

android:id="@+id/buttonl"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/botonHe">

</Button>

T. ibleRow>

Twxt-View></TextView>

Text View

.indroid:textColor="@color/textColor"

Page 148: Android

HIM >«Hl)QRAMACl6N DE DISPOSITIVOS M6VILI SA IKAVI'MII l:JEMPLOS

. indroid:layout_width="fill_parent"

. i ndro i d:1ayout_he ight ="wrap_cont

ent"

. i ndroid:text="@string/potential"

/ >

V I r’w .mdroid: background=

"@color/lineColor" .»ndroid:

layout_height=" lsp" >

/V Iow*

I'« » 1 v 1 nwx/TextView>

Ml 11nRow android:padding="3sp"> I I i i r.ixt

«in Iroid: id="@+id/R0 0 " nm I

roid:layout_width="f ill_parent"

•lidt'oid: layout_height=

"wrap_content"

.mi Iroid:text="1"

Hi l‘>IXt

UP I roid:id="@+id/R10" MIIII i'oid:

layout_width= "f ill_parent"

1 1 1' I t'oid: 1 ayout_he ight =" wrap_cont ent"

Hu Iroid:text="l"

Page 149: Android

134 ANDROID: PROGRAMACI0N DE DISPOSITIVOS MOVtLES A IIMVfeS DE F. JEMPLOS

<TextView

android:textColor="@color/textColorn

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:text="@string/RO"

/>

</TableRow>

<TableRow >

<EditText

android:id="@+id/larabdaOO"

android:layout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="0.0"

/ >

<EditText

android:id="@+id/lambdalO"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="0.0"

/>

<TextView

android:textColor="@color/textColor"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:text="@string/lambda0"

/ >

</TableRow>

<TableRow android:padding="3 sp">

<EditText

android:id="@+id/R01"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="l.99"

/ >

<EditText

android:id="@+id/Rll"

android:1ayout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="1.53"

/>

<TextView

android:textColor="@color/textColor"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:text="@string/Rl"

/>

Page 150: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPI <)B

</TableRow>

■TableRow >

<EditText

android:id="@+id/lambda01"

android:layout_width="f ill_parent"

android:layout_height="wrap_content"

android:text="-0.46"

/>

■ EditText

android:id="@+id/lambdall"

android:layout_width="f ill_parent"

android:layout_height="wrap_content"

android:text="-0.91" / >

* TextView

android:textColor="@color/textColor"

android:layout_width="f ill_parent"

android:layout_height="fill_parent"

android: text = "@string/lambdal11 / >

■/TableRow>

■TableRow android:padding=" 3 sp" >

•TextView

android:textColor="@color/textColor"

android:layout_width="f i1l_parent"

android:layout_height="fill_parent"

android:text="@string/Emax" />

•TextView

android:textColor="@color/textColor"

android:1ayout_width="f i1l_parent"

android:layout_height="wrap_content"

android:text="@string/tolerancia" />

tTextView

android:textColor="@color/textColor"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/resolucion" / >

</TableRow>

<TableRow>

<EditText

android:id="@+id/Emax"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="100" />

Page 151: Android

I36 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVI'!: III EJEMPLOS

<EditText

android:id="@+id/tolerancia"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="0.5" />

<EditText

android:id="@+id/resolucion"

android:layout_width="fill_parent"

android: layout_height="

wrap_content11 android:text="1.e-5 " / >

</TableRow>

<TextView

android:textColor="@color/textColor"

android:layout_width="f ill_parent"

android:layout_height="wrap_content"

android:text="J.E. Amaro, 2 011" / >

</TableLayout>

El ejemplo se puede examinar en la figura 13.3. También vemos aquí cómo añadir

ciertos efectos de formato en un layout. Insertando un Textview vacío se produce un

espacio vertical. Insertando un view de un color y anchura se dibuja una línea horizontal.

Este layout será el punto de partida de la aplicación HandroidPhysics que se presenta

en el apéndice C.

Figura 13.3. Utilizando recursos en un layout incluyendo sub-índices

y super-índices.

Page 152: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII ISA IHAVÉNDf I II Mil .OS 137

14. HILOS Y CONTROLADORES

14.1. Ejecuciones en background con Thread

En Java, y también en Android, podemos ejecutar varias secciones de un programa en

paralelo. Cada uno de estos procesos se denomina thread o hilo, y se ejecuta en

background con una prioridad determinada bajo el control de un objeto de la clase Thread

de Java. Generalmente sólo hay un hilo asociado a una actividad, el hilo principal,

consistente en una serie de instrucciones o sentencias que se ejecutan secuencialmente.

Una forma de crear un hilo es definir una clase que extiende a la clase Thread. La

nueva clase debe sobrescribir el método run() , que se ejecutará cuando se inicie el hilo:

class Hilo extends Thread{

II . . .

@Override

public void run(){

// instrucciones a ejecutar

}

II ...

}

Para comenzar la ejecución del hilo se instancia un objeto de la clase Hilo y se

ejecuta el método start () :

Hilo hilol = new Hilo();

hilol.start()

Podemos definir varios hilos y ejecutarlos todos al mismo tiempo con distintas

prioridades.

La vista de la pantalla sólo se puede modificar desde el hilo principal. Los procesos que

se ejecutan en un hilo no tienen permitido modificar los objetos de

Page 153: Android

138 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

tipo view, por ejemplo un Textview. Si lo intentamos, el programa se compilará,

pero dará un error durante la ejecución. Si queremos mostrar en pantalla los datos o

gráficos generados en un hilo podemos utilizar un controlador (handler), que es un objeto de

la clase Handler. Un controlador residente en el hilo principal puede recibir mensajes de

otro hilo y ejecutar instrucciones en consecuencia, por ejemplo, escribir en pantalla.

Para enviar un mensaje a un controlador handler desde un hilo:

- Se obtiene el mensaje asociado al controlador

Message msg=handler.obtainMessage();

■ Se construye un objeto de tipo Bundle para empaquetar los datos

Bundle b =new Bundle();

■ Insertamos los datos en el bundle mediante parejas ("etiqueta", dato) ,

por ejemplo para insertar un entero y una cadena en el bundle

b.putlnt("etiquetal",entero);

b.putString(''etiqueta2", cadena);

■ Finalmente se inserta el bundle en el mensaje y se envia al controlador

msg.setData(b);

handler.sendMessage (msg) ;

En cuanto se envia un mensaje al controlador, el sistema ejecuta el método

handler.handleMessage () de la clase Handler, que se habrá reescrito para

aceptar el mensaje enviado y ejecutar otras instrucciones. Hay que definir el controlador

handler en el hilo principal:

Handler handler= new Controlador();

donde la clase Controlador extiende la clase Handler y sobreescribe (Override) el método handleMessage () :

class Controlador extends Handler{

@Override

public void handleMessage(Message msg){

int entero=msg.getData().getlnt("etiquetal");

String cadena=msg.getData().getString("etiqueta2");

// otras instrucciones.... }

}

Para leer el contenido del mensaje se usa el método msg-getData<) , que »'xtrae el

objeto bundle, de donde podemos leer los datos usando i' t: Int ( "etiquetal" ) y

getString("etiqueta2") - A continuación, podemos ejecutar otras instrucciones que se

realizarán en ei hilo principal.

Todo esto se pone en claro en el siguiente ejemplo. Ejecutamos dos hilos simultáneos,

que envían mensajes a un controlador, que los muestra en pantalla. ( .ida hilo cuenta del 1

Page 154: Android

ANDROID: PROGRAMACIÓN DE DISP08ITIV0H MÓVIl I !¡ A IN AVI Mil I II MPLOS 139

aMO con un retraso temporal expresado en millsegundos. I'.ira este ejemplo utilizamos la

siguiente interfaz de usuario definida en el fichero m.iin.xml.

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

<LinearLayout

Kinlns:android="http://schemas.android.com/apk/res/android"

android:background="#ff f fbb"

android:orientation="vertical" android: layout_width="

f ill_parent11 android:layout_height="fill_parent"

>

<TextView

android:textColor="#550000"

android:textSize="25sp"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"

android:id="@+id/textol" />

</LinearLayout

La actividad Hilos .java es la siguiente:

package es.ugr.amaro;

import android.app.Activity; import android.os.Bundle; import

android.os.Handler; import android.os.Message; import

android.widget.TextView;

public class Hilos extends Activity {

Handler handler=new Controlador();

I TextView textol,texto2;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

textol=(TextView) findViewByld( R .id.textol);

Hilo hilol=new Hilo(10,100)

Hilo hilo2=new Hilo(5,200); hilo2.setPriority(7);

hilol.start(); hilo2.start();

class Hilo extends Thread{

int máximo, tiempo,-

Hilo(int n,int t){

maximo=n;

tiempo=t;

Page 155: Android

140 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES /V IH/WI':. 1)1 liJEMPLOS

}

@Override public

void run(){

for (int i=0;i<=maximo;i++){ try{

Thread.sleep(tiempo); }

catch (InterruptedException e){ ; }

// Construye el mensaje

// para enviar al controlador handler

Message msg=handler.obtainMessage();

// inserta datos en el mensaje //enpaquetandolos

en un bundle Bundle b =new Bundle();

b.putInt("total",i);

b.putString ( "thread" , currentThread ()

.toStringO) ; msg.setData(b);

// envia el mensaje handler.sendMessage(msg);

}

}

}

// Controlador para recibir mensajes del hilo

class Controlador extends Handler{

@Override

public void handleMessage(Message msg){

int total;

// recibe los datos enviados en el mensaje msg

Page 156: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS Móvil I '.A IKAVI'MH I .II MPLQ8 I 4 I

total=msg.getData().getlxit<"total");

String th.read=msg. getData ()

.getStriixgC'thread") ; textol.append<"\n"+total+"

"+-threa.d) ;

} }

} _____________________________________________

Figura 14.1. Dos hilos cuenian del 1 al 10 y un controlador va mostrando el resultado en la

pantalla.

El resultado se ve en la figura 14.1. En la primera columna escribimos el nntero i, a

medida que el controlador lo va recibiendo y, en la segunda, el hilo del (|ue proviene. Hemos

usado el método currentThread () , toStringO que ilovuelve información sobre el

hilo actual y lo almacena en una cadena. La prioridad del segundo hilo la hemos modificado

con hilo2 . set Prior ity (7). I .i prioridad por defecto de un hilo es 5. El valor

de i se va incrementando en i .ida hilo lentamente debido al retraso, expresado en

microsegundos mediante la Instrucción Thread. sleep (tiempo).

14.2. Diálogos de progreso

I a técnica anterior se puede aplicar para mostrar una barra o diálogo de progreso,

Indicando que se está ejecutando un proceso en backgroiind. La barra de progreso es un

tipo de diálogo: un objeto de la clase ProgressDialog, que «ixtiende a Dialog, y es

una actividad flotante. Se inicia mediante nhowDialog(int estilo), donde estilo

puede ser 0 (spinner) ó 1

BBsfflp»

Helio World, Hilos!

0 Thread[Thread-8,5,main]

1 Thread[Thread-8,5,main]

0 Thread[Thread-9,7,main]

2 Thread[Thread-8,5,main]

3 Thread[Thread-8,5,mainj

1 Thread[Thread-9,7,mainj

4 Thread[Thread-8,5,imainj

5 Thread[Thread-8,5,ma¡nj

2 Thread[Thread-9,7,main]

6 Thread[Thread-8,5,ma¡n]

7 Thread[Thread-8,5,mainj

3 Thread[Thread-9,7,main]

8 Thread[Thread-8,5,main]

9 Thread[Thread-8,5,main]

4 Thread(Thread-9,7,main]

10 Thread[Thread-8,5,main]

5 Thread[Ttiread-9,7,main]

Page 157: Android

142 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

(horizontal). Esto hace que se ejecuten los métodos one reaten ial og () y

onPrepareDialog () de la clase Activity, que deben ser redefinidos

(@Override) en nuestra actividad para que la barra de progreso se muestre de acuerdo

con nuestras necesidades. El método onCreateDialog () sólo se ejecuta la primera

vez que mostramos el diálogo. Si lo mostramos sucesivas veces, sólo se ejecutará el

método onPrepareDialog ().

En el ejemplo que viene a continuación se abre una barra de progreso de tipo horizontal.

Utilizaremos la interfaz de usuario definida en el siguiente fichero main.xml:

<?xml version="1.0" encoding="utf-B"?> cLinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#ffffff"

android:orientation="vertical" android:layout_width="f

i1l_parent" android:layout_height="fill_parent"

>

<TextView

android:textColor="#000000"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"

android:id="@+id/texto"

/ >

<Button android:text="Empezar" android:id="@+id/buttonl"

android:1ayout_width="f i1l_parent"

android:layout_height="wrap_content">

</Button>

</LinearLayout>

Nuestra actividad viene en el siguiente programa BarraDeProgreso. j ava:

package es.ugr.amaro;

import android.app.Activity;

import android.app.Dialog;

import android.app.ProgressDialog;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.TextView;

public class BarraDeProgreso extends Activity implements

OnClickListener{

ProgressDialog progreso;

Controlador handler=new Controlador(); int maximo=100; int

Page 158: Android

» I I I un i l l ) PROGRAMACIÓN DE DISPOSITIVOS MÓVII ESA lUAUI'V. Ill I II Mfl OS 143

delay=100; int estilo=0;

TextView texto;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Button boton= (Button) findViewByld(R.id.buttonl);

boton.setOnClickListener(this);

texto=(TextView) findViewByld(R.id.texto);

}

©Override

public void onClick(View v) { showDialog(estilo);

}

// Crea una barra de progeso

©Override

public Dialog onCreateDialog(int id) {

progreso = new ProgressDialog(this);

progreso.setProgressStyle(estilo);

progreso.setMessage(""); return progreso;

}

// Prepara la barra de progeso

©Override

public void onPrepareDialog(int id,Dialog dialog) {

progreso=(ProgressDialog)dialog;

progreso.setProgressStyle(estilo);

progreso.setMax(máximo); progreso.setProgress(0) ;

progreso.setMessage(

"Ejecutando hilo en background..."); Hilo

thread=new HiloO; thread.start() ;

)

class Controlador extends Handlerj

@Override

public void handleMessage (Message msg) {

int total=msg.getData().getlnt("total");

progreso.setProgress(total);

texto . setText ("Total "+total+" Máximo: "-t-maximo) ;

if(total==maximo){

dismissDialog(estilo) ;

}

}

}

class Hilo extends Thread{

@Override

public void run(){

Page 159: Android

144 ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVIL.! S A> 1RAVÉ ü DE EJEMPLOS

for (int i=0;i<=maximo;i++){

try {

Thread.sleep(delay);

} catch (InterruptedException e){;}

Message msg=handler.obtainMessage();

Bundle b =new BundleO;

b.putInt("total" , i) ;

msg.setData(b);

handler.sendMessage(msg);

}

}

}

}

Vemos el resultado en la figura 14.2 (izquierda). Pulsando el botón se inicia el diálogo,

ejecutándose los métodos onCreateDialog () y onPrepareDialog (). En éste se

inicia el proceso thread de la clase Hilo, que consiste en un ciclo que cuenta del uno al

cien con un retraso de 100 milisegundos. Se envía un mensaje al controlador con la variable

incremental del ciclo. En cada paso del ciclo el controlador actualiza el valor mostrado en la

barra de progreso mediante progreso. setProgress (total) . Cuando termina el

ciclo (total=maximo), el controlador finaliza el diálogo con dismissDialog (l).

Entonces se devuelve el control al hilo principal y se puede repetir el proceso pulsando de

nuevo el botón, en cuyo caso se ejecuta solamente onPrepareDialog () .

Si cambiamos en este programa la variable estilo=0, y comentamos la instrucción

progreso. setMax (máximo) tendremos un diálogo de progreso circular adecuado al

caso en que no podamos predecir cuándo finalizará el hilo secundario. El resultado se ve en

la figura 14.2 (derecha).

Page 160: Android

Menili l'Ut )( iKAMACIÓN DE DISPOSITIVOS MÓVIl I S A TRAVI'S Di I .11 MPLOS 145

M.3. Interfaz Runnable

I ululo otro procedimiento alternativo para crear un hilo. Consiste en definir una i i .m que

implemente la interfaz Runnable. Esto requiere definir el método i mi () , que se ejecutará

al iniciarse el hilo mediante:

Tliread hilo= new Thread (runnable} ;

h I l.o. start () ;

donde runnable es un objeto de la clase que implementa la interfaz ■Ufumble. La

ventaja de este procedimiento en lugar de extender la clase f in . ,< i , como hemos hecho en

este capítulo, es que cualquier clase puede imiilnmontar un interfaz. En particular puede ser

una clase que a la vez extienda a ln i l.i’.ti view y que podemos insertar en un layout. Así

podemos tener varios • i| 1111■ i de tipo view en la pantalla, cada uno asociado a

instrucciones que se i in n|()cutando en su propio hilo. Otra ventaja es que no es necesario

utilizar un itoiiliolndor, pues el contenido de estos objetos view puede ser actualizada

MHiiiniumente usando el método postlnvalidate () de la clase view. Este MAtorio

hace que se vuelva a dibujar el contenido de un objeto view, ♦•I“1 litándose el método

onDraw()(en este caso no se puede usar Wivn i I • i.11 e() para dibujar de nuevo, porque

este método sólo se puede utilizar •ii ni lillo principal y no en hilos secundarios.)

En el siguiente ejemplo usamos esta técnica para actualizar dos contadores en dos hilos

independientes. Cada hilo consiste en un objeto de la clase TextoAnimado que extiende

a view y que hemos definido como clase interna. Cada hilo tiene un contador cuyo valor se

incrementa con un retraso y se muestra en pantalla. Estos objetos view se añadirán al

layout definido en el siguiente fichero main.xml:

Figura 14.2. Diálogos de Progreso Horizontal y Giratorio.

Page 161: Android

146 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

<?xml version="l.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#ffffff"

android:orientation="vertical" android:layout_width="f

i1l_parent" andr o i d: 1 ayou t_he ight=" fill _par en

t" android:id="@+id/layout"

>

<TextView

android:id="@+id/texto"

android:textColor="#00 0000"

android:textSize="3 5sp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Interfaz Runnable" />

</LinearLayout>

El programa Java, donde definimos la actividad RunnableEjemplo, es el siguiente.

Los dos contadores son los elementos de un array. Los parámetros de los objetos

TextoAnimado son, además de la clase actual this, el retraso temporal y el índice del

contador (0,1).

package es.ugr.amaro.runnableej emplo;

import android.app.Activity;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.os.Bundle; import

android.view.View;

import android.view.ViewGroup.LayoutParams;

import android.widget.LinearLayout;

public class RunnableEjemplo extends Activity {

boolean continuar=true;

String mensaje="";

Page 162: Android

' V I II1ROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I ' ■ A rRAVf.H 1 ) 1 I Jl M P I 09

int[] contador={O , O} ;

TextoAnimado texto,texto2;

««Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

LinearLayout 11=(LinearLayout) findViewByld(R.id.layout);

LayoutParams params=new LayoutParams(600,100);

texto= new TextoAnimado(this,40,0);

texto.setLayoutParams(params);

11.addView(texto);

texto2= new TextoAnimado(this,200,1);

texto2.setLayoutParams(params);

texto2.setBackgroundColor(Color.YELLOW);

11.addView(texto2);

Thread hilo= new Thread(texto); hilo.start();

Thread hilo2= new Thread(texto2); hilo2.start();

class TextoAnimado extends View implements Runnable{

int retraso; int i ;

Paint paint=new Paint();

public TextoAnimado(Context context,int retraso,int

super(context); this.retraso=retraso; this.i=i;

paint.setColor(Color.BLACK); paint. setTextSize (30) ,-

paint.setAntiAlias(true); }

@0verride

protected void onDraw(Canvas canvas){ super.onDraw(canvas);

canvas.drawText(mensaje,50,50,paint); }

public void run() {

while(continuar){

try{Thread.sleep(retraso);} catch

(InterruptedException e) •{ ,- }

contador[i]++;

mensaje="Contador: "+contador[i];

postlnvalidate(); }

}

} }

I SI!«5:56.PM I RunnableEjempIo

Page 163: Android

149 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOti

Interfaz Runnable

Contador: 18026

Contador: 3691

Figura 14.3. Dos hilos en dos objetos View implementando la inerfaz Runnable.

El resultado se ve en la figura 14.3. Los dos contadores correspondientes a los índices

i=o, l del array contador [], avanzan de uno en uno con un retardo de 40 y 200

milisegundos, respectivamente.

Si se ejecuta esta aplicación y se observa detenidamente, se verá que ocasionalmente

alguno de los contadores (con más frecuencia el segundo) muestra el resultado

correspondiente al otro contador, pero inmediatamente después continúa con su propio

contaje. Esto se debe a que el texto a escribir, almacenado en la variable de la clase

principal mensaje está siendo compartido por los dos hilos, que están ejecutándose

simultáneamente. Entonces puede ocurrir que inmediatamente antes de que en un hilo se

escriba la variable mensaje, el otro hilo modifique súbitamente su contenido. Este

ejemplo ilustra el

Page 164: Android

ANDHOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII E S A I HAVf ’• DI I II MI M Oí , 49

ii|MI de interacciones que pueden producirse al trabajar con varios hilos

ulniultáneamente. La solución en este caso es trasladar la declaración de la vmlable:

| String mensaje="";

a la clase TextoAnimado, en cuyo caso cada hilo modificaría su propia copia de li<

variable mensaje.

14 4. Notificaciones

l i barra de estado, que aparece en la parte superior de la pantalla, puede mostrar l i f .

notificaciones que envían las aplicaciones que se ejecutan en background.

I '.lo permite lanzar a ejecutar un hilo desde una actividad, pasar a otra actividad y

I I improbar si sigue ejecutándose. La notificación que envía el hilo consiste en un

iimnsaje de texto que se puede examinar en la vista expandida de notificaciones,

i |i ii» se despliega tirando hacia abajo de la barra de estado.

Ilustraremos el uso de notificaciones creando una actividad que usa la siguiente

ii ili irfaz de usuario en main. xml:

■?xml version="l.0" encoding="utf-8"?>

•LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="f i1l_parent"

android:background="#ffffff"

>

•:TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Ejemplo de notificaciones desde un hilo"

android:textSize="2 0sp" android:textColor="#000000" / >

<ImageView android:layout_width="wrap_content"

android:src="@drawable/icon" android:id="@+id/imageViewl"

android:layout_height="wrap_content">

■'/ImageView>

<TextView

android:layout_width="fill_parent"

android:layout_height="wrapcontent"

android:text="Obsérvese este icono a la derecha de la

barra de estado"

Page 165: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 150

android:textSize="20sp"

android:textColor="#00 0

000'

/ > </LinearLayout>

a Obsérvese este icono a la derecha de la barra de estado

_ ____

Figura 14.4. Notificaciones desde un hilo ejecutándose en background. Izquierda: Obsérvese

el icono de notificación en la barra de estado. Derecha: Notificación detallada mostrando el

mensaje enviado por el hilo.

El fichero Java de la actividad es el siguiente. El proceso de creación de la notificación

requiere seguir varios pasos que están indicados con comentarios en el listado. En concreto:

■ Instanciar una referencia al manager de notificaciones, que es un objeto de la clase

NotificationManager.

* Crear la notificación, un objeto de la clase Notification, que incluye un icono, un

texto a mostrar al inicio y una fecha que no tiene otra utilidad que para ordenar las

distintas notificaciones del sistema cronológicamente.

■ Definir un intent, para acceder a nuestra aplicación desde la vista extendida de

notificaciones y un Pendinglntent. El Pendinglntent contiene la información del

intent y concede permisos para ser utilizado desde otra actividad externa.

June 25,2011

Android

8:31 AM

Notifications

Ejemplo de notificaciones desde

un hilo

Notificaciones

AM !

Hilo funcionando

comador=916 8:29 AM

Page 166: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I «A IKAVI'NOI I II MCI 03 I5l

Actualiza el texto de la notificación expandida, actualiza la notificación con

setLatestEventlnf o (> y la notifica al manager con uotif y () .

En este ejemplo, la actualización y notificación se ha incluido en un hilo que incrementa

un contador con un retraso. El texto de la notificación incluye el valor ilol contador.

Figura 14.5. La notificación persiste en la barra de estado cuando cerramos la actividad

pulsando la tecla back y volviendo a la pantalla home, ya que el hilo sigue ejecutándose en

background.

I ackage es.ugr.amaro.notificaciones;

Import android.app.Activity;

Import android.app.Notification;

Import android.app.NotificationManager;

I niport android. app . Pendinglntent ;

Import android.content.Context;

Import android.content.Intent;

Import android.os.Bundle;

public class Notificaciones extends Activity {

boolean continuar=true;

int retraso=100;

Page 167: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 152

int contador=0;

// variables para la notificación.

NotificationManager manager;

Notification notificación;

CharSequence notificacionTitle = "Hilo funcionando";

CharSequence notificacionText =

Context context;

Intent notificacionlntent;

Pendinglntent pendinglntent;

/** Called when the activity is first created. */ @Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

// referencia al manager de notificaciones

String servicio=Context.NOTIFICATION_SERVICE;

manager=(NotificationManager)getSystemService(

servicio);

// crea la notificación int icon=R.drawable.icon;

String texto="ej ecutando";

long cuando=System.currentTimeMillis();

notificacion=new Notification(icon,texto,cuando);

// define el intent de la notificación expandida context

= getApplicationContext(); notificacionlntent = new

Intent(this,

Notificaciones.class);

pendinglntent = Pendinglntent.getActivity(this,

0, notificacionlntent, 0);

// inicia un nuevo hilo

Contar contar=new Contar();

Thread hilo = new Thread(contar);

hilo.start(); }

// clase para ejecutar un hilo que manda una notificación class

Contar implements Runnable{

public void run() {

while(continuar){ try { Thread.sleep( retraso ); }

contador++ ;

//texto de la notificación expandida not

i f i cac ionText ="contador="+ cont

ador; //actualiza la notificación

notificación.setLatestEventlnfo(context,

notificacionTitle,

notificacionText, pendingEntent) //

Page 168: Android

catch ( InterruptedException e ) -{ ; }

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I S A IRAVÉHDE I II Ml'l OS 153

comunica la notificación al manager int

ref=l;

manager.notify(ref,notificación);

El resultado se ve en la figura 14.4. Al ejecutar nuestra aplicación aparece en la barra

de estado el icono de Android ¡con.png, indicando que la notificación está activa. Si

desplegamos la barra de estado, tirando de ella hacia abajo, veremos que se muestra el

mensaje de la notificación. Si pulsamos la tecla back o Home y salimos de nuestra

aplicación, figura 14.5. vemos que la barra de estado continúa mostrando el ¡cono de la

notificación. Esto nos confirma que el hilo sigue ejecutándose en background. Si abrimos la

vista detallada de notificaciones y pulsamos en la notificación, se abre de nuevo nuestra

actividad (es aquí donde el pendinglntent está siendo utilizado).

Puede haber más de una notificación proveniente de distintos hilos o del mismo. El

número de referencia ref=l en la notificación al manager permite controlar qué

notificación se está actualizando. Por ejemplo, si al final del método run() añadimos la

línea:

manager.notify(2,notificación);

estamos notificando al manager una segunda notificación. Al ejecutar nuestra

aplicación ahora se verán dos iconos en la barra de estado y dos notificaciones en la vista

detallada, figura 14.6.

Page 169: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILI S A lHAVfü DE EJEMPLOS

Figura 14.6. Dos notificaciones en la barra de estado y en la vista

detallada de notificaciones.

15. ANIMACIONES

En el capítulo anterior hemos introducido los conceptos necesarios para realizar

SH© 9:44 AM june 25, 2011 ^ÜfllfS 9:4-4 AM Notificaciones I

Android Clear | Ejemplo de notificaciones desde un hilo Notificatons

IsdSlll Obsérvese este icono a la derecha de la barra de estado

Hilo funcionando contador=462 9:43 A M

jg Hilo funcionando contador=462 9:43 AM

Page 170: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIt I S A IR AVI' ü 111 I II Ml ’I OK I 55

animaciones, es decir, introducir sensación de movimiento en un texto o en general un

gráfico, modificando rápidamente el dibujo de la pantalla. Es como ver una película, que

consiste en una sucesión de imágenes o fotogramas.

Hasta ahora hemos mostrado contadores dinámicos que cambian con el tiempo. A

continuación, animaremos otros objetos gráficos imprimiéndoles distintos tipos de

movimiento.

15.1. Movimiento uniforme. La bola botadora

Comenzaremos con el movimiento más simple: una bola, representada por un círculo rojo,

que inicialmente está en la parte superior de la pantalla y se mueve hacia abajo con

velocidad constante. Cuando llegue al borde inferior invertiremos su velocidad, moviéndose

hacia arriba. Al llegar arriba, volvemos a invertir su velocidad y el movimiento se repite. Para

este programa no utilizaremos la interfaz de usuario de main.xml, sino que dibujaremos

directamente sobre un canvas. El grueso del programa es la clase Dinamicaview, que

extiende a view e implementa la interfaz Runnable. El programa es el siguiente:

package es.ugr.amaro.movimientorectilineo;

import android.app.Activity;

public class MovimientoRectilineo extends Activity {

boolean continuar=true;

float velocidad=0.5f;

int dt=10; int

tiempo=0;

Thread hilo=null;

DinamicaView dinamica;

/** Called when the activity is first created. *■/

©Override

public void onCreate(Bundle savedlnstanceState) {

dinamica=new DinamicaView[this);

setContentView(dinamica); hilo = new

Thread(dinamica); hilo.start(); }

// detenemos el hilo si pausa @Override

public void onPause(){ super.onPause() ; continuar=false ; }

// reiniciamos el hilo si resume @Override

public void onResume(){ super.onResume(); continuar=true;

if(hilo==null){

hilo=new Thread(dinamica); hilo.start();

Page 171: Android

super.onCreate(savedlnstancestate);

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I S A 11 (AVf' ¿ I) I EJEMPLOS

} }

class DinamicaView extends View implements Runnable{

int x,y,ymax; // coordenadas Paint

paintFondo,paintParticula,paint; public

DinamicaView(Context context) { super(context);

// Colores para el dibujo y tmaño del texto

paintFondo=new Paint();

paintParticula=new Paint();

paint=new Paint{);

paintFondo.setColor(Color.WHITE);

paintParticula.setColor(Color.RED);

paint.setColor(Color.BLACK);

paint.setTextSize(3 0); }

@0verride public void run() {

while(continuar){ tiempo=tiempo+dt;

// movimiento uniforme y=y+v*t

y=y+(int)(velocidad*dt);

/ / s i llega abajo invertimos velocidad

if(y>ymax) velocidad=-velocidad;

// si llega arriba invertimos velocidad

if(y<0) velocidad=-velocidad;

postlnvalidate(); try { Thread.sleep( dt

) ; }

catch ( InterruptedException e ){ ; } } }

// obtiene geometria del canvas

@Override

protected void onSizeChanged(

int w, int h; int oldw,int oldh){

x=w/2; Y=0; ymax=h;

}

@Override

public void onDraw(Canvas canvas ){

canvas.drawPaint(paintFondo);

canvas.drawCircle(x, y, 30, paintParticula);

canvas.drawText("y="+y, 50, 50, paint);

canvas.drawText("t="+tiempo, 50, 90, paint); }

} // fin dinamica

Page 172: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 158

}

Podemos ver dos capturas de pantalla en la figura 15.1. En el método onstart ()

instanciamos nuestro objeto view e iniciamos el hilo para la animación. En esta actividad

implementamos también los métodos onPauseO para detener el hilo en caso de

abandonar la actividad y onResumeO para reiniciar la actividad si volvemos a ella. Estos

métodos deberían incluirse siempre, aunque por brevedad no los mostramos explícitamente

en todos nuestros ejemplos.

Los parámetros que requiere el programa son la velocidad de la bola y el Incremento de

tiempo o retraso con el que redibujamos la pantalla:

float velocidad=0.5f;

int dt=10;

Page 173: Android

I58 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I '.A TRAVÉS DE IJEMPLOS

Animamos al lector a modificar estos valores y ver lo que ocurre, teniendo en cuenta que

el tiempo está expresado en unidades de milisegundos (ms) y la velocidad en

pixeles/milisegundo (p/ms). Si la velocidad es demasiado grande, pongamos mayor de 10

p/ms, la bola recorrerá 10 pixeles en un milisegundo, una distancia demasiado grande para

apreciar un cambio brusco de posición entre una pantalla y la siguiente. Si el tiempo dt es

demasiado grande, pongamos mayor que 50ms (equivalente a 20 fotogramas por segundo),

apreciaremos el tiempo que la pantalla está parada y el movimiento nos parecerá

parpadeante. Los valores más adecuados para que el movimiento nos parezca suave y

fluido son velocidad < 1 y dt < 10.

En esta aplicación hemos definido el método onSizeChanged para extraer los

nuevos valores de anchura y altura del canvas en el caso de que la geometría de éste se

modifique, principalmente al girar el teléfono (giro que en el emulador realizamos pulsando

Ctrl-F 11).

La posición de la bola se calcula en el método run () , donde su coordenada y se

incrementa según la ecuación del movimiento:

y = y0 + vdt.

Teniendo en cuenta que la velocidad es de tipo f loat y las coordenadas y tiempo son

enteros, esta ecuación se implementa en nuestro programa como:

®®®7:53AM

MovImientoRectHineo I MovimientoRectilinec

y=250 y=539 t=35700

t=1151250

9

Figura 15.1. La pelota botadora.

Page 174: Android

y = y + (int)(velocidad*dt) ¡

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII 1 A IHAVI'M)! I II MPI OS 159

Inicialmente la velocidad es positiva y la pelota cae hacia abajo. Cuando la pelota llega

a la base de la pantalla invertimos su velocidad (la hacemos negativa):

if(y > ymax) velocidad=-velocidad;

y el sentido de su movimiento se invierte, dirigiéndose hada arriba. Al llegar arriba

invertimos de nuevo su velocidad:

if(y <0 ) velocidad= -velocidad;

y el movimiento se repite estacionariamente.

15.2. Movimiento acelerado. La bola botadora II

Para simular otros elementos de la dinámica introduzcamos una aceleración, que

represente la fuerza de la gravedad:

float velocidad=0.05f;

float aceleracion=0.Olf;

int dt=l;

Modifiquemos el método run () trasladando todo el cálculo de la posición a un nuevo

método cambiaPosición () . Esto nos permitirá modificar fácilmente el programa si

queremos añadir otro tipo de trayectorias más adelante. Bastará con modificar este último

método.

@Override public void run() {

while(continuar){ cambiaPosicion();

postInvalidate(); try { Thread.sleep(

dt ); } catch ( InterruptedException e

){ ; } }

}

public void cambiaPosicion() {

tiempo=tiempo+dt;

// movimiento y=y+v*dt

y=y+(int)(velocidad*dt);

// fuerza v=v+a*dt

velocidad=velocidad+aceleracion*dt;

// si llega abajo invertimos velocidad

if(y>ymax) velocidad=-Math.abs(velocidad);

/ / s i llega arriba invertimos velocidad

if(y<0) velocidad=Math.abs(velocidad); }

La única modificación que hemos hecho es introducir el cambio de velocidad en cada

intervalo de tiempo según la ecuación:

Page 175: Android

160 ANDROID PROGRAMACIÓN OE DISPOSITIVOS MÓVIII H A IK/WÉ8DE EJEMPLOS

v = v0 + adl

ya que la aceleración representa precisamente el cambio infinitesimal de la velocidad:

velocidad = velocidad + aceleración * dt;

Esta aceleración puede también interpretarse aquí como producida por una fuerza

sobre una partícula de masa igual a uno m=1, ya que, según la ecuación de Newton, F=ma.

Nótese que en CambiaPosicion () hemos cambiado las líneas para invertir la velocidad

en los extremos, introduciendo explícitamente su signo (es decir, más o menos su valor

absoluto). Esto es debido a que, por problemas de redondeo, podría darse el caso de que la

partícula sobrepase el borde y la inversión de velocidad no sea suficiente para sacarla, en

cuyo caso quedará indefinidamente fuera de la pantalla y su velocidad continuará

invirtiéndose en cada iteración.

En la figura 15.2 vemos dos capturas de pantalla. Aunque en estas imágenes estáticas

no es posible apreciar el movimiento de la simulación, hemos escrito en la pantalla también

el valor de la velocidad, para demostrar cómo está cambiando continuamente. También

hemos desplazado la posición x de la bola para dejar sitio al texto. Este es el nuevo método

onDraw () :

@Override

public void onDraw(Canvas canvas ){

canvas.drawPaint(paintFondo);

canvas.drawCircle(x+100, y, 30, paintParticula);

canvas.drawText("y="+y, 50, 50, paint);

canvas.drawText("t="+tiempo, 50, 90, paint);

canvas . drawText ( "v=11+velocidad, 50, 130,

paint); }

lÉlliÉ 10:34 AM ®b®©4:ZÍPM| Movimiento Rectilíneo Mouimi eritoR« c t if in e o

y=403 y=24 A t=221921 t=14719

V=-6.0400434 V=¿.Q399983 ^

m

Page 176: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII H A IRAVf-S DI I JEMPLOS 1 6 1

Figura 15.2. La bola botadora acelerada. En la figura de la derecha la velocidad es tan

grande que la captura de la pantalla no ha captado la imagen de la bola, en el momento en

que cambiaba de posición.

15.3. Conservación de la energía

SI observamos detenidamente la simulación anterior durante unos minutos en el nmulador o

en el teléfono, veremos que la velocidad va aumentando poco a poco y puede llegar a

hacerse el doble en unos minutos. En particular, su energía no se conserva. Esto es

consecuencia de la poca precisión en la resolución de la licuación del movimiento, que

hemos implementado de forma incremental, con un paso de tiempo de 1 ms, lo que hace

que la solución sea inestable para tiempos muy largos. Aunque la ecuación puede

resolverse con más precisión usando métodos matemáticos conocidos, en este caso vamos

a aplicar el principio de conservación de la energía, que es una condición que debe verificar

nuestra Imyectoria y que mejorará su estabilidad. Como es sabido del curso de física

i’lomental, la energía asociada a una fuerza constante en el eje y es la suma de energía

cinética y energía potencial:

E = mv2 H-may

donde el signo menos en la energía potencial se debe a que en el dispositivo el fije y

apunta hacia abajo. De esta fórmula podemos despejar el valor de y:

Page 177: Android

y = (v212-E ¡ m)fa

I62 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILFS A TRAVÉS DE EJEMPLOS

Esta es la fórmula que emplearemos para calcular y. En principio tendríamon que

conocer la masa de la partícula m, pero veamos que en este problema en irrelevante. La

energía debe mantenerse constante e igual a la energía inicial, paro y=0, que es:

E = wjvq / 2

Sustituyendo en la ecuación anterior, encontramos que la coordenada y viene dada por:

y = (v2-vl)l(2a)

que no depende de la masa. Esto quiere decir que podemos elegir cualquier valor de la

masa, por ejemplo m=1. Si calculamos la coordenada y mediante esta fórmula, la energía

de nuestra bola se conservará, lo que contribuye a la estabilidad y periodicidad de su

movimiento.

Para implementar la conservación de la energía basta modificar el método

cambiaPosición () de la siguiente forma:

public void cambiaPosicion() {

tiempo=tiempo+dt;

// fuerza v=v+a*dt

velocidad=velocidad+aceleracion*dt;

// conservación de la energia float

cinetica=velocidad*velocidad/2;

y=(int)((cinetica-energia)/aceleración);

// si llega abajo invertimos velocidad

if(y>ymax) velocidad=-Math.abs(velocidad);

// si llega arriba invertimos velocidad

if(y<0) velocidad=Math.abs(velocidad);

}

Previamente hay que declarar la variable de clase energia en la clase principal:

float energia;

y hay que definir el valor constante de ésta Igual a la energía inicial en el método

onSizeChanged () :

@Override

protected void onSizeChanged(

int w, int h, int oldw,int oldh.) {

Page 178: Android

IVNUHOID PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I MA IHAVI'MH I JEMPLOS 163

X=w/2;

y=0;

ymax=h;

energia=0.5f * velocidad * velocidad - aceleración * y; }

Con estos cambios el movimiento se mantiene estable, puesto que forzamos i|ue \á

energía sea constante y, con ello, también la velocidad máxima de la bola.

15.4. Simulación de caída con ligadura

Una ligadura mecánica es una restricción sobre el movimiento de un cuerpo. En la niguiente

actividad simularemos el movimiento de un cuerpo, representado por un circulo rojo, que

cae por la gravedad siguiendo una trayectoria parabólica, por «ijemplo una bola que se deja

caer en un pozo con dicha forma. La figura 15.3 muestra dos instantáneas del programa

Android durante su caída. Inicialmente ostá localizado en las coordenadas (xmin,ymin)

= (o, 0) . La ecuación de la pnrábola que está dibujada es:

x0

donde ymax es la altura del canvas y x0 es la mitad de su anchura. En la iciividad hemos

introducido una clase Trayectoria con métodos para calcular las piopiedades de la

trayectoria. Por ejemplo getY(x) proporciona el valor de y en lunción de x.

Lsta simulación está basada en el ejemplo de la pelota botadora de la sección .interior.

La fuerza que se ejerce sobre la partícula está dirigida en la dirección y (li.icia abajo, pero y

es positivo en nuestro sistema de coordenadas):

Fy = ma

donde m=l es la masa y a es la aceleración de la gravedad. Utilizaremos el I •( íncipio de

conservación de la energía:

E = T — may

donde T es la energía cinética, mv212, y - may la energía potencial. A partir de «’••l.i

ecuación podemos calcular la altura si conocemos la velocidad, como en el ■ .r.o de la

pelota botadora: T-E

y = ------- ma

Page 179: Android

164 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII M A, IHAVl' !¡ I)E EJEMPLOS

Figura 15.3. La partícula que cae con una ligadura y está obligada a seguir una parábola.

Finalmente, conocida la altura y, podemos conocer la coordenada horizontal a partir de

la ecuación de la parábola inversa:

x = x0±xj\-y/ymax

El problema es elegir enre las dos soluciones correspondientes a las dos posiciones

posibles (izquierda o derecha). Nosotros lo haremos introduciendo una variable booleana,

cambio, que cambia de valor cada vez que la partícula llega abajo y pasa por el punto

inferior de la curva. Si la variable es true, se mueve hacia la izquierda y tomamos el

signo menos. Si es f a l s e , se mueve hacia la derecha y tomamos el signo positivo.

Todo se reduce a calcular la velocidad en cada instante. El vector velocidad es siempre

tangente a la curva de la trayectoria. Por tanto, conocemos su dirección y resta por calcular

su magnitud o módulo v = | v |. En este caso, la trayectoria es una parábola f(x). El vector

tangente a la gráfica de una función f(x) está determinado por su derivada:

T= (lf(x))

Por otra parte, la componente tangencial de la aceleración es (ver Alonso-Finn, Eq.

(5.43)):

«7- = uTdv / di

Esta aceleración debe ser igual a la fuerza tangencial (para m~l), que es la componente

de la fuerza gravitatoria en la dirección de la tangente T:

FT = maf (x) / (1 +f(x)2)ia

Por tanto, lo que hacemos es calcular el cambio en la velocidad en cada intervalo di

Sli«7:30PM 7i39 PM Ligaduras I Ligaduras

*=9 y=57 / \ x=97 y=4tr [ t=14380 / \ t=15010 1

\ v=0.35484576 / \ v= 9.971766 I

\ Componentes de la velocidad / 1 1 \ Componentes de la velocidad j

\ VX=0.060052082 / \ VX=0.25849575 I \ VY=0.34872743 / \ 0.9357546 /

\ /

\ / \ /

\ /

Page 180: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILLS A IKAVÉN DI I II MPI.OS 1 6 5

mediante:

dv = (Ft/ m)dt

El siguiente listado es el programa Java completo. La dinámica anterior está

implementada en el método cambiaPosicion3(). Las propiedades de la trayectoria

se calculan usando un objeto de la clase Trayectoria.

package es.ugr.ligaduras;

import android.app.Activity; import

android.content.Context; import

android.graphics.Canvas; import

android.graphics.Color; import

android.graphics.Paint; import

android.graphics.Paint.Style; import

android.graphics.Path; import

android.os.Bundle; import

android.view.View;

import android.view.View.OnClickListener;

public class Ligaduras extends Activity implements

OnClickListener{

boolean continuar=true;

float velocidad=0.If;

float

aceleracion=0.OOlf;

float energia; int dt=1;

int tiempo=0;

Thread hilo=null;

DinamicaView dinamica;

Trayectoria trayectoria=new Trayectoria(100,100);

/** Called when the activity is first created. */ @Override

public void onCreate(Bundle savedlnstanceState)

{ super.onCreate(savedlnstanceState);

dinamica=new DinamicaView(this);

setContentView(dinamica);

dinamica.setOnClickListener(this)

;

hilo = new Thread(dinamica)■ hilo.start();

}

// detenemos el hilo si pausa

@Override

public void onPause(){

super.onPause(); continuar=false; }

Page 181: Android

166 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIL! S A. IKAVI':. DE EJEMPLOS

// reiniciamos el hilo si resume

@Override

public void onResume(){

super.onResume() ; continuar=true;

if(hilo==null){

hilo=new Thread(dinamica);

hilo.start() ; }

}

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

continuar=!continuar; if(continuar|

hilo==null){ hilo=new Thread(dinamica);

hilo.start(); }

}

class DinamicaView extends View implements Runnable{

int x,y,xmin,ymin,ymax; // coordenadas float

tangenteX,tangenteY; float tx,ty;

Paint paintFondo,paintParticula,paint,

paintCurva,paintVector;

Path path;

String control; boolean cambio=true;

public DinamicaView(Context context) {

super(context);

// Colores para el dibujo y tamaño del texto

paintFondo=new Paint();

Page 182: Android

«HUNDID: PROGRAMACIÓN De DISPOSITIVOS MÓVII F.SA IHAVÉS 111 I II MI'IOS

paintParticula=new Paint () ; paint=new

Paint(); paintFondo.setColor(Color.WHITE);

paintParticula.setColor(Color.RED);

paint.setColor(Color.BLACK);

paint.setTextSize(18); paintCurva=new Paint();

paintCurva.setStyle(Style.STROKE);

paintVector=new Paint();

paintVector.setStrokeWidth(8);

paintVector.setColor(Color.BLACK); }

// obtiene geometria del canvas @0verride

protected void onSizeChanged(

int w, int h, int oldw,int oldh){

X=w/2; xmin=0; y=o;

ymax=h-xmin;

float anchura=w; float altura=h;

trayectoria=new Trayectoria(anchura,altura); ymin=(int)

trayectoria.getY(xmin); energia=0.5f * velocidad *

velocidad - aceleración * ymin;

control="anchura:"+anchura+" altura:"+altura; //

construye el path de la trayectoria path=new Path();

path.moveTo(xmin,ymin); for (int i=xmin; i<anchura-

xmin;i++){ float xi=i;

float yi=trayectoria.getY(xi);

path.lineTo(xi,yi); }

}

@0verride public void run() {

while(continuar){

cambiaPosicion3();

postlnvalidate();

try { Thread.sleep( dt ); }

catch ( InterruptedException e ){ ; } }

Page 183: Android

public void cambiaPosicionS( ) {

1 6 8 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I í A TRAVÉS DE EJEMPLOS

float[] tangente={0, 0}; tiempo=tiempo+dt;

tangente=trayectoria.getTangente(x) ;

float tangenteX=tangente[0];

float tangenteY=tangente[1];

tx=tangenteX*velocidad;

ty=tangenteY*velocidad;

float aT=aceleracion*tangenteY;

velocidad=velocidad+aT*dt;

float cinetica=velocidad*velocidad/2;

float yfloat=((cinetica-energia)/aceleración);

y=(int) yfloat;

if(y>=ymax) {

x=(int)

(x+Math.signum(velocidad)*dt);

y=(int) trayectoria.getY(x); cambio=!

cambio; }

if (cambio) x=(int) trayectoria.getX2(y);

else x=(int) trayectoria.getXl(y);

// si llega arriba invertimos velocidad

if(y<ymin)velocidad=-velocidad;

(»Override

public void onDraw(Canvas canvas ){

canvas.drawPaint(paintFondo);

canvas.drawCircle(x, y, 30, paintParticula);

canvas.drawText("x="+x+" y = " + y ( 50, 50, paint); canvas.drawText("t="+tiempo, 50, 90, paint);

canvas.drawText("v="+velocidad, 50, 130,

paint); canvas.restore();

canvas.drawPath(path,paintCurva);

canvas.drawText("Componentes de la

velocidad", 50,170,paint) ,-

float e=100; // escala para vector

canvas.drawLine(x,y, x+e*tx,y+e*ty,paintVector);

canvas.drawText("V",x+e*tx+20,y+e*ty-20,paint);

canvas.drawText("VX="+tx, 50,200, paint);

canvas.drawText("VY="+ty, 50,230, paint); }

} // fin dinamica

}

Page 184: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I HA IHAVpH DI I II Ml’l OS I 69

// clase parara la trayectoria de una partícula

class Trayectoria{

float yMax,xO;

Trayectoria(float anchura, float

altura){ yMax=altura; x0=anchura/2;

float getY(float x){ float xxO= (x-xO)

/xO ,- float y=yMax*(l-xxO*xxO);

return y; }

// raiz positiva de la función inversa

float getXl(float y){

double raiz,radicando;

radicando=Math.max(Of,1-

y/yMax);

raiz=Math.sqrt(radicando);

float xl=(float) (xO+xO*raiz);

return xl; }

// raiz negativa de la función inversa

float getX2(float y){

double raiz,radicando;

radicando=Math.max(Of,1-y/yMax);

raiz=Math.sqrt(radicando) ; float

x2=(float) (xO-xO*raiz); return

x2; }

// componente y del vector unitario tangente a la

curva float[] getTangente(float x){

float [] tangente=new float[2];

float xxO=(x-xO)/xO;

float derivada=-yMax*2*xxO/xO;

double

denominador=Math.sqrt(l+derivada*derivada);

tangente [0] = (float) (1/denominador) ; tangente

[1] = (float) (derivada/denominador); return

tangente;

} }

}

Page 185: Android

170 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII '• A I U/XVI'S DE EJEMPLOS

El resultado se ve en las figuras 15.3, 15.4 y 15.5. La posición y velocidad dit la

partícula se calculan en el método cambiaPosicion3 <). Cuando la partícula llega

arriba invertimos la velocidad para que vuelva a bajar en sentido opuesto Existe un

problema cuando la partícula llega abajo, al punto mínimo (figura 15.5), ya que la

componente tangencial de la fuerza es cero, por lo que su velocidad no cambiaría y, por

tanto, tampoco su altura. Si no hacemos nada más, la partícula llega al mínimo y se detiene.

Pero la partícula debe seguir adelante puesto que su velocidad no es cero. Para que sea

así, en este punto, debemos modificar la coordenada x de la partícula mediante:

dx = vdt

y así conseguimos que la partícula siga adelante. Hay que tener cuidado, además, al

calcular las coordenadas en pixeles, puesto que son números enteros y, por redondeo, es

posible que dx=0.

P~~ üSi© *31 PM üü©7:31 PM I Ligaduras I Ligaduras

Figura 15.4. La partícula que cae con una ligadura parabólica, en su

trayectoria ascendente.

Page 186: Android

tbSl«7:33PM

Mili l'IdHIRAMACIÓN DE DISPOSITIVOS MÓVILI 'i A TRAVÉS DI I J! MPLOS

Figura 15.5. La partícula que cae cerca del mínimo del potencial

CigSdtuías

Page 187: Android
Page 188: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl FS A TRAVÉS DE I .11 MIM OH 173

APÉNDICE A

I LEMENTOS DE JAVA

I ste apéndice contiene una introducción al lenguaje Java necesario para seguir los ejemplos

de este libro. Esta introducción a Java es específica para Android. No li ataremos los

programas Java independientes ni los applets. Por tanto, todos los ejemplos podrán

ejecutarse como aplicaciones Android en un emulador o en un loléfono o tablet. Esta

aproximación a Java es algo inusual. Existe una idea ostablecida de que el lenguaje Java

debe aprenderse antes que Android y de hecho todos los libros de Android suponen que el

lector conoce Java u otro longuaje similar como C++. Aunque la lógica de primero se empieza

a andar y luego a correr es correcta, lo que es desacertado en en el presente caso es asociar

a Android con correr. Aunque las aplicaciones profesionales de Android non programas de

gran complejidad, esto no impide que se puedan escribir programas sencillos que puedan

comprenderse y que permitan aprender el Innguaje. Al aprender Android y Java al mismo

tiempo, se evita tener que asimilar conceptos de Java que Android no soporta, por ejemplo,

los gráficos y los applets.

A.1. Programa básico de Java con Android

Utilizaremos el programa Eclipse para crear un nuevo proyecto de Android llamado /

jemploJaval. Un proyecto de Android contiene un programa de Java y otros datos en una

serie de ficheros, que son utilizados por el programa o por el sistema. Un programa de Java

es una colección de clases, contenidas en uno o varios ficheros filel.java, file2.java,.... En

Android estos ficheros java se • ilmacenan en el directorio src de nuestro proyecto actual. Al

crear nuestro nuevo proyecto de Android, se crea la actividad EjemploJaval, almacenada en

el fichero I jemploJaval.java, que se encuentra en el directorio src. Al hacer doble click sobre

este fichero en el explorador de archivos, se abre en el editor de Eclipse y nos encontramos

con el programa Java más simple:

package es.ugr.amaro;

import android.app.Activity;

publíc class EjemploJava extends Activity (

/** Called when the activity is first created. *J

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); }

}

Este es el modelo que utilizaremos como punto de partida en todos nuestros programas

Java. Examinemos su estructura:

• El programa contiene una serie de instrucciones o sentencias. En Java cada

instrucción o sentencia debe terminar con un punto y coma. Se pueden escribir

Page 189: Android

import android.os.Bundle;

174 ANDROID; PROGRAMACIÓN DE DISPOSITIVOS MÓVII ISA IHAVÉSDÍ liJEMPLOS

varias instrucciones en una línea o una instrucción en varia líneas. Los espacios en

blanco son ignorados.

• La primera línea package es .ugr .amaro. ejemplojaval; indica que

esta clase pertenece al paquete es.ugr.amaro. Cada punto en el nombre de un

paquete indica un subdirectorio, por lo que nuestro programa Java está contenido en

el directorio:

src/es/ugr/amaro/ejemplojaval

• Las dos líneas siguientes precedidas por import indican que este programa utiliza

dos clases predefinidas en dos paquetes del sistema Android.

import android.app.Activity; import android.os.Bundle;

En este caso, el programa importa la clase Activity del paquete android. app y la

clase Bundle del paquete android.os. Android contiene numerosos paquetes con miles

de clases. En el editor de Eclipse, cuando escribimos el nombre de una clase, ésta se subraya

en rojo si se requiere añadir un import, por lo que no necesitamos recordar el nombre del

paquete. Basta pulsar con el botón derecho sobre el nombre de la clase y aparece una lista de

opciones, entre ellas la de importar el paquete. La seleccionamos y Eclipse escribirá la

instrucción import por nosotros.

• El programa contiene una clase llamada EjemploJaval cuya definición abarca el

bloque de código comprendido entre la llave inicial y final:

public class JavaEjemplol extends Activity { }

Nótese que la definición de la clase no termina con punto y corra. Esto es debido a que no

se trata de una sentencia o Instrucción ejecutable, sino un tipo de definición. El atributo

public indica que la clase es pública y puede ser utilizada oxternamente. La declaración de

la clase finaliza con extends Activity. Esto significa que nuestra clase es una subclase

de ia clase Activity, definida en el paquete android.app y hereda todas sus

propiedades, además de las que nosotros le queramos añadir. Por tanto, JavaEjemplol es una

extensión o una generalización de la clase Activity. Se dice que Activity es una super-clase de

JavéÉjemplol.

• La siguente línea:

/** Called when the activity is first created. */

es un comentario. Los comentarios pueden abarcar varias líneas y se delimitan por las

parejas de caracteres:

/ -k -k . . . * /

o también:

/* */

Page 190: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A 1KAVÉS DE IiJEMPl OS 175

Las dobles barras // comienzan un comentario hasta el final de la línea.

• Dentro de la definición de la clase JavaEjemplol encontramos la declaración de un

método de la clase llamado onCreate.

@Override

public void onCreate(Bundle savedlnstanceState) {

}

Este método es una función con un parámetro llamado savedlnstanceState de tipo

Bundle. La declaración comienza con la clave (SOverride, lo que indica que se está

redefiniendo o sobreescribiendo el método onCreate de la super-clase. El tipo de acceso

del método es public, o público, al que se puede acceder externamente desde otro

programa. El método es de tipo void porque esta función no devuelve ningún resultado.

• Finalmente, entre dos llaves, tenemos la definición del método, que consiste en dos

instrucciones:

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Page 191: Android

176 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '.A lUAVfs DE EJFMPLOS

En la pimera, el prefijo super indica ejecutar un método de la super-clase Activity.

Por tanto, la instrucción:

super.onCreate(savedlnstanceState)

ejecuta el método onCreate () de Activity, aplicado sobre el argumento

savedlnstanceState. La última instrucción ejecuta el método setContentview()

tomando como argumento la variable R. layout. main, qua es una referencia al fichero

main.xml que contiene el layout de la interfaz de usuario que vemos en la pantalla.

Esta es la estructura básica de una actividad o programa de Android, que puede

considerarse un molde, o template para todos los programas que escribiremos a continuación.

Usaremos siempre el siguiente fichero res/layout/main.xml:

<?xml version="l. 0" encoding= "utf -8 11 ?>

cLinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:background="#ffffff"

android:orientation="vertical" android:layout_width="f

ill_parent" android:layout_height="fill_parent"

>

cTextView

android:textColor="#000000"

android:textSize="18sp"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"

android:id="@+id/textView" / >

</LinearLayout>

El anterior layout define un campo de texto llamado “textView” que nos permite escribir en

la pantalla. A continuación, modificaremos el programa básico para escribir texto en la pantalla

como en el siguiente ejemplo.

package es.amaro.ugr.ej emplojaval;

import android.app.Activity;

import android.os.Bundle;

import android.widget.TextView;

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate (savedlnstanceState)

setContentview(R.layout.main);

T'íxtView textview=

(Textview) f indViewByEd (R. id .

textview) ; i üxtView.setText(

"El programa más básico de Java con Android " +

"escribe un texto en la pantalla con setText.");

Page 192: Android

HI Ut DISPOSITIVOS MÔVIII SA TRAVÉS DI l II NI'IOS 177

IüxtView.append(

" Así se añade más texto con append."); i

üxtView.append("\nAsí se escribe una segunda línea." );

i '

Ai¡ul se define una variable textview que se refiere al campo de texto y mili' modificarlo

con setText () y añadir más texto con append (). El (»••iiliiido se ve en la figura A.1.

lie 18:49

Ejemplojaval

El programa más básico de Java con Android escribe un texto en la

pantalla con setText. Así se añade más texto con append.

Así se escribe una segunda línea.

Figura A.1. Programa básico para escribir texto.

A ) V.nubles

Lm* vMilnlilt'M almacenan datos, que pueden ser datos primitivos (números en IdIIhIiI'i

in|in>:.ontaciones) o referencias a objetos (que son conjuntos de datos). MI II|m>i» dn datos

primitivos son: int, float, double, char, boolean, |HI i n i n . i t y byte. Los

más importantes pueden almacenar:

• int. Un número entero entre - 2 , i 4 = 7 , 4 8 3 , 6 4 8 y - 2 r l 4 7 , 4 8 3 , 6 4 7 .

• float. Un número con decimales entre 3 . 4 e - 3 S y 3 . 4 e 4 3 8 .

• double. Un numero en doble precisión entre i. 7e-308 yi.7e+308.

• char. Un caracter UNICODE.

• boolean. Una variable lógica que vale true o false.

Otros tipos de variables importantes son:

• string. Es una clase para almacenar cadenas de caracteres.

Page 193: Android

178 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÚVII I ■ A I HAVÉK l>l EJEMPLOS

• void. Se usa para describir un método que no devuelve ningún valor.

Las variables deben declararse e inicializarse en cualquier punto del programa. Por

ejemplo, modifiquemos el programa anterior para declarar e inicializar algunas variables,

que escribiremos en pantalla.

public class EjemploJaval extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textview);

tv.setText(

"Declaración e inicialización de variables ");

// declaración e inicialización de variables int i ;

i=123;

float x,y=l; x=0.5123f;

double a= 123, b=3.1416e-10; char caracter='a 1;

boolean esFalso=true;

String cadena="Esto es una cadena";

// escribe los valores de las variables

tv.append("\n i="+i);

tv.append("\n x="+x+",y="+y);

tv.append("\n a="+a+",b="+b);

tv.append("\n caracter="+caracter);

tv.append("\n esFalso="+esFalso);

tv.append("\n cadena="+cadena);

} }

Page 194: Android
Page 195: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII (NA TRAVÍM1I I I I M I ' I OÜ I 79

El resultado de este programa se ve en la figura A.2. Vemos que pueden declararse varias

variables del mismo tipo en la misma sentencia separándolas con comas. Los valores de las

variables float deben tener el sufijo "f" .

22:231 EjempioJaVal

Declaración e inicialización de

variables

i=123

x=0.5123,y=1.0

a=123.0,b=3.1416E-10 caracter=a

esFalso=true

cadena=Esto es una cadena

Figura A.2. Declaración e inicialización de variables.

A.3. Conversión de variables

I as valores de las variables se pueden convertir de un tipo a otro. SI la conversión se hace a

un tipo más amplio, por ejemplo de int a float, la conversión se realiza Implícitamente.

Si, al contrario, la conversión se realiza a un tipo más restringido, necesitamos indicarlo

explícitamente con una conversión o cast, indicando el nuevo tipo entre paréntesis pues se

puede perder información. Por ejemplo:

float a = 1.5f;

int i = (int) a;

En el siguiente ejemplo convertimos un valor de int a float a double y viceversa.

public class EjemploJaval extends Activity {

/** Called when the activity is first created. */

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

Page 196: Android
Page 197: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 180

TextView tv=(TextView) findViewById(R.id.textView)

tv.setText(

"Conversión de variables ");

// conversion de int a float a double int i = 12

5 ; float x=i; double d=x;

tv.append("\n\n Conversion de int a float a double") ;

tv.append("\n i="+i); tv.append("\n x="+x); tv.append("\n

d="+d);

// conversion de double a float a int

d=0.01234567 89e3; x=(float) d; i=(int) X;

tv.append("\n\n Conversion de double a float a int");

tv.append("\n d="+d); tv.append("\n x="+x); tv.append("\n

i="+i);

El resultado de la conversión se ve en la figura A.3

Conversion de variables

Conversion de int a float a double

¡=125

x=125.0

d=125.0

Conversion de double a float a int

d=12.3456789 x=12.345679 i=12

Figura A.3. Conversión de variables.

Con las variables numéricas se pueden realizar las operaciones aritméticas de suma, resta,

multiplicación y división [ + , - , * , / ) ■ También está definido el resto tras una división (%)

y el incremento y decremento en una unidad (+-4, . A

continuación, tenemos un ejemplo de utilización de estos operadores algebraicos. El

resultado se ve en la figura A.4. Los operadores se pueden combinar para realizar

operaciones más complejas. Hay que tener cuidado de incluir los paréntesis necesarios, si

no estamos seguros de la preferencia en que se realizan las operaciones. Por ejemplo, la

multiplicación se realiza antes que la suma, así que x+y*z=x+ (y*z) . Se pueden sumar

variables de distinto tipo y el resultado es una variable del tipo más amplio. Por ejemplo, la

suma de un entero y un float es un float. Si queremos que el resultado de una operación se

Page 198: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES ^ IRA7ÉS OE EJEMPLOS

convierta aun tipo más restingido, debemos preceder la expresión con el nuevo tipo entre

paréntesis, poniendo también entre paréntesis, si es necesario, la expresión que se está

convirtiendo. Por ejemplo i = ( i n t ) (x+y) no es lo mismo que i= ( i n t ) x+y. En este último

caso, x se convierte a entero antes de sumar. Ante la duda siempre es preferible escribir los

paréntesis.

Ü8B<@ 8:30 Ejemplojaval

Operaciones aritméticas

2.0 + 3.0 = 5.0 2.0-3.0 = -1.0 2.0 * 3.0 = 6.0 2.0 / 3.0 = 0.6666666666666666

74.0 / 3.0 da resto = 2.0

i incrementado en uno = 2 i

decrementado en uno =1

Operaciones con tipos distintos 74.0+1=75.0 74.0+1=75

Resultado de operación compuesta Z=307.4009891458349

Figura A.4. Operaciones algebraicas con variables.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv= (TextView) findViewByld(R.id.textView) ;

tv.setText(" Operaciones aritméticas\n");

int i = 1,j ; double x=2,y=3,z;

// suma z=x+y;

tv.append("\n "+x+" + "+y+" = "+z);

// resta z=x-y;

tv.append("\n "+x+" - "+y+" = "+z);

// multiplicación z=x * y;

tv.append("\n "+x+" * "+y+" = "+z) ;

// division z=x / y;

tv.append("\n "+x+" / "+y+" = "+z);

// resto X= 74 ;

Z = X % y;

tv.append("\n\n "+x+" / "+y+" da resto = "+z);

Page 199: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES ^ IRA7ÉS OE EJEMPLOS

// incremento i + +;

tv.append("\n\n i incrementado en uno = "+i); i--;

tv.append("\n i decrementado en uno ="+i);

// suma de tipos distintos

tv.append("\n\n Operaciones con tipos distintos"); z= x+i; j=

(int) x+i;

tv.append("\n"+x+"+"+i+"="+z); tv.append("\n"+x+"+"+i+"="+j);

// operaciones más complejas z= (x* (y+j ) / (x*x+l) -1/y) *

(i-x) /y;

Z = Z * Z ;

tv.append(

"\n\n Resultado de operación compuesta z="+z);

}

I .is fundones matemáticas están definidas como métodos de la clase Math en el paquete

java.lang. Este paquete es importado automáticamente. En el MHuiente ejemplo

utilizamos algunas de las funciones más usuales y el resultado mí ve en la figura A.5.

i ül¡® 10:39 I

Ejemplojaval

x = PI = 3.141592653589793 y

= -1.0

Valor absoluto de y =1.0 Raiz cuadr. de

x=1.7724538509055159 Logaritmo de x

=1.1447298858494002 Exponencial(x)

=23.140692632779267 x al cubo

=31.006276680299816 coseno de x= -1.0

seno de x= 1.2246467991473532E-16

Tangente(x)=

-1.2246467991473532E-16

Arcocoseno(y)= 3.141592653589793

Arcoseno(y)= -1.5707963267948966

Arcotangente(y)=

-0.7853981633974483

Máximo de x ey =3.141592653589793

El resto de x entre y es=

0.14159265358979312

Expresado en grados x= 180.0

Expresado en radianes

y=-0.017453292519943295

Figura A.5. Funciones matemáticas en Java.

public class EjemploJaval extends Activity {

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate (savedlnstanceState)

Page 200: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 184

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

double x,y,z; x=Math.PI;

tv.setText("x = PI = "+x);

y = - i ;

tv.append("\n y = "+y);

tv.append("\n Valor absoluto de y ="4-Math.abs (y) )

; z=Math.sqrt(x);

tv.append("\n Raiz cuadr. de x="+z); z=Math.log(x);

tv.append("\n Logaritmo de x ="+z) ;

z=Math.exp(x);

tv.append("\n Exponencial(x) ="+z);

z=Math.pow(x,3); tv.append("\n x al cubo

="+z); z=Math.cos(x);

tv.append("\n coseno de x= "+z];

z=Math.sin(x);

tv.append("\n seno de x= "+z); z=Math.tan(x);

tv.append("\n Tangente(x)= "+z);

z=Math.acos(y);

tv. append (" \n Arcocoseno (y) = 11+z) ;

z=Math.asin(y);

tv.append("\n Arcoseno(y)= "+z);

z=Math.atan(y);

tv.append("\n Arcotangente(y)= "+z);

z=Math.max(x,y);

tv.append("\n Maximo de x e y ="+z);

z=Math.IEEEremainder(x, y);

tv.append("\n El resto de x entre y es= "+z);

z=Math.toDegrees(x);

tv.append("\n Expresado en grados x= "+z);

z=Math.toRadians(y);

tv.append("\n Expresado en radianes y="+z);

} }

Otros métodos de interés son:

• randomO devuelve un número aleatorio entre 0 y 1,

• los métodos de redondeo hacia arriba ceil (), hacia abajo floor(), que

proporcionan números double con cifras decimales nulas,

• round () redondea un float y lo transforma en el int más próximo, o

redondea un double y lo transforma en long.

El siguiente ejemplo hace uso de estos métodos. El resultado se ve en la figura A.6.

Page 201: Android

I SWfcl 17:21 1

PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I S A IHAVf!; DI I Jl UPLOS

Ejemplojaval

Números aleatorios y métodos de redondeo

Un número aleatorio entre 0 y 2, x=

1.2516931781779987 ceil(x)= 2.0 floor(x)=

1.0 round(x)= 1

Redondeos hasta cualquier cifra decimal

redondeado a la segunda cifra 1.25

redondeado a la tercera cifra 1.252

redondeado a la cuarta cifra 1.2517

redondeado a la quinta cifra 1.25169

Figura A.6. Números aleatorios y métodos de redondeo.

public class Ejemplojaval extends Activity {

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView)

tv.setText("Números aleatorios y métodos de redondeo

double x,y; int i ;

x=2*Math.random(); tv.append(

"\n Un número aleatorio entre 0 y 2, \n x= "+x

y=Math.ceil(x);

tv.append("\n ceil(x)= "+y);

y=Math.floor(x);

tv.append("\n floor(x)= "+y);

i=(int) Math.round(x);

tv.append("\n round(x)= "+i);

tv.append(

"\n\n Redondeos hasta cualquier cifra decimal")

y=Math.round(x*l.e2)/I.e2;

Page 202: Android
Page 203: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 186

A.6. Bloque if-else

Un bloque es una serie de instrucciones entre los caracteres abrir y cerrar llave:

{ }

En Java un bloque se procesa como si se tratara de una sóla instrucción o sentencia. Las

variables declaradas dentro de un bloque no están definidas fuera de él.

Los bloques if-else permiten ejecutar instrucciones dependiendo de la relación entre los

valores de ciertas variables. Esta relación se establece mediante el uso de los operadores de

comparación, que son: igual, distinto, mayor, menor, mayor o igual, menor o igual:

==, •=i >, <, >=, <=

También se pueden utilizar variables booleanas, que darán true o false si cierta relación se

verifica, por ejemplo:

float x = 1, y = 2 ;

boolean condicion = x < y;

Los operadores lógicos entre variables booleanas son: AND, denotado en java:

Se , ScSc

y OR:

Por ejemplo:

boolean condicionl,condicion2,condicion3,condicion4;

condicion3 = condicionl & condicion2; condicion4 =

condicionl | condicion2;

la segunda cifra "-+y) la

tercera cifra "-+y) la

cuarta cifra "-(-y) ; la

quinta cifra " n-y) ;

tv.append("\n redondeado a

y=Math.round(x*1.e3)/I.e3;

tv.append("\n redondeado a

y=Math.round(x*l.e4)/I. e4 ;

tv.append("\n redondeado a

y=Math.round(x*l.e5)/I.e5;

tv.append("\n redondeado a

Page 204: Android

ANI lUOID: PROGRAMACIÓN DE DISPOSITIVOS MÔVILt : i A IKAVI'MJI I JI MPI OS 187

La diferencia entre los operadores simples (&) o dobles <&&), es que el simple evalúa

ambas condiciones, mientras que el doble evalúa la primera y, si es falsa, no evalúa la

segunda.

En el siguiente ejemplo demostramos el uso del bloque if-else y del uso de variables

boolean. El resultado en la figura A.7.

Bloque if-else

2.0 < 3.0

Operadores booleanos condicionl

es = true condicion2 es = true Las

dos son true simultáneamente:

2.0 > 1 y 3.0 <10

Figura A.7. Bloques if-else y uso de variables booteanas.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText(" Bloque if-else \n"); double x=2,y=3;

if(x==y){

tv.append("\n "+x+" = "+y);

} else if(x>y){

tv.append("\n "+x+" > "+y) ?

} else {

tv.append("\n "+x+" < "H-y) ; } tv.append("\n\n Operadores booleanos");

boolean condicionl= x>l;

boolean condicion2 = y<5;

tv.append("\n condicionl es = "tcondicionl);

Page 205: Android

188 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I 1; A IIMVÉS DE EJEMPLOS

tv.append("\n condicion2 es = "+condicion2);

if(condicionl & condicion2){

tv.append("\n Las dos son true simultáneamente: " +- "\

n" +x+11 > 1 y " +y+" < 10");

} else{

tv.append("\n Una de las dos es falsa"),- }

} }

A.7. Bucles for

El bucle for permite repetir una Instrucción normalmente utilizando un índice que se

incrementa en cada paso. La instrucción a repetir puede ser una única sentencia o un bloque

delimitado por llaves. Su estructura es la siguiente:

for ( inicializacion ; condicion ; incremento ) {

// bloque de sentencias

sentencial; sentencia2;

El argumento de for, entre paréntesis, consta de tres sentencias separadas por un punto y

coma. En la primera se inicializa una o varias variables. La segunda es una condición o

expresión booleana. Si la condición se verifica, se ejecutará el bloque que viene a

continuación. Finalmente se incrementa la variable. Se repite el proceso hasta que la

condición deje de verificarse. Las variables declaradas dentro del bucle no están definidas

fuera de él.

En el siguiente ejemplo usamos un bucle for para generar una tabla de valores de la

función seno entre 0 y 1, figura A.8. Si intentamos escribir el valor de la variable i después

del bucle, el compilador de java genera un error: variable no definida.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState)¡

Page 206: Android

ANI)ROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII [RAIHAVI'Mil I II Ml'I OS 189

setContentVìew(R.layout.main); TextView tv=(TextView) f indViewByld (E. id. textVi ew)

tv.setText("Bucle for"); double x=10,y = 0; forfint

i=0; i<10; i + + ){ y=Math.sin(i/x);

tv.append("\n "+i+", sin{i/x)= "+y); }

tv.append(

"\n Fin del bucle for, i no esta definida");

tv.append("\n y= "+y);

} }

ffij« 7:44 Ejempiojaval

Bucle for

0, sin(i/x)= 0.0

1, sin(i/x)= 0.09983341664682815

2, sin(i/x)= 0.19866933079506122

3, sin(i/x)= 0.29552020666133955

4, sin(i/X)= 0.3894183423086505

5, sin(i/x)= 0.479425538604203

6, sin(i/x)= 0.5646424733950354

7, sin(i/x)= 0.644217687237691

8, sin(i/x)= 0.7173560908995228

9, sin(i/x)= 0.7833269096274834

Fin del bucle for, i no está definida y=

0.7833269096274834

Figura A.8. Bucle for.

A.8. Bucle while

I I bucle while es similar al bloque for, pero sólo requiere como argumento una i ondlción o

variable booleana. El bucle se ejecuta repetidamente hasta que la condición sea falsa.

while( boolean ) { // bloque de sentencias

sentencial;

sentencia2;

}’"

En el siguiente ejemplo generamos una tabla de 10 números aleatorios usando un

bucle while con una variable que se va incrementando hasta que toma el valor 10, y el bucle

finaliza (figura A.9).

Page 207: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 190

8:06

Ejemplojaval

Bucle while

0, random()= 0.655774082 5333068

1, random()= 0.6000441211517162

2, random()= 0.22138671116387454

3, random()= 0.18030833619411024

4, random()= 0.18148334430544466

5, random()= 0.3629492692812285

6, random()= 0.5803092947428174

7, random()= 0.7989001640293847

8, random()= 0.8888199333245952

9, random()=

0.6973743935769815 Fin del bucle for,

i=10

Figura A.9. Bucle while.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Bucle while"); int i=0; while(i<10){

// variable no definida fuera del bucle double

y=Math.random(); tv.append("\n "+i+", random()= "+y)

; i++;

}

Page 208: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVII HS A IRAVÉS 01 I .11 MPIOS 191

tv.append(11 \n Fin del bucle for, Í="4L);

} }

Para mayor control del desarrollo de un bucle, pueden utilizarse además las siguientes

sentencias:

• break. Finaliza el buble.

• continué. Vuelve al comienzo del bucle.

Por ejemplo en el siguiente programa utilizamos break y continué para controlar la

terminación de un bucle, saltando el quinto paso (figura A.10).

I ................. Sil« 8:25 I Ejemplojaval

Bucle whiie

1, sqrt()= 1.0

2, sqrt()= 1.4142135623730951

3, sqrt()= 1.7320508075688772

4, sqrt()= 2.0

6, sqrt()= 2.449489742783178

7, sqrt()= 2.6457513110645907

8, sqrt()= 2.8284271247461903

9, sqrt()= 3.0

Fin del bucle, 1=10

Figura A.10. Bucte while usando break y continue.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Bucle while"); int i=0; while(true){ i +

+ ;

// salta al principio del bucle if(i==5) continue;

// finaliza el bucle if (i==10) break;

double y=Math.sqrt(i); tv.append< "\n

"+i+", sqrt()= "+y) } tv.append("\n Fin del bucle, i="+i);

}

Page 209: Android

192 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I ', A IRAVÉK III I JFMPLOS

}

A.9. Bloques switch

El bloque switch es una alternativa al bloque if-else si queremos realizar una acción

dependiendo del valor de una variable, comparándola con una serie de casos. Después de

cada caso hay que utilizar break para finalizar el bloque, porque todo lo que viene a

continuación se ejecuta siempre sin realizar las comparaciones. He aquí un ejemplo de uso de

switch dentro de un bloque for, cuyo resultado se ve en la figura A.11.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Bucle switch"); for(int i=0;i<20;i++){

switch(i){ case 5: {

tv.append("\n pasa por 5");

break; } case 10: {

tv.append("\n también pasa por 10");

break; } case 15:{

tv.append("\n toma el valor 15");

break; } default:

tv.append("\n i= "+i);

} // fin del bloque switch

} // fin del bloque for }

}

¡=0 ¡=1 i= 2 ¡=

3 ¡= 4

pasa por 5

¡= 6 i= 7

i=8 i= 9

también pasa por 10

¡=11 ¡=12 ¡=13 ¡=14

toma el valor 15

¡=16

¡=17

¡=18

¡=19

Figura A.11. Bloque switch dentro de un bucle for.

A.10. Métodos

Page 210: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII A TRAVC :, Uh fc II MI'I OS 1 9 3

Un método es un bloque de sentencias que se puede ejecutar repetidas veces invocando su

nombre. Los métodos pueden tener cero, uno o varios parámetros y devolver o no un

resultado de cierto tipo. Los métodos son el análogo de las funciones o subrutinas de otros

lenguajes. La declaración de un método tiene la siguiente estructura:

acceso resultado nombre (lista de parámetros) { // Bloque del método

return valor; // si no es void }

• Acceso indica si el método se puede ejecutar desde otra clase distinta, y puede

ser public, private, protected, o el tipo por defecto, si no se indica nada.

Page 211: Android

194 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MrtVII I ' • A IHWÉK DE I JEMPLOS

En el siguiente ejemplo definimos un método para calcular el factorial de un número («/).

Este método lo incluimos como método de la clase EjernploJav.il después del método

onCreate, en el que hemos estado programando hasta ahora. El método factorial es

llamado repetidas veces en un bucle desde el método onCreate. Distintos métodos de una

clase pueden llamarse entre sí. El resultado es una tabla con el factorial de los primeros 20

números, figura A.12.

Método factorial 01 = 1.0 1 1 = 1.0 2! = 2.0 3! = 6.0 4!

= 24.0 5! = 120.0 6! = 720.0

7! = 5040.0 81 = 40320.0 91 =

362880.0 101 = 3628800.0 11 ! = 3.99168E7 12! = 4.790016E8 13! =

6.2270208E9 14! = 8.71782912E10

15 ! = 1.307674368E12 16! =

2.0922789888E13 17! =

3.55687428096E14 18! =

6.402373705728E15 19 ! = 1.21645100408832 E17

Figura A. 12. Uso de un metodo para calcular el factorial de un numero.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Metodo factorial"); for(int i=0;i<20;i++){

tv.append("\n "+i+" ! = "+factorial(i)); }

}

// metodo para calcular el factorial de un numero double

factorial(int n){ double fac=l; if (n==0)return fac; for

(int i=l;i<=n;i++)fac=fac2i; return fac; }

}

En el siguiente ejemplo definimos un método void para imprimir un número, que no

devuelve ningún resultado. Tiene dos argumentos: un número float y un objeto TextView, el

campo de texto donde estamos escribiendo. El resultado de imprimir varios números en un

bucle se ve en la figura A.1 3.

public class EjemploJaval extends Activity {

2 Resultado debe ser un tipo de dato primitivo, int, float, double, etc., o el

nombre de una clase o void, si el método no devuelve ningún resultado.

• Nombre es el nombre del método.

• La lista de parámetros, Indicando tipo y nombre, separados por comas.

Page 212: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII.I HA ÍHAVI'. DI I II Ml*l OS 195

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Método void para imprimir"); for(int

i=0;i<20;i++){ float x= i*i; print(x(tv); }

}

// metodo para escribir un numero en un campo de texto

void print(float x, TextView tv){ tv.append("\n Metodo

print "+x); }

Figura A.13. Un método void para imprimir un número.

Un ejemplo de un método que no requiere ningún argumento es la función para generar

números aleatorios Math. random (J .

A.11. Clases y objetos

Un objeto es un conjunto de datos de distintos tipos que se referencian con una única variable.

Los objetos no sólo contienen datos sino que también realizan acciones. Cada objeto

pertenece a una dase y debe declararse como tal precediendo el nombre de la variable por el

nombre de la clase mediante la sentencia:

NombreDeLaClase variable;

¡ 8! ® 20:02

EjemploJaval Método voi d para imprimir Metodo pr int 0.0 Metodo pr int 1.0 Metodo pr int 4.0 Metodo pr int 9.0 Metodo pr int 16.0 Metodo pr int 25.0 Metodo pr int 36.0 Metodo pr int 49.0 Metodo pr int 64.0 Metodo pr int 81.0 Metodo pr int 100.0 Metodo pr int 121.0 Metodo pr ¡nt 144.0 Metodo pr int 169.0 Metodo pr int 196.0 Metodo pr int 225.0 Metodo pr int 256.0 Metodo pr int 289.0 Metodo pr int 324.0 Metodo pr int 361.0

Page 213: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 196

Una clase es un bloque de código con toda la información sobre los tipos de datos que

contienen sus objetos, cómo construirlos, y con métodos para operar sobre sus datos o para

realizar acciones concretas. Una dase contiene variables de clase y métodos. Todos los

métodos de una clase tienen acceso a las variables de clase y pueden modificarlas, a no ser

que las variables se declaren final. La estructura de una clase es la siguiente:

acceso class Nombre {

// variables de la clase

variablel; variable2;

//otras variables

//métodos de la clase

metodol (parámetros) {

....

metodo2 (parámetros){

i ”

// otros métodos }

Page 214: Android
Page 215: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIL! HA TRAVflI DI I .II MCI OS I97

El identlficador de acceso de una clase sólo puede ser public o ninguno. Todas las

sentencias de un programa Java, excepto package e import, deben estar contenidas dentro de

una clase. Las clases utilizadas en un programa Java pueden ser definidas por el

programador, o ser de un paquete de las librerías de Java. Existe el convenio de que el

nombre de una clase empiece siempre por mayúscula.

Un programa Java es una colección de clases en uno o varios ficheros. Un fichero puede

contener varias clases, pero sólo una puede ser public. El nombre del fichero debe

coincidir con el de la única dase public que contiene.

En el siguiente ejemplo definimos una clase Dato del tipo más simple, que contiene

únicamente datos: un entero, un float y un double. En la clase principal EjemploJava 1

creamos un objeto de tipo Dato usando new Dato() y asignamos valores a sus variables

o campos de clase. Para acceder a estas variables usamos el nombre del objeto, seguido de

un punto y el nombre de la variable. La salida del programa se ve en la figura A.14. La clase

Dato se ha incluido al final del fichero principal, pero podría igualmente incluirse sola en un

archivo Dato.java en el mismo directorio, declarándola public.

I ~ ~ _" SU« 22:181

Ejemplojav.n

Clase que contiene tres datos

numéricos

Se accede a las variables de clase

mediante el nombre del objeto,

seguido de un punto y el nombre de la

variable

miDato.¡= 1

miDato.f = 1.35

miDato.d = 230.0

Figura A.14. Uso de una clase para albergar datos.

public class EjemploJaval extends Activity {

@Override

Page 216: Android
Page 217: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 198

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText(

"Clase que contiene tres datos numéricos");

tv.append("\n Se accede a las variables de clase " +

"mediante el nombre del objeto, seguido de un " + "punto

y el nombre de la variable1');

// declaración de objeto Dato

Dato miDato;

// creación de objeto Dato;

miDato=new Dato();

// asignación de valores para el objeto Dato

miDato.i=l; miDato.f = 1.35f ; miDato.d=2.3e2 ;

tv.append("\n miDato.i= "+miDato.i); tv.

append (11 \n miDato. f = "+miDato. f) ;

tv.append("\n miDato.d = "+miDato.d);

} }

class Dato {

int i ;

float f;

double d; }

Entre los programadores de Java, se aconseja que las variables de clase se declaren

privadas mediante private y que no puedan ser modificadas, ni siquiera visibles, fuera de

la clase. Esto significa que el acceso a la variable de clase mediante objeto. variable no es

posible y dará un error de compilación. Para extraer y modificar las variables se usan

exclusivamente métodos, lo que permite controlar sus posibles valores. Para inicializar las

variables se usa también un método constructor con el mismo nombre que la clase, que se

ejecuta al crear un nuevo objeto. El constructor debe ser void. Puede haber varios

constructores con distintos argumentos y se ejecutará el que corresponda.

Page 218: Android
Page 219: Android

» BMP 5:38

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '.A IHAVÉ:. III I II MI'I OS

EjempJoJaval

Clase que contiene tres datos

numéricos

Se accede a las variables de cíase

mediante ef nombre del objeto,

seguido de un punto y uno de ios

métodos get{) miDato ,getl()= 1

miDato.getF() = 1.35 miDato.getD() =

230.0

Después de modificar las variables

con SET:

mi0ato,getl()= 200 miDato.getFO =

1.23456 miDato.getD() = 1.111 E-24

Figura A. 15. Uso de una clase para albergar datos, con variables de clase privadas.

A continuación, modificamos el ejemplo anterior ocultando los campos de clase y

usando métodos. El constructor Dato() permite inicializar los objetos al crearlos (figura A.

15).

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText(

"Clase que contiene tres datos numéricos");

tv.append("\n Se accede a las variables de clase " +

"mediante el nombre del objeto, seguido de un " +

"punto y uno de los métodos get()");

// declaración de objeto Dato

Dato miDato;

// creación de objeto Dato;

miDato=new Dato(1,1.35f,2.3e2);

tv.append("\n miDato.getl()= "+miDato.getl());

Page 220: Android
Page 221: Android

200 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

tv.append("\n miDato.getF{) = "+miDato.getF());

tv.append("\n miDato.getD() = "+miDato.getD())

miDato.setl(200); raiDato.setF(1.23456f);

miDato.setD(0.lllle-23);

tv.append(

"\n\n Después de modificar las variables con SET:"); tv.

append (11 \n miDato.getl () = "+miDato.getl());

tv.append("\n miDato.getF() = "+miDato.getF());

tv.append("\n miDato.getD() = "+miDato.getD());

} }

class Dato {

private int i;

private float f;

private double d;

// método constructor de la clase

Dato(int ivar, float fvar, double dvar){

i=ivar; f=fvar; d=dvar; }

// métodos SET para modificar las variables

void setl(int ivar){ i=ivar; }

void setF(float fvar){ f=fvar;

}

void setD(double dvar){ d=dvar; }

// métodos GET para extraer las variables

int getl(){

return i; }

float getF(){ return f;

}

double getD(){ return d;

} }

En el siguiente ejemplo creamos una clase de números complejos llamada i'omplejo, que

se ha añadido al final del fichero. Esta dase contiene dos variables a,b que almacenarán la

parte real e imaginaria, respectivamente. La ■ lase contiene cuatro métodos. Uno con el

mismo nombre de la dase, Complejo, Mué se llama constructor de la clase, que se ejecuta al

crear un objeto de la clase, ilonde se inicializan las variables. Los otros tres métodos extraen

la parte real, imaginaria y el módulo del número complejo representado por un objeto. En este

i'|omplo creamos dos números complejos y escribimos sus partes real e Imaginaria. El

resultado se ve en la figura A.16.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

Page 222: Android

*111 'Mi )||) PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVF H 01 I II MIMOS 201

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView); tv.

setText ("Clase de números Complejos1');

Complejo cl,c2,c3;

cl=new Complejo(1,1);

c2=new Complejo(2,3);

// partes real e imaginaria usando métodos

tv.append("\n\n cl="+cl.real()+"+i"+cl.imag());

tv.append("\n c2="+c2.real()+"+i"+c2.imag());

// partes real e imaginaria usando variables de clase

tv.append("\n\n cl="+cl.a+"+i"+cl.b); tv.append("\n

c2="+c2.a+"+i"+c2.b);

tv.append("\n\n modulo de el = "+cl.modulo());

tv.append("\n modulo de c2 = "+c2.modulo());

} )

class Complejo {

double a,b;

Complejo(double x,double y){

a=x; b=y ; }

double real (){ return a; }

double imag(){ return b? }

double modulo(){ return Math.sqrt(a*a+b*b);

}

}

üe 19:25 Ejempíojaval

Clase de números Complejos

c1=1.0+¡1.0 c2=2.0+¡3.0

c1=1.0+¡1.0 c2=2.0+¡3.0

modulo de c1 = 1.4142135623730951

modulo de c2 = 3.605551275463989

Page 223: Android

202 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII .I ü A TRAVÉS DE EJEMPLOS

Figura A.16. Uso de la clase de números complejos.

La instrucción para crear el número complejo 2+3i usando esta clase es:

Complejo c = new Complejo(2,3);

En el ejemplo vemos que podemos acceder a las variables o a los métodos de un objeto

utilizando el nombre del objeto seguido de un punto y el nombre de la variable, o el nombre

del método. Por ejemplo, la parte real del número anterior se puede extraer de estas dos

formas:

double r;

r=c.real() ?

r=c.a;

Page 224: Android

MKDNOID PROGRAMACIÓN DE DISPOSITIVOS MÓVII l:S A TRAVÉ8 1)1 I JtMPLOS 203

A.12. Sub-clases

I n Java se puede definir una subclase, que hereda las variables y métodos de la i lase

original, llamada su superclase. La subclase puede contener variables y métodos nuevos, o

puede redefinir o sobreescrlblr los métodos de su superclase. I ’¡ira declarar una subclase se

usa la estructura:

class Subclase extends Superclase{ }

Esta estructura de subclase es ya familiar para nosotros, puesto que la hemos nncontrado

en todos los ejemplos anteriores, al definir la clase EjemploJaval i orno una subclase de

la clase Activity. También hemos visto que en todos los ci|emplos se define el método

onCreate (), precedido por la etiqueta @Override. I '.to indica que estamos

redefiniendo, sobreescribiéndolo, el método con el mismo nombre de la superclase

Activity.

En el siguiente ejemplo definimos una subclase Complejo2 de la clase Complejo del

ejemplo anterior. Esta subclase define nuevos métodos para Mimar, multiplicar e invertir

números complejos. Las variables y métodos de la miperclase están definidos y se pueden

invocar dentro de la nueva clase usando "I prefijo this. La clase y la superclase están aquí en

el mismo fichero, pero podrían haberse puesto en ficheros java distintos, con el mismo

nombre que la i l.ise correspondiente.

public class EjemploJaval extends Activity {

©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Ejemplo de una subclase"); tv.append(

"\n La clase Complejo2 extiende la clase Complejo"+

" definiendo métodos para la suma y producto " +

" de números complejos");

Complejo2 el,c2,c3,cllnv,c2Inv; cl= new Complejo2(1,1);

c2= new Complejo2(2,3);

tv.append("\n cl="+cl.real()+" + i"+cl.imag());

tv.append("\n c2="+c2.real()+" + i"+c2.imag());

// suma cl+c2 c3=cl.sum(c2);

tv. append( "\n suma ="+c3 . real ()+" + i"+c5.iir\ag()) ;

// producto cl*c2 c3=cl.prod(c2); tv.append(

"\n producto = "+c3 . real ( ) + " + i"+-c3 . irnag () ) ;

// inverso l/cl

cllnv=cl.inv();

tv.append(

"\n l/cl ="+clInv.real()+" + i ( "+cllnv.imag( ) +" ) " )

; // inverso l/c2 c2Inv=c2.inv() ; tv.append(

"\n 1/c2 =" + c2Inv.real()+" + i("+c2Inv.imag()+")") ; //

Page 225: Android

204 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVI! I ’.A !HAVf:;DF I: JEMPLOfl

producto cl*l/cl c3=cl.prod(cllnv);

tv.append("\n cl/cl ="+c3.real ( )+" + i"+c3.imag()); //

producto c2*l/c2 c3=c2.prod(c2Inv);

tv.append("\n c2/c2 ="+c3.real()+" + i"+c3.imag()); }

}

class Compiejo2 extends Compiejo{

Complejo2(double x,double y){

super(x,y); }

Complejo2 sum(Compiejo2 c){

double cReal=this.real()+c.real ( ); double

clmag=this.imag()+c.imag();

Complejo2 result= new Compiejo2(cReal,clmag); return

result; }

Compiejo2 prod(Compiejo2 c){

double cReal=this.real()*c.real()-this.imag()*c.imag();

double clmag=this.real()*c.imag()+this.imag()*c.real();

Complejo2 result= new Complejo2(cReal,clmag); return

result; }

Complejo2 inv(){

double modulo=this.modulo();

double cReal=this.real()/(modulo*modulo);

double clmag=-this.imag()/(modulo*modulo);

Complejo2 result= new Complejo2(cReal,clmag); return

result; }

} class Complejo {

double a,b;

Complejo(double x,double y){

a=x;

b=y ; }

double real(){ return a; }

double imag(){ return b; }

double modulo(){ return Math.sqrt(a*a+b*b);

}

}

I I resultado se muestra en la figura A. 17. En este ejemplo vemos que el • nnstructor de la

subclase consiste en la línea super (x,y) , lo que indica que se 'f ute el constructor de la

Page 226: Android

ANUMnil): PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 205

superclase Complejo(x,y). La variable super hace Mninpre referencia a la superclase de

la clase actual. La misma fórmula se emplea ni ilofinir el método onCreate(), cuya primera

línea es super .onCreate () , para n|ii<¡Utar el método onCreateQ de la superclase

Activity.

de una subclase Complejo2

extiende la clase Complejo definiendo

métodos para la suma y producto de

números complejos c1=1.0 + Í1.0 c2=2.0

+ ¡3.0 suma =3.0 + ¡4.0 producto =-1.0 +

¡5.0 1/C1 =0.4999999999999999 + ¡(-

0.4999999999999999)

1/c2 =0.15384615384615385 + ¡(-

0.2307692307692308) c1/c1

=0.9999999999999998 + iO.O c2/c2 =1.0 +

1-5.551115123125783E-17

Figura A.17. Uso de una subclase de números complejos.

Page 227: Android

206 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIL! '• A IR/VVÉH DE EJEMPLOS

Obsérvese que en los tres métodos de ComplejoZ se usa la variable especial this,

para indicar el nombre del objeto asociado a la clase actual. Asi, this.real () sería la parte

real del presente objeto.

A.13. Variables y métodos estáticos y finales

Una clase puede contener variables estáticas, que deben ser declaradas como variables de

clase mediante:

static variable;

No se pueden definir dentro de un método. Estas variables pertenecen a la clase y no

requieren un objeto de la clase para usarlas, aunque un objeto puede modificarlas. Para

acceder a una variable estática se precede su nombre por el nombre de la clase, como

clase, variable. Por ejemplo, la variable Math.Pl de la clase de funciones

matemáticas es estática.

Una clase puede contener también métodos estáticos, que no requieren un objeto de la

clase para utilizarlos. Se emplean de la misma forma que las variables estáticas. Por ejemplo,

los métodos de la clase de funciones matemáticas Math, como Math. log(), son

estáticos.

Las variables finales son constantes que se inicializan cuando se declaran y no se pueden

modificar. Se suelen escribir con mayúsculas. Por ejemplo:

final double PI=3.1416;

Una variable final también puede declararse estática.

static final PI=3.1416;

La variable Math.Pl es estática y final.

Un método también puede declararse final. Se prohíbe entonces que el método pueda ser

modificado por una subclase. En cierto modo el método es constante, como las variables

finales.

En el siguiente ejemplo definimos una clase con tres variables y un método estáticos. Dos

de las variables son final y no pueden modificarse, pero la variable aa es incrementada

cada vez que se construye un objeto. Esta variable vale inicialmente cero (inicializada al

compilar) y puede ser referenciada antes de que exista ningún objeto de la clase. Al crear un

nuevo objeto, con new Aa () , la variable se incrementa en una unidad, y puede utilizarse

para contar el número de objetos de la clase que se han creado.@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv=(TextView) findViewByld(R.id.textView);

tv.setText("Variables y métodos final yjo static");

Page 228: Android

public class EjemploJaval extends Activity -{

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVES I >1 I II MPI OR 207

tv.append("\n static aa="+Abc.aa); tv.append("\n

static final BB="+Abc.BB); tv.append("\n static final

CC="+Abc.CC); double x=1.5;

tv.append("\n Función static f (x)="+Abc.f (x) ) ;

for (int i=l;i<10;i++){

Abe vl=new Abc(); vl.write(tv); }

tv.append("\n Fuera del bucle:");

Abe v2=new Abe(); v2.write(tv);

Abe v3 =v2; v3.write(tv); }

}

class Abc{

static int aa=0; static

final int BB=555; static

final int CC=777;

Abe(){ aa++;

}

void write(TextView tv){

tv.append("\n Variable static aa="+aa); }

static double f(double x){

return BB+CC*x;

} }

La salida de este programa se ve en la figura A.18. Obsérvese que el valor de In variable

estatica aa se incrementa cada vez que se crea un objeto nuevo en ei

bucle, pero no al asignar la última variable v3, puesto que no se crea ningíi» objeto nuevo,

sólo se asigna una referencia a un objeto que ya existe.

I : Í1«2Í1*¡

Variables y métodos final yfo static static aa=0

static final BB=5S5

static final CC=777

Función static f(x)=1720.5 Variable static aa=1

Variabie static aa=2

Variable static aa=3

Variable static aa=4

Variable static aa=5

Variable static aa=6

Variable static aa=7

Variable static aa=8

Variable static aa=9

Fuera del bucle:

Page 229: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 208

Variable static aa=10

Variable static aa=10

Figura A.18. Uso de variables y métodos static.

A.14. Arrays

Los arrays consisten en grupos de variables que se referencian con uno o varios índices

enteros. El tamaño del array, es decir, el número de objetos que contiene, debe especificarse

al crearlo. Un array es a su vez un objeto de una clase especial y debe crearse con la orden

new, seguida de la clase a la que pertenencen los objetos del array, especificando su

longitud entre corchetes. Por ejemplo, para declarar un array conteniendo 3 números enteros

usamos:

int [] a;

a = new int [3] ;

Equivalentemente, se puede declarar un array escribiendo los corchetes tras el nombre de

la variable. Por ejemplo:

int a [] ;

El array anterior contiene tres variables enteras denotadas a [ o ] , a [ i ] , a [2]. Los

contenidos del array se denotan poniendo entre corchetes una variable entera, que cuenta el

número de orden de cada elemento, a [i]. Pero hay que tener siempre en cuenta que se

empieza a contar en cero. Es decir el primer elemento de

Page 230: Android

ANIIKOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I.S A IUAVÍ M>l I II MPLOS 209

mi array es el número cero, y si el array tiene dimensión «, su ultimo elemento es el n l. Un

array es un objeto y length es la variable de clase donde se almacena su longitud. Por

tanto, la longitud del array anterior se puede obtener mediante A . Length.

Los contenidos de un array se inicializan automáticamente a cero si son numéricos.

También podemos inicializar un array igualándolo a un bloque de vnlores separados por

comas, como:

int[] a = (l,2,3,4,5};

En el siguiente ejemplo ilustramos el uso de los arrays en un programa Java. Definimos un

array entero, un array double, y una función cuyo argumento es un i ni ay. El resultado se ve

en la figura A. 19.

public class EjemploJaval extends Activity {

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv= (TextView) findViewByld(R.id.textView);

tv.setText("Ejemplos de arrays");

// definición de un array de longitud 3 int[] miArray;

miArray=new int[3];

// obtención de la longitud del array int

longitud=miArray.length;

tv.append("\n Longitud del array= "+longitud);

// escribimos los valores iniciales del array (cero) for

(int i=0;i<3;i++){

tv.append("\n i="+i+", miArray[i]="+miArray[i]);

miArray[i]=l + i*i ;

tv.append("\n Valor después ="+miArray[i]); }

// inicializacion de un array doublet]

miArray2={0,1,2,3}; tv. append (" \n miArray2 =11) ; for

(int i=0;i<miArray2.length;i++){ tv.append(" "+i+" , "); }

double total=suma(miArray2); tv.append("\n

suma="+total);

}

// suma los elementos de un array

double suma(double[] a){ double s

= 0;

int nsumandos=a.length;

for(ínt i=0;icnsumandos;i++){

s= s+a [i] ; }

Page 231: Android

210 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I '■ A IF(A7I-H DE EJEMPLOS

return s;

}

}

[ ' BSesüi Ejemplojaval

Ejemplos de arrays

Longitud del array= 3

¡=0, m¡Array[i]=0 Valor

después =1 i=1,

miArray[i]=0 Valor

después =2 i=2,

m¡Array[¡]=0 Valor

después =5 m¡Array2= 0,

1 , 2, 3 , suma=6.0

Figura A. 19. Uso de arrays.

A.15. Arrays 2D

Un array de dos dimensiones (2D) es un array de arrays. Se especifica con dos índices

entre corchetes. El primero indica la fila y el segundo la columna. Por ejemplo un array de

enteros con dos filas y tres columnas se declara de la siguiente forma:

int [] [] a; a=

new int[2][3];

y sus elementos son variables enteras denotadas a [i] [j] , donde i=CJ y j=0, l , 2 .

También se puede definir cada fila separadamente como un array de una dimensión. Por

ejemplo, en las siguientes líneas primero declaramos un array 2D que tiene dos filas. A

continuación, se declara que cada fila es a su vez un array con tres elementos:

int [] [] a = new int [2]

[] ; a[0]=new int[3];

a[1]=new int[3];

Esto permite construir arrays con número de columnas variable. Por ejemplo, la primera

fila podría contener dos elementos y la segunda cuatro, de la siguiente forma:

Page 232: Android

ANKROID PROGRAMACIÓN DE DISPOSITIVOS MÓVII I S A IHAVI’ü HI I .II Ml 1 Oí; 2 1 1

int[] [] a = new int [2] []

; a[0]=new int[2]; a[1]=new

int[4] ;

El siguiente programa Android es una demostración del uso de arrays 2D en Java, con

número de columnas fijo y variable. El resultado se puede ver en la llgura A.20.

a SB« 7:34

Ejemplojaval

Ejemplos de arrays miArray

filas = 3, Columnas= 2 fila: 0,1, fila: 10,11,

fila: 20,21,

miArray2:

Filas= 2 , Columnas = 3 fila: 1.0, 2.0, 3.0,

fila: 4.0, 5.0, 6.0,

miArray3:

Fila: 0.0,

Fila: 10.0,11.0,

Fila: 20.0,21.0,22.0,

miArray4:

Fila: 1.0, 2.0,

Fila: 3.0, 4.0 , 5.0,

Fila: 6.0,

Fila: 7.0, 8.0, 9.0, 0.0,

Figura A. 20. Uso de arrays 2D.(©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main);

TextView tv= (TextView) fíndViewByld(R.id.textView);

tv.setText("Ejemplos de arrays");

// definición de un array bidimensional int [] []

miArray; miArray=new int[3][2];

// obtención de la longitud del array

int filas=miArray.length;

int columnas=miArray[0].length;

tv.append("\n miArray \n filas = "+filas);

tv.append(", Columnas= "+columnas);

// inicializamos el array for (int i=0;i<filas;i++){

for (int j=0;j<columnas;j++){ miArray[i] [j]=10*i+j; }

}

// escribe el contenido del array for (int

i=0;i<filas;i++){ tv.append("\n fila: "); for (int

j=0;jccolumnas;j++){

tv.append(" "+miArray[i] [j ]+","); }

Page 233: Android

ic class EjemploJaval extends Activity {

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII ü A IHAVÉS DE EJEMPLOS

}

// definimos e incializamos un array

double miArray2[][]={ {1,2,3}, {4,5,6}};

filas=miArray2.length;

columnas=miArray2[0].length;

tv.append("\n\n miArray2:");

tv.append("\n Filas= "+filas);

tv.append(" , Columnas = "+columnas);

// escribe el contenido del array

for (int i=0;i<filas;i++){ tv.append("\n fila: "); for

(int j=0;j<columnas;j++){

tv.append(" "+miArray2[i][j]+","); }}

// array con columnas variables

double miArray3 [] [] =new double [3]

[] ;

miArray3[0]=new double [1]

; miArray3[1]=new

double[2]; miArray3[2]=new

double[3];

miArray3[0] [0]=0;

miArray3[1]

[0]=10; miArray3

[1] [ 1]=11;

miArray3[2]

[0]=20; miArray3

[2] [1]=21;

miArray3 [2]

[2]=22;

tv.append("\n\n miArray3:"); for (int

i=0;i<3;i++){ tv.append("\n Fila: ");

for(int j=0;j<=i;j++){

tv.append(""+miArray3[i] [j]+" , "); }

}

doublet] [] miArray4= { { 1, 2 } , {3 , 4 , 5 } , { 6

} , {7 , 8 , 9 , 0 } }; tv.append("\n\n miArray4: ");

filas=miArray4.length; for (int i=0;i<filas;i++){

columnas=miArray4[i].length;

tv.append("\n Fila:");

Page 234: Android

cadena = "esto es una cadena";

214 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII ISA IHAVÉK Dfc EJEMPLOS

for(int j = 0;j <columnas;j + +){

tv.append(" "+miArray4[i] [j]+" , "); }

A 16. Cadenas

i i clase string está definida en el paquete java, lang y representa cadenas iln

caracteres. Una cadena o String es un objeto de esta clase. Una String literal «•'i un texto

rodeado por comillas dobles. Para crear un objeto string se puede ir..ir el constructor de

la clase o usar una cadena literal, por ejemplo:

String cadena; cadena = new String("esto es una cadena");

Para transformar a string una variable numérica, booleana o carácter, se usa el método

estático valueOfO.

double x=1.245;

String cadena= String.valueOf (x) ;

Para concatenar cadenas se usa el operador " + ".

String cadenal= "esto es ";

String cadena2= "una cadena";

String cadena3= cadenal+cadena2;

El operador “+” también realiza la conversión a cadenas de otros tipos de datos.

double x=1.256;

String cadenal= "x="+x;

Este hecho lo hemos utilizado repetidamente en todos los ejemplos anteriores, pues el

argumento de append () es una string.

Java incluye numerosos métodos para manipular cadenas incluyendo:

• length () . La longitud de una cadena cadenal se extrae mediante cadenal.length().

• substring (int ini, int fin). Método para extraer una subcadena. Se

especifica la posición del primer caracter incluido y del primer caracter no incluido.

La posición del primer caracter tiene el índice cero.

• toüpperCase () y toLowerCase3() . Conversión a mayúsculas y a minúsculas.

3 replace(char a, char b) . Reemplaza el primer caracter por el

segundo.

• trim () . Elimina espacios en blanco al principio y al final.

Page 235: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILtS A IHAVI' -DI I .11 MI'IOS 215

• compareTo (string cadena) . Compara con otra cadena y devuelve un entero

negativo si la primera es menor que la segunda, y positivo si ocurre lo contrario. Si

son iguales devuelve cero.

• indexof (string cadena) . Devuelve la posición de la primera

ocurrencia de una subcadena.

El uso de estos métodos se ¡lustra en el siguiente programa. La salida se puede ver en

la figura A.21.

public class EjemploJaval extends Activity {

TextView tv; @Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

findViewById(R.id.textView);

String cadenal="Cadenas de caracteres";

tv.setText(cadenal);

// constructor

String cadena2=new String("\n Constructor de

cadenas"); tv.append(cadena2);

// Concatenación cadenal="\n Concatenación"; cadena2="

de cadenas \n";

String cadena3=cadenal+cadena2; tv.append(cadena3);

// Transformación a cadena con valueOfO

double x=3.1416e-3;

cadena2 = String.valueOf(x);

tv.append("Transformación de double a cadena\n");

tv.append(cadena2);

// conversion de String a double cadenal="3.1416e-3";

x = Double.parseDouble(cadenal); x= x*2;

tv.append("\n Conversion de string a double\n "+x);

// conversion de String a int cadenal="1234";

int i= Integer.parselnt(cadenal); i=i*2;

tv.append("\n Conversion de string a int\n "+i);

// longitud de una cadena

cadenal="Granada";

int longitud= cadenal.length();

tv.append("\n La longitud de Granada es "+longitud);

longitud="Nueva York".length();

• toCharArray () . Extrae los caracteres de una cadena en un array.

Page 236: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A rUAVÍ S DF EJEMPLOS

tv.append( "\n La longitud de Nueva York es "+■longitud);

// conversion a mayúsculas y minúsculas

cadenal="Conversion a mayúsculas";

cadenal=cadenal.toUpperCase();

tv.append("\n"+cadenal); cadenal="CONVERSION A

MINUSCULAS"; cadenal=cadenal.toLowerCase();

tv.append("\n"+cadenal);

// subcadenas. Indices comienzan en cero

cadenal="Extrayendo subcadenas";

// desde el principio hasta el caracter décimo

cadena2=cadenal.substring(0,10);

// desde el 11 hasta el final

cadena3=cadenal.substring(11);

tv.append("\n"+cadena2); tv.append("\n"+cadena3);

// comparación de cadenas cadenal="Granada";

cadena2="Albacete"; i=cadenal.compareTo(cadena2); if

( i<1){

tv.append("\n"+cadenal+" antes que "+cadena2); } else {

tv.append("\n"+cadenal+" despues que "+cadena2); }

// búsqueda de subcadenas cadenal="Granada";

i=cadenal.indexOf("da");

tv.append("\n Granada contiene da en la posicion "+i);

// reemplazar caracteres cadenal="Granada";

cadena2=cadenal.replace('a 1, 'u') ; tv.append(

"\n Reemplazando las aes por ues: "+cadena2);

//elimina espacios en blanco cadenal=

" trim elimina blancos al inicio y fin "

cadenal=cadenal.trim(); tv.append("\n*"+cadenal+"*");

// extracción de los caracteres

cadenal="Granada";

char[] letras=cadenal.toCharArray();

tv.append("\n Separando los caracteres:Vn"); for

(int j=0;j<letras.length;j++){ tv.append(" +

"+letras[j]); }

}

lili © 11:02 I Ejemplojaval

Cadenas de caracteres Constructor de

cadenas Concatenación de cadenas

Transformación de double a cadena

Page 237: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 218

0.0031416

Conversión de string a double 0.0062832

Conversión de string a int 2468

La longitud de Granada es 7 La longitud de

Nueva York es 10 CONVERSION A

MAYUSCULAS conversión a minúsculas

Extrayendo subcadenas

Granada despues que Albacete Granada

contiene da en la posicion 5

Reemplazando las aes por ues: Grunudu

*trim elimina blancos al inicio y fin*

Separando los caracteres:

+ G + r + a + n + a + d + a

Figura A.21. Manipulación de cadenas.

A 11. Formato numérico

posee una completa librería para manipular cadenas. En esta sección mlioduclmos la

clase DecimalFormat para dar formato a números decimales, Imii-.formándolos en

cadenas. Esta clase es de utilidad para mostrar números en l'iinl.illii con una estructura de

cifras determinada, o para escribirlos en un fichero. I'ni.i nllo, primero se construye un objeto

de tipo DecimalFormat

Hi’oimalFormat df = new DecimalFormat (patrón)

donde patrón es una cadena indicando el número de cifras deseado, o formato. Luego

se emplea el método format () para transformar un número en una cadena con dicho

formato. Por ejemplo:

double x=l. 234 5; String cadena = df.format<x);

El número se redondea hacia arriba. Las principales reglas para especificar el patrón son

las siguientes:

• Un punto indica la posición del punto decimal.

• El símbolo o indica un dígito o un cero sí no hay ningún dígito en esa posición. Por

ejemplo, el patrón "0 0 .0 0 0" Indica números con tres decimales y con dos cifras como

mínimo a la izquierda del punto decimal, por ejemplo, 12 .345, 01.234,

12.340, 123.450.

• El símbolo # indica un dígito. Si no hay ningún dígito en esa posición, no escribe nada.

Por ejemplo, el patrón "##.###" produce números con el formato 12 .345, 1.23, 123.45.

• El símbolo E seguido de ceros se utiliza para notación científica e indica una potencia

de 10. Por ejemplo, el patrón "0.00E00" produciría los números 1.23E03, 0.12E10, 1.20E-01.

Page 238: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 219

• Una coma indica agrupación de cifras con un separador, Por ejemplo, el patrón ",

000" agrupa por miles, como en 12, 000 .

• Con un punto y coma se puede especificar un símbolo alternativo al signo menos de

los números negativos, en lugar de un guión.

Por defecto se utiliza la notación “local” que generalmente consiste en que el punto

decimal es una coma y el separador de cifras es un punto. Para modificar el separador es

necesario especificar un objeto DecimalFormatSymbols, que define los separadores, al

definir el formato. Por ejemplo, para que el punto decimal se escriba siempre con un punto:

DecimalFormatSymbols symbols= new

DecimalFormatSymbols(Lócale.US);

symbols.setDecimalSeparator('.');

df= new DecimalFormat(".###",symbols);

El objeto symbols lleva los símbolos locales de Estados Unidos, pero hemos modificado

su separador decimal con setDecimalSeparator () .

En el siguiente programa mostramos varios ejemplos de formato. El resultado se puede

ver en la figura A.22.

Page 239: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl i S A IHAVI Mil IJL MPl O!; 2

import j ava . text. DecimalFormat ; import

java.text.DecimalFormatSymbols; import

java.util.Locale;

import android.app.Activity; import

android.os.Bundle; import

android.widget.TextView;

public class EjemploJaval extends Activity {

TextView tv;

(©Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

findViewByld(R.id.textView);

tv.setText("DecimalFormat");

double x,y,z;

x=12345.6789;

tv.append("\n Sin formato x="+x) ;

DecimalFormat dfl;

dfl= new DecimalFormat(".#");

tv.append("\n Una cifra decimal: "+df1.format(x)); dfl=

new DecimalFormat(".##");

tv.append("\n Dos cifras decimales: "+df1.format(x)) dfl=

new DecimalFormat(".###"); tv.append(

"\n Tres cifras decimales: "+df1.format(x)); dfl=

new DecimalFormat(",###.##");

tv.append("\n Agrupar por miles: "+dfl.format(x));

DecimalFormatSymbols symbols =

new DecimalFormatSymbols(Locale.US);

symbols.setDecimalSeparator('.'); dfl= new

DecimalFormat(".###",symbols); tv.append("\n\n Punto

decimal = +dfl.format(x));

y = 1.234;

Z=-1.234; tv.append(

"\n\n Rellenar con ceros a derecha e izguierda:");

tv.append("\n sin formato y="+y); tv.append("\n sin

formato z=" + z) ;

/ / E l ; permite definir el simbolo del signo menos dfl=

new DecimalFormat("00.0000;menos",symbols);

Page 240: Android
Page 241: Android

220 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII 1 \ I HAVf S DI f ,11 MPLOS

tv.append(" \n "+df1 . format < y ) ) ; tv .append(" \n

"+df1 . for mat(z));

tv . append (" \n\n Notación ci ent í f ica 1 ' ) ;

df l= new Deci malFor mat ("OEO",sy mbol s) ;

tv .append(" \n "+df1 . format(y) ) ;

df l= new Deci malFor mat ("0 .OEO0",sy mbols ) ;

tv .append(" \n "+df1 . format(y) ) ;

df l= new Deci malFor mat ("00 .OOft#EOO", sy mbol s) ;

tv .append(" \n "+df1 . f ormat(y) ) ;

df l= new Deci malFor mat (" .00E0",sy mbol s) ;

tv .append(" \n "+df1 . format(y) ) ; }

}

a ill« 20:34

Ejemplojaval

DecimalFormat Sin formato x=12345.6789 Una cifra decimal: 12345,7 Dos cifras decimales: 12345,68 Tres cifras decimales: 12345,679 Agrupar por miles: 12.345,68

Punto decimal = .12345.679

Rellenar con ceros a derecha e izquierda: sin formato y=1.234 sin formato z=-1.234 01.2340 menosOI .2340

Notación científica 1E0 1.2E00 12.34E-01 .12E1

Figura A.22. Uso de la clase DecimalFormat para dar formato a los números.

A.18. Manejo de Excepciones

Cuando en la ejecución de un programa se produce un error, ésta se detiene. Cada error

suele producir un mensaje o excepción, que permite determinar el problema. Con el manejo

de excepciones podemos evitar errores y que el programa siga ejecutándose. Para manejar

una excepción se usa un bloque try- catch. El código donde se puede producir un error debe

estar en el bloque try. Si el error se produce, se lanza una excepción y se ejecuta el código del

bloque catch, que es el que recoge la excepción. Opcionalmente se puede incluir un bloque

finally, que se ejecuta en todo caso, se produzca la excepción o nc.

try {

// codigo que arroja la excepción }

catch (Exception e){

Page 242: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I -A IHAYf-MH I II MI *1 OS 221

// codigo que recoge la excepción }

finally {

// codigo que se ejecuta siempre }

La instrucción catch requiere un parámetro e, que es un objeto de tipo Exception

o una de sus subclases, que lleva la información del tipo de error producido. En el siguiente

programa demostramos el manejo de excepciones forzando dos errores típicos: Intentar

acceder a índices de un array que no existen, lo que arroja una excepción del tipo

ArraylndexOutOfBoundException, y acceder a Indices de una cadena que tampoco existen, lo

que arroja una excepción de tipo StringlndexOutOfBoundException. El tipo de excepción

recogido se escribe en pantalla, ver figura A.23.

public class EjemploJaval extends Activity {

TextView tv; @Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

findViewByld(R.id.textview);

tv.setText("Excepciones\n");

d ou bl e t ] v = ne w do u b l e [ 1 0 ] ; double

x=-1;

try {

X=V [ 1 0 ] ;

} catch(Exception e){

tv.append("\n\n Excepción encontrada: "+e);

tv.append(

"\n\n Se ha intentado acceder al indice 10 "

+"del array v[10]");

} finally{

tv.append("\n x="+x); }

String

cadena="abcdefg";

try {

tv.append("\n"+cadena.substring(15,20));

} catch(Exception e){

tv. append ("\n\n Excepción encontrada: "+-e);

tv.append("\n\n Se ha intentado acceder " + "a la posicion

15 de "+cadena) }

} }

Page 243: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 222

Ejemplojavdl

Excepciones

Excepción encontrada: java.lang.

ArraylndexOutOfBoundsException

Se ha intentado acceder al índice 10

delarray v[10] x=-1.0

Excepción encontrada: java.lang.

StringlndexOutOfBoundsException

Se ha intentado acceder a la posicion

15 de abcdefg

Figura A.23. Uso de bloques try-catch para recoger excepciones.

Finalmente, indiquemos que un método puede arrojar una excepción y ésta ser

declarada mediante la etiqueta throws, por ejemplo:

public método throws Excepción {

throw e; }

Page 244: Android

ANHHi lili PROGRAMACIÓN OF DISPOSITIVOS MÓVII I S A TRAVÉS DE EJEMPLOS 223

En el caso en que se produzca la excepción, el método debe arrojarla mediante la instrucción

throw e.

A. 19. Interfaces

En Java un método no puede ser el argumento de otro método. Por ejemplo, si escribimos un

método para calcular el mínimo de una función F(x), el nombre de la función debe conocerse

de antemano. Si queremos minimizar varias funciones distintas, esto podría ser un problema.

Las interfaces resuelven este problema, definiendo métodos vados, que se pueden

implementar posteriormente por distintas clases. Así una clase podría contener la función a

minimizar y podríamos pasarle un objeto de esa clase al método minimizador. Una interfaz se

define similarmente a una clase, sólo que sus métodos sólo están declarados, es decir, no

están implementados. Por lo tanto, las interfaces no son clases y, por tanto, no se pueden

instanciar objetos de una interfaz, sino de una clase que implemente la interfaz.

Por ejemplo, para definir una interfaz que lleva una función, escribiríamos:

interface Funcion{ double f(double x);

}

Aquí, la función f (x) está declarada, pero no está implementada. Una clase i|iie

implementa esta interfaz podría ser la siguiente:

class Funcionl implements Funcion{ public double f(double x){

return l+x+2*x*x;

}

y un método que utiliza la interfaz sería:

double evalúa(double x, Función portador){ double

valor=portador.f(x); return valor;

Nótese que aquí el argumento no es un objeto de la clase Función, sino de uiiii clase que

implemente dicha interfaz.

I I siguiente ejemplo es un programa completo donde se implementa la interfaz nnlmlor tres

veces, con tres funciones distintas, que se evalúan en un punto y se iiuiit'ilra el resultado (ver

figura A.24).TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

findViewByld(R.id.textView); tv.setText("Ejemplo de

interfaz " +

"\n\n Se implementan tres funciones distintas");

Page 245: Android

public class EjemploJaval extends Activity {

224 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILI S A TRAVÉ.H DE EJEMPLOS

double a=0.5;

class Funcionl implements Funcion{ public double

f(double x){ return l+x+2*x*x; }

}

Funcionl miFI = new Funcionl();

double valor=evalua(a, miFl);

tv.append("\n\n Valor de miFl = "+ valor);

class Funcion2 implements Funcion{ public double

f(double x){ return l/(l+2*x*x); }

}

Funcion2 miF2 = new Funcion2(); valor=evalua(a,

miF2);

tv.append("\n\n Valor de miF2 = "+ valor);

class Funcion3 implements Funcion{ public double

f(double x){ return Math.atan(x); }

}

Funcion3 miF3 = new Funcion3(); valor=evalua(a,

miF3);

tv.append("\n\n Valor de miF3 = "+ valor); }

// método para evaluar una función // proporcionada en

la interfaz Función

Page 246: Android

IKOUNAMACIÓN DE DISPOSITIVOS MÔVILI S A FRAVÉS DE I Jl ME’LO:. 225

double évalua(double x, Función portador){

double valor=portador.f(x); return valor; }

// interfaz que lleva una función

interface Funcion{

double f(double x); }

mm*» 7-.30 Ejempiojava! Ejemplo de interfaz

Se ¡mplementan tres funciones distintas

Valor de miF1 = 2.0

Valor de miF2 = 0.6666666666666666

Valor de miF3 = 0.4636476090008061

i i\itim A.24. Uso de una interfaz para evaluar distintas funciones en un método.

< >lm ejemplo del uso de interfaces es el siguiente. Trabajando con arrays 2D o villi' ' s

encontramos a menudo bloques comunes del tipo:

I n.i (int i = 0 ; i<miArray. length; i + +) {

Toi' (int j = 0 ; j <miArray [i] . length; j + + ) {

// instrucciones

}

I I bloque común del doble bucle podría pasarse a un método "M "ArrayO , cuyo

argumento serían las instrucciones a realizar. Esto puede

hacerse con una interfaz con un método -manipula, como en el siguiente programa. La

interfaz, Manipulador, está ¡mplementada por dos clases y los objetos de esas clases

se pasan al método recorreArray () que contiene el bucle El resultado se ve en la

figura A.25.

Page 247: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 226

S Si® 11:29 Ejemplojaval

Ejemplo de

interfaz a(0,0) =

0.0 a(0,1)= 1.0

a(0,2) = 2.0 a(1,0)

= 10.0 a(1,1)= 11.0

a(1,2)= 12.0 a(2,0)

= 20.0 a(2,1)= 21.0

a(2,2) = 22.0

a(3,0) = 30.0

a(3,1) = 31.0

a(3,2) = 32.0

Figura A.25. Uso de una interfaz para manipular matrices.

public class EjemploJaval extends Activity {

TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

findViewByld(R.id.textView);

tv.setText("Ejemplo de interfaz");

// array bidimensional doublet] []

miArray; miArray=new double[4][3];

class Manil implements Manipulador{

public void manipula(double[][] a,int i, int j){

a[i] [j]=10*i + j ; }

}

Manil ml= new Manilf)■

recorreArray(miArray,ml);

class Mani2 implements Manipulador{

public void manipula(double[][] a,int i, int j) tv.append("\n

a(" + i+","+j + ") = "+a[i][j]>; }

}

Mani2 m2= new Mani2();

Page 248: Android

Mil lUOID PROGRAMACIÓN DE DISPOSITIVOS MÓVIII SA IHAVf'DI I II MPIO!. 227

recorreArray(miArray,m2);

}

// método para realizar acciones sobre un array //

usando la interfaz Manipulador

void recorreArray(double[][] miArray, Manipulador m){

for (int i=0;icmiArray.length;i++){

for(int j=0;jcmiArray[i].length;j++){

m.manipula(miArray,i,j);

}

}

}

// interfaz para manipular un array

interface Manipulador{

void manipula(double[][] a,int i,int j }

Las clases internas Manil y Mani2 que implementan la interfaz Manipulador son

ejemplos de clases locales, que sólo son visibles dentro de un Moque de código. En este

caso, sólo se necesita instanciar un objeto de estas i l.ises, por lo que esta implementación se

podría haber hecho utilizando clases .inónimas, tratadas en la siguiente sección.

A. 20. Clases anónimas

( liando sólo se necesita un objeto de la clase, por ejemplo para implementar una lulurfaz, no

es realmente necesario definir una clase completa. Se puede utilizar mui clase anónima, es

decir, que no tiene nombre, instancíando directamente un i >1 >|oto de la clase. Por ejemplo:

Interfaz inter= new Interfaz(){ // implementación

Nótese que aquí no se está creando un objeto de la clase interfaz r porque las

interfaces no son clases, sino que se está creando un objeto de una clase anónima que no

tiene nombre y que ¡mplementa la interfaz.

En el siguiente programa implementamos la interfaz Función de la sección anterior

usando clases anónimas, el resultado es exactamente el mismo de la figura A.24.

public class Ejemp1oJaval extends Activity {

TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

Page 249: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 228

findViewByld(R.id.textView); tv.setText("Ejemplo

de interfaz " +

"\n\n Se implementan tres funciones distintas");

double a=0.5;

Función miFl= new FuncionO { public double

f(double x){ return l+x+2*x*x; }

};

double valor=evalua(a, miFl); tv.append("\n\n Valor de miFl = "+ valor);

Función miF2 = new FuncionO { public double

f(double x){ return l/(l+2*x*x); }

} ;

valor=evalua(a, miF2);

tv.append("\n\n Valor de miF2 = "+ valor);

Función miF3 = new FuncionO { public double

f(double x){ return Math.atan(x); }

};

Page 250: Android
Page 251: Android

ANDROID PROGRAMACIÓN DE DISPOSITIVOS MÓVII I NA IIIAVI-'. 1)1 I II MI 'I 08

valor=evalua (a, miF3 > tv.append("\n\n Valor de miF3 = "+ valor);

}

// método para evaluar una función //

proporcionada en la interfaz Función double

evalúa(double x, Función portador){ double

valor=portador.f(x); return valor; }

}

// interfaz que lleva una función

interface Funcion{

double f(double x); }

Como descubrimos al examinar este ejemplo, en realidad tampoco es necesario darle

nombre a los objetos miFl, miF2, miF3 de la clase anónima <|ue ¡mplementa la interfaz

Función, sino que bastaría incluir su definición directamente como argumento del método

evalúa (), es decir:

double valor=evalua(a, new Funcion(){

public double f(double x){ return

l+x+2*x*x; }

}>;

Obtenemos, entonces, la siguiente versión equivalente del mismo programa que ilustra las

posibilidades que ofrece el lenguaje Java para definir un método, (ientro del argumento de

otro método.

public class EjemploJaval extends Activity {

TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main); tv= (TextView)

findViewByld(R.id.textView); tv.setText("Ejemplo

de interfaz " +

"\n\n Se implementan tres funciones distintas");

double a=0.5;

double valor=evalua (a, new FuncionO { public

double f(double x){}

}>;

tv.append("\n\n Valor de miFl = "+ valor);

valor=evalua (a, new FuncionO { publ i c double

f (double x ){ return 1 / ( l+2*x*x );

Page 252: Android

ublic class EjemploJaval extends Activity {

I III I I'M XIHAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DI t JI-MPLOS 231

} }>;

tv.append("\n\n Valor de miF2 = "+ valor);

valor=evalua (a, new FuncionO { public

double f(double x){ return Math.atan(x); }

});

tv.append("\n\n Valor de miF3 = "+ valor); }

// método para evaluar una función //

proporcionada en la interfaz Función double

evalúa(double x, Función portador){ double

valor=portador.f(x); return valor; }

}

// interfaz que lleva una función

interface Funcion{

double f(double x); }

Aunque esta notación es compacta y es utilizada por muchos programadores,

implementar una interfaz con una clase anónima dentro del argumento de un método puede

resultar confuso para el principiante, pues el código resulta más difícil de entender. Sólo con

la práctica se llega a dominar esta técnica. Para comenzar se aconseja implementar

explícitamente las interfaces con clases no anónimas. La utilidad de la clase anónima

surgirá por sí sola.

Para terminar esta discusión, el siguiente ejemplo muestra la versión del programa de la

figura A.25 implementado con clases anónimas.

TextView tv;

@Override

public void onCreate(Bundle savedlnstanceState) {

super.onCreate(savedlnstanceState);

setContentView(R.layout.main)? tv= (TextView)

findViewByld(R.id.textView);

tv.setText("Ejemplo de interfaz");

// array bidimensional doublet] [] miArray;

miArray=new double[4][3];

// Llamada al método con segundo argumento un objeto

Page 253: Android

232 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I '• A TRAVÉS DE EJEMPLO!)

/ / d e una clase anonima implementando una interfaz

recorreArray(miArray,new Manipulador(){

public void manipula(double[][] a, int i, int j) {

a[i] [j]=10*i +j ; }

}>;

recorreArray(miArray,new Manipulador(){ public void

manipula(double[][] a,int i, int j){ tv.append("\n

a("+i+","+j+") = "+a[i][j]); }

}>;

}

// método para realizar acciones sobre un array //

usando la interfaz Manipulador vi ild

recorreArray(double[] [] miArray, Manipulador m){

I or (int i = 0;i<miArray.length;i++){

for(int j=0;jcmiArray[i].length;j++){

m.manipula(miArray,i,j); }

// Interfaz para manipular un array

Inl i’il.ice Manipulador!

void manipula(double[][] a,int i,int j);

A. 21. Otras características de Java

A. 21.1. Paquetes

En Java las clases se agrupan en paquetes, especificados en la primera línea del fichero:

package es.ugr.amaro;

Esto indica que el fichero .class, obtenido al compilar el fichero .java, está localizado en

el subdirectorio es/ugr/amaro. Todas las clases del mismo paquete están en el mismo

directorio. Para evitar problemas, se aconseja utilizar nombres únicos para los paquetes,

como un nombre de dominio o de correo electrónico. Para que una clase pueda utilizar otra

clase definida en otro paquete se debe especificar ésta con la orden import al principio del

fichero. Por ejemplo, para usar la clase EjemploJaval del paquete es.ugr.amaro,

escribiríamos:

import es.ugr.amaro.Ej emploJaval;

Se pueden importar todas las clase de un paquete escribiendo un asterisco:

Page 254: Android

ublic class EjemploJaval extends Activity {

I III I I'M XIHAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DI t JI-MPLOS 233

import es.ugr.amaro.4

A. 21.2. Clases públicas

Por defecto, las clases son privadas y sólo son accesibles a las otras clases de su mismo

paquete. Si queremos que una clase sea pública y pueda ser importada por clases en otros

paquetes, debemos declararla como public. Por ejemplo:

public class EjemploJaval{

i”

A. 21.3. Privilegios de acceso de los métodos y variables

Aunque una clase sea pública, sus métodos y variables tienen su propio tipo de acceso,

que puede ser de cuatro tipos: public, protected, private, o el tipo por

defecto, si no se especifica nada. La diferencia está en el tipo de clases que pueden

acceder a ellos.

4 public: es el tipo menos restrictivo, permitiendo acceso a todas las

clases. Es decir, si un método es public, puede invocarse desde cualquier clase

de cualquier paquete.

Page 255: Android

lili l'ln ii IUAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS I >1 I II MPLOS 234

• protected: no permite el acceso a las clases de otro paquete, a no ser que

sean sub-clases de la clase que contiene el método o variable,

• tipo por defecto: si no se especifica nada, no permite el acceso a las clases de otro

paquete. Dicho de otro modo, los métodos no pueden ser ejecutados por clases de

otro paquete. Si queremos que lo sean, deben ser declarados públicos.

• private: es el tipo más rectictivo. No es accesible ni siquiera a las clases del

mismo paquete. Sólo lo puede ejecutar la clase que lo contiene.

A i i 4. Clases y métodos abstractos

Him dase abstracta se declara precediéndola del comando abstract. Las clases

N I I ' I I I . iotas son similares a las interfaces, conteniendo lo que se denomina métodos

Nli’ilisetos, precedidos también de la palabra abstract, y que sólo están • !••• i.ii.«dos,

pero no implementados. Las clases abstractas se diferencian de las mi.'il,nos en que

también pueden contener métodos concretos, es decir, llii|ili'iiiüntados. No se puede crear

un objeto de una clase abstracta, sino sólo de miii 'In sus subclases que ¡triplemente todos

sus métodos abstractos.

HERRAMIENTAS DE DESARROLLO DE ANDROID

B. 1. Eclipse

Eclipse es un entorno de desarrollo interactivo (IDE) recomendado para comenzar con

Android y Java. Lo hemos utilizado para escribir todos los ejemplos de este libro.

B. 1.1. Problemas en la instalación

La instalación de Eclipse es tan sencilla como descargar y descomprimir, tanto en Windows

como en Linux. Eclipse se iniciará normalmente si tenemos instalada la versión

recomendada de Java JDK. Aún asi siempre pueden surgir problemas, sobre todo en Linux

debido a la gran variedad de distribuciones existentes. Algunos de los problemas que

pueden surgir están documentados en el fichero README distribuido con Eclipse.

Documentaremos aquí un problema adicional que puede surgir en la instalación y que

no se menciona en la distribución de Eclipse.

Por ejemplo, es posible que Eclipse no arranque en Linux, aunque tengamos instalada

la última versión de Java JDK, debido a que en nuestro ordenador haya instaladas otras

máquinas virtuales de Java además de la oficial de Sun. Hemos encontrado este problema

en una distribución de Ubuntu, que tenía Instalada una versión libre de la maquina virtual.

La solución fue desinstalar todo el software de Java que no fuera el oficial de Sun.

B. 1.2. Importar una clase Java de otro proyecto

Supongamos que queremos utilizar en un proyecto proyectol una clase de Java utilizada en

Page 256: Android

ANI)ROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I !i A IRAVÉ S DE EJEMPLOS 235

otro proyecto proyecto2 de Eclipse. Los pasos a seguir son los siguientes.

• Pulsar con el botón derecho en src/nombre_del_paquete y seleccionar Import... Se

abrirá la ventana select.

• Seleccionar General - File System y pulsar Next. Se abrirá la ventana File System.

• Ir a la primera línea From directory:, pulsar Browse y localizar el directorio que

contiene a la clase que queremos importar. Generalmente se encontrará en el

directorio workspace de Eclipse, dentro de una carpeta de proyecto. Tendremos

que navegar por la estructura de directorios src/nombre_del_paquete hasta

localizar el directorio que contiene a la clase a importar. Pulsar en aceptar.

• Seleccionar el fichero Java que nos interesa y pulsar Finish.

El fichero Java seleccionado se copiará en nuestro proyecto. Una vez aquí podremos

cambiar el nombre del paquete en la sentencia package, primera línea del fichero.

B. 1.3. Importar un proyecto completo ya existente

SI queremos llevarnos nuestros proyectos de Android en un pendrive para trabajar un otro

ordenador, o tener un backup, no basta con copiar los ficheros del directorio de trabajo, ya

que Eclipse no los reconocerá como proyectos y no los ibrirá. Lo que debemos hacer es

exportar e importar los proyectos. Eclipse puede nxportar e importar un proyecto completo,

como sistema de ficheros. Todo el proyecto queda almacenado en un directorio que

podemos copiar a voluntad.

Para exportar un proyecto:

• Pulsar con el botón derecho sobre el nombre del proyecto en el explorador de

archivos de Eclipse.

• Seleccionar Exportar - File System - To Directory.

• Seleccionar un directorio y pulsar Finish.

Para importar un proyecto almacenado en un directorio,

• Seleccionar File - Import - Existing projects into workspace - next.

• Se abrirá la ventana Import Projects. Marcar la casilla Select root

directory y pulsar browse

• Se abrirá una ventana de explorador de archivos. Seleccionar el directorio raíz

que contiene nuestro projecto y pulsar en aceptar.

Page 257: Android

B.2. Android Virtual Device (AVD)

236 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

Un AVD es un emulador de un dispositivo Android, es decir, un programa que simula un

teléfono Android en nuestro ordenador. Esto permite ejecutar nuestras aplicaciones android

sin necesidad de copiarlas a un dispositivo real.

Controles de teclado:

• Ctrl-F11 y Ctrl-F12 cambian de apaisado a vertical y viceversa.

• Alt-Enter cambia a pantalla completa.

B. 3. Dalvik Debug Monitor Server (DDMS)

En Eclipse, seleccionar el menú:

Window > Open Perspective > Other... > DDMS

para abrir la perspectiva DDMS.

Para capturar la pantalla del dispositivo virtual en la perspectiva DDMS, localizar la

ventana devices (arriba a la izquierda) y pulsar el icono que representa una cámara

fotográfica, o bien en el menú de la ventana devices. La imagen capturada se abrirá en una

ventana, que se podrá salvar en un fichero png (figura B.1).

Figura B.1. Captura de pantalla del AVD.

Page 258: Android

ANIiHOID: PROGRAMACIÓN III DISPOSITIVOS MÓVILES A TRAVÉS DÉ EJEMPLOS 237

Page 259: Android

APÉNDICE C

238 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIl I '. A I HAVÉS DE EJEMPLOS

B. 4. Instalar driver dispositivo Android de Samsung en Linux (Ubuntu

Jaunty)

Tara poder tener acceso a nuestro Samsung lo primero es conseguir que Ubuntu

I. Tunty detecte correctamente el teléfono.

Los pasos a seguir para conseguirlo son:

Como superusuario editar el siguiente fichero (crearlo si no existe):

/etc/udev/rules.d/51-android.rules Copiar la siguiente línea completa al fichero y

guardar los cambios: SUBSYSTEM=="usb", ATTRS{idVendor}=="04e8",

MODE="0666"

Cambiar los permisos del fichero:

chmod a+rx /etc/udev/rules.d/51-android.rules Conectar el

dispositivo al PC con el cable usb.

Para ver si ha funcionado cambiar al directorio donde está instalado el SDK y njecutar

adb devices. Por ejemplo, en mi PC android-SDK/platform- tools/adb

devices. Si el dispositivo está conectado y ha sido detectado, iparecerá en la lista. Por

ejemplo, en mi PC aparece:

~/android-SDK/platform-tools$ adb devices List of devices

attached emulator-5554 device 1000e7d982el device

Mi Samsung Galaxy Tab aparece listado como el device 1000e7d982e1.APLICACIONES

En este apéndice aplicamos los conceptos y técnicas introducidas en este libro para realizar

un programa completo de cálculo científico, con aplicación directa al cálculo de la estructura

del núcleo de helio. Esta aplicación puede descargarse de la página web

http://www.ugr.es/~amaro/android e instalarse directamente en un dispositivo Android. El

código fuente también se encuentra disponible para su descarga. Para comprender la

estructura de este programa no se necesitan conocimientos previos de Física, pues

bastaría indicar que se calculan las ecuaciones (C.1) a (C.5) a partir de los parámetros de

entrada y de los datos experimentales, que se descargan de la red según se explica más

abajo. Ahora bien, para el lector más avanzado y curioso, incluimos en cada sección una

pequeña introducción para aclarar el significado de las ecuaciones, el de los parámetros de

entrada y el de las magnitudes que se están calculando.

C. 1. Interacción neutrón-protón

Page 260: Android

ANIiHOID: PROGRAMACIÓN III DISPOSITIVOS MÓVILES A TRAVÉS DÉ EJEMPLOS 239

En el siguiente programa calcularemos (más bien ajustaremos) la energía potencial de

interacción entre un neutrón y un protón. El programa puede utilizarse en un curso de Física

Cuántica como ilustración de la resolución de la ecuación de ondas (ecuación de

Schrödinger) en una dimensión.

-u'\x) + U(r) u(r) = £ u(r),

donde u(r) es la función de onda relativa del sistema neutrón-protón, r es la distancia

entre las dos partículas y £->0 es la energía relativa multiplicada por 2/¿//?2, siendo /u = m/2

la masa reducida y m la masa del protón. La constante de Plank reducida es h = h/2it.

Queremos encontrar la energía potencial U(r), parametrizada en la forma:

U(r) = A 0S(r-R 0 ) + ¿ ,S( r -RJ

Page 261: Android

Mil I'KOORAMACIÓN DE DISPOSITIVOS MÓVILES ATRAVÉBDE I .11 MI’I OS 23l)

donde XQ, XU Ro, Ri, son cuatro parámetros que se van a ajustar en el programa

Miinparando con datos experimentales de la interacción. Este potencial lo hemos

iMiametrizado como suma de dos funciones del tipo delta de Dirac, centradas en ■I puntos

R0 y R¡, indicando que la interacción sucede en esos dos puntos. La (unción delta de Dirac

S(x) verifica:

• 8(x) = 0, si x es distinto de cero, y

• j 5(x)dx = 1, en cualquier intervalo conteniendo al cero.

I’ara este programa no necesitamos conocer los detalles de la resolución de la m

luición de ondas con el potencial anterior. Nos basta con tener la expresión mntemática de

la función solución u(r), que está dada en la sección C.2..

I ¡i actividad principal de este programa es el siguiente fichero il.uitlroicPhysics.java.

Utilizaremos el layout Introducido en el ejemplo 13.3, que ' mi isla de los tres ficheros

main.xml, strings.xml, colors.xml.

■package es.ugr.amaro.handroicphysics;

import android.app.Activity;

11111)(>rt android. content. Intent ; 11111 'i >rt android. content. SharedPref erences ; Import android.os.Bundle;

Import android.view.View; llfflport

android.view.View.OnClickListener;

11 nip' irt android. widget. EditText ;

Bmport android.widget .Toast;

p u M i c class HandroicPhysics extends Activity implements

OnClickListener{

Mi.11 edPreferences misDatos; I'M 1 tText editLOO ,

editLOl ; i" 111:Text

editLlO, editLll ;

I'M 1 tText editROO, editROl;

I KM 11 Text editRlO,editRll;

K ' l l I Text editEmax,editTolerancia,editResolucion;

'»override

public void onCreate(Bundle savedlnstanceState) {

tiuper.onCreate (savedlnstanceState)

netContentView(R.layout.main); }

IOI( ivftrride

pi')»r«Cted void onStart(){ wuper.onStart();

Page 262: Android
Page 263: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 240

View buttonl=findViewByld(R.id.button!)■

View button2=findViewByld (R. id.button.2) ■

View button3=findViewByld(R.id.button3);

buttonl.setOnClickListener(this);

button2.setOnClickListener(this);

button3.setOnClickListener(this);

// lee lambadOO en el fichero de preferencias

misDatos=getSharedPref erences ("preferencias 11 , 0) ;

editEmax=(EditText) findViewByld(R.id.Emax); editEmax.

setText (11 " +misDatos . getFloat (" Emax ",100) ) ;

editTolerancia=

(EditText) findViewByld(R.id.tolerancia);

editTolerancia . setText ("11 +

misDatos.getFloat("tolerancia",0.5f));

editResolucion=

(EditText) findViewByld(R.id.resolucion);

editResolucion.setText(""

+misDatos.getFloat("resolucion",(float) le-5));

editR00=(EditText) findViewByld(R.id.R0 0);

editR01=(EditText) findViewByld(R.id.ROl);

editROO.setText(""+misDatos.getFloat("R00" , 0.75f)) ;

editROl.setText(""+misDatos.getFloat("R01", 1. 25f));

editR10=(EditText) findViewByld(R.id.RIO);

editRll=(EditText) findViewByld(R.id.Rll);

editRlO.setText(""+misDatos.getFloat("RIO", 0 . 75f) ) ;

editRll.setText(""+misDatos.getFloat("Rll", 1. 25f)) ;

editL00=(EditText) findViewByld(R.id.lambdaOO);

editL01=(EditText) findViewByld(R.id.lambdaOl);

editL10=(EditText) findViewByld(R.id.lambdal0);

editLll=(EditText) findViewByld(R.id.lambdall);

editLOO.setText(""

+ misDatos.getFloat("lambdaOO", 0.73f));

editLOl.setText(""

+ misDatos.getFloat("lambdaOl",-0.7f));

editLlO.setText(""

+ misDatos.getFloat("lambdal0", 0.73f));

editLll.setText(""

+ misDatos.getFloat("lambdall",- 0.7f));

}

(©Override

protected void onPause(){

super.onPause();

SharedPreferences.Editor miEditor=misDatos.edit();

Page 264: Android
Page 265: Android

mm I'HOGRAMACIÓN DE DISPOSITIVOS MÓVIL! S A 1HAVI':. Ill I II Ml'LOH

float dato;

dato=Float.parseFloat(editROO.getText() .toStringO) ;

miEditor.putFloat("R00";dato);

dato=Float.parseFloat(editROl.getText().toString(l);

miEditor.putFloat("R01",dato);

dato=Float.parseFloat(editRlO.getText().toString());

miEditor.putFloat("RIO",dato);

dato=Float.parseFloat(editRll.getText().toString());

miEditor.putFloat("Rll"(dato);

dato=Float.parseFloat(editLOO.getText().toString(l);

miEditor.putFloat("lambdaOO",dato);

dato=Float.parseFloat(editLOl.getText().toString());

miEditor.putFloat("lambdaOl",dato);

dato=Float.parseFloat(editLlO.getText().toStringO);

miEditor.putFloat("lambdalO",dato);

dato=Float. parseFloat (editLll. getText () .toStringO) ;

miEditor.putFloat("lambdall",dato);

dato=Float.parseFloat(editEmax.getText().toString())

miEditor.putFloat("Emax",dato); dato=Float.parseFloat(

editTolerancia.getText().toString())

miEditor.putFloat("tolerancia",dato); dato=Float.parseFloat(

editResolucion.getText().toString())

miEditor.putFloat("resolucion",dato);

miEditor.commit();

Toast.makeText(this,"Datos guardados",1).show();

imOverride

public void onClick(View v) {

int i=v.getld();

Intent intención;

if(i==R.id.buttonl){

// calcula la energia del He4 intencion=new

Intent(this,He4.class);

startActivity(intención); }

else if(i==R.id.button2){

// calcula desfasaje para spin=0 intencion=new

Intent(this,PhaseShift.class);

intención.putExtra(PhaseShift.spinExtra, 0);

startActivity(intención); } '■lee if (i==R. id.button3) {

// calcula desfasaje para spin=l

intencion=new

Intent(this,Ph.aseSh.ift.class);

Page 266: Android

MIINOII) PROGRAMACIÓN DF DISPOSITIVOS MÓVILFS A TRAVÉS (31 I JEMPl OS 243

(C.3)

intención.putExtra(PhaseShift.spinExtxa, 1);

startActivity(intención) ;

}

}

}

La actividad puede verse en la figura C.1 (que es la misma del ejemplo 13.3). La

actividad tiene tres botones y 11 campos de texto.

J.E. Amaro, 2011

Figura C.1. Interfaz de usuario para ajustarla interacción neutrón-protón y para calcular la

energía del helio-4.

Debemos aclarar que la interacción depende de una variable del protón y neutrón

denominada espín. El espín total puede ser cero o uno. La interacción para espín cero se

denomina el canal1Sn y la interacción para espín uno el canal 3S¡. De manera que debemos

encontrar dos conjuntos de parámetros, uno para cada canal. En la primera columna hay

que introducir los valores iniciales de los cuatro parámetros 10, h, Ro, para el canal ‘S0. En

la segunda columna introducimos los valores para los cuatro parámetros en el canal 3S,.

Los valores de R¡ están en unidades de Fermi (fm) (1 Fermi = 10"15 metros) y los de h-, en

fm'1. En la última fila hay tres campos de texto. El primero, Emax, es la máxima energía

experimental que vamos a incluir en el ajuste posterior, en la figura es de 100 MeV (Mega

electrón Voltios). El segundo es la tolerancia, que es el mínimo error experimental que

aceptamos. En el ejemplo es de 0.5, indicando que el error

HandrolcPhysics Interacción Neutrón-Protón

V(r)=E] V2|J ¿(r-R¡) (Pulse para ajustar X, y R¡)

Ema,(MeV) Tolerancia Resolución

100 0.5 pT¡E^5

Page 267: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 244

nxperimental no puede ser menor de 0.5 (si es menor, lo modificamos para que Mea

exactamente 0.5). El tercer campo es la resolución, que corresponde a la ultima cifra

decimal de nuestros parámetros, que se va a variar en el ajuste. En rtste caso es de 10'5.

En la actividad HandroicPhysics.java definimos tres botones marcados A, B, C. Al pulsar

el primero, se ajustan o calcular los parámetros del canal rS0, Al pulsar el vigundo, se ajusta

el canal 3S¡. El tercer botón se utilizará para calcular la energía ■ le ligadura del núcleo de 5He (Helio 4) o partícula alfa.

Cada vez que se inicia la actividad anterior y se ejecuta el método onStartQ, los

contenidos de los campos de texto se leen de un fichero de preferencias con

SharedPreferences. De la misma forma, cuando salimos de la actividad (al pulsar un botón

o la tecla back), se ejecuta el método onPause() y se guardan los contenidos de los campos

de texto en el fichero de preferencias.

C. 2. Ajuste por mínimos cuadrados

Al pulsar el botón A se ajustan los parámetros del canal 'S0. Para ello utilizamos • uní el

potencial es cero en los puntos r distintos de R„y R, (puesto que la delta de bli.ac es cero).

Por tanto, la función de onda solución del problema en cada mlorvalo es una función

trigonométrica, correspondiente a una partícula libre con

numero de ondas & = yfe , y se puede escribir:

5 Modificar los parámetros del potencial y repetir el proceso, recalculando la función

chi cuadrado hasta encontrar el mínimo.

Page 268: Android

MIINOII) PROGRAMACIÓN DF DISPOSITIVOS MÓVILFS A TRAVÉS (31 I JEMPl OS 245

(C.3)

donde 80 y ó, son fases constantes que se determinan imponiendo que la (unción de

onda sea continua y que su derivada sea discontinua con una i II-.-continuidad dada por:

«Y R¡+) -u'( R-) = A; u( R¡ )

piopiedad que se obtiene integrando la ecuación de ondas en un intervalo iii < idedor de

R¡ y usando la propiedad de Integración de la delta de Dirac. El insultado son las siguientes

ecuaciones, que emplearemos para calcular las fases:

' .o puede calcular así el desfase total o desfasaje:

ó = So + 6¡

si r < R, o si R0< r< R/ si

R¡< r

u(r) = sin kr, u(r) = sin

(kr+ ó0), u(r) = sin (kr+ ó0

+ ó¡) ,

(C.l)

y: (C.2)

ó0 = tan'((cot k Ro+A0/k)'!) - kR0

do + ó¡= tan'((cot (k R¡+ ó0)+ A] /k)'¡) - kR¡

Page 269: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 246

El desfasaje se calcula a partir de las ecuaciones (C.1) a (C.3) en el programa siguiente

PhaseShift.java. Este desfasaje o es debido a la interacción y puede medirse

experimentalmente haciendo incidir haces de neutrones sobre núcleos de hidrógeno

(protones). Existen varias parametrizaciones para los datos experimentales del desfasaje.

Algunas de ellas se pueden descargar de la página web nucleon-nudeon online:

http://nn.online.org/NN

En esta página web seleccionaremos Phase shiñs versus energy (table), lo que nos

lleva a una página donde podemos elegir las siguientes opciones:

• Choose model. Seleccionaremos todos los modelos.

• Choose interaction. Seleccionaremos la interacción neutrón-protón.

• Energy interval. Seleccionaremos el intervalo de energia Tmin=1 MeV,

Tmax=350 MeV.

• Intervals of energy. Introduciremos un intervalo de 1 MeV.

• Gíve the phase. Introduciremos el canal deseado, en este caso 1S0.

Al enviar estos datos, se mostrará en pantalla una tabla con la información deseada. La

descargaremos en un fichero, que contendrá el desfasaje experimental para energías desde

1 MeV hasta 350 MeV, con un intervalo de energía de1

MeV,

que copiaremos en el directorio /res/raw de nuestro proyecto. Cada fila contiene el

valor de la energía en la primera columna, y, en las restantes columnas, el desfasaje

calculado con varios modelos. Tomando el valor medio de estos desfasajes, obtenemos el

que consideraremos desfasaje experimental. La variación (máximo menos mínimo) de estos

desfasajes es lo que consideraremos el error experimental. De este fichero seleccionamos

un conjunto de valores {(Eu óh ¿1¿): i=l,...,n} para la energía, desfasaje experimental y su

error, respectivamente.

A continuación, lo que haremos en el programa será lo siguiente:

1. Elegir un conjunto de parámetros del potencia.

2. Calcular el desfasaje S(E¡) mediante las fórmulas anteriores.

3. Calcular la función chi cuadrado:

(C.4)

Este número

es una

estimación de la distancia global a los datos experimentales.

n

Page 270: Android

All! iMOID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÍ' DI I .11 MH OH 247

El funcionamiento del programa para el canal Si, se ilustra en la figura C.2. Consiste en

una animación donde se dibuja el desfasaje experimental en función de la energía y los

puntos calculados, que se van modificando en cada iteración hasta que se alcanza el

mínimo con la resolución deseada. Al finalizar, pulsamos la tecla back y los nuevos valores

del potencial aparecen en los campos de texto de la primera columna, figura C.3. El listado

del programa PhaseShift.fava es el siguiente.

package es.ugr.amaro.handroicphysics;

import java.io.BufferedReader;

import java.io.InputStream;

import j ava.io.InputStreamReader;

import java.util.StringTokenizer;

import android.app.Activity;

import android.content.Context;

import android.content.SharedPreferences;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.os.Bundle;

import android.view.View;

import android.widget.Toast;

public class PhaseShift extends Activity {

public static final String spinExtra="spin";

SharedPreferences misDatos;

final int ndeltas=2; // numero de deltas

final int nparametros=2*ndeltas;

int spin;

doublet] energy=new double[400];

doublet] [] dat=new double [400] [5] ;

double [] energyExp ={1,3,5,10,20,30,40,50,70,

100,150,200,250,300,350};

int nDatos,nDatosExp; doublet] expdat=new

double[20]; doublet] expdatError= new

double[20]; doublet] deltaDeg=new double[20];

Plot plot;

String texto,textol;

String texto2="Paso";

String texto3="CALCULANDO..."; double

lambdat][]=new double[2][ndeltas]; double

Rdelta[] []=new double [2] [ndeltas]; double

Emax;

boolean contínuar=true;

Thread hilo;

//variables para minimizar

Page 271: Android

248 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A 1 KAVÍS DE EJEMPLOS

double[] xvar = new double[2*ndeltas] ;

double tolerancia,resolución;

(©Override

public void onCreate(Bundle savedlnstanceState){

super.onCreate(savedlnstanceState);

// spin pasado en parametro extra

spin=getIntent().getlntExtra(spinExtra, 0) ;

leerPreferencias() ;

leerDatos();

plot=new Plot(this);

setContentView(plot) ;

hilo=new Thread(plot);

hilo.start();

class Plot extends View implements Runnable{ int width,height;

Paint paintl,paint2,pain3,paint,paintRun;

Path pathl ,-

int topMargin=30;

int margin=3 0;

int x0,xl,y0,yl,x,y;

double eO, el, dO, dl;

public Plot(Context context) { super(context); paint=new

Paint(); paint.setColor(Color.BLACK);

paint.setTextSize(16); paintRun=new Paint();

paintRun.setColor(Color.RED);

paintRun.setTextSize(20); paintl=new Paint();

paintl.setColor(Color.BLACK);

paintl.setStyle(Paint.Style.STROKE);

paintl.setStrokeWidth(1); paint2=new Paint();

paint2.setColor(Color.RED);

paint2.setStyle(Paint.Style.STROKE);

paint2.setStrokeWidth(3); pathl=new Path();

e0 = 0 ; el=350; d0=-20; dl = 180 ; }

@Override

protected void onSizeChanged(

int w, int h, int oldw, int oldh){ width=w;

height=h; xO=margin; xl=width-margin; y0=height/2;

yl=topMargin; }

@Override

protected void onDraw (Canvas canvas){

canvas.drawColor(Color.WHITE); texto="Desfasaje Neutron-

Proton. SPIN="+spin; canvas.drawText(texto,20,20,paint);

Page 272: Android

I III I I '|<()(IRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 249

canvas.drawRect(xO,yO,xl,yl,paintl);

canvas.drawText(textol,

width/2-30,topMargin+2 0,paint);

canvas.drawText(texto2,

width/2-30,topMargin+4 0,paint);

canvas.drawText(texto3,

width/2-3 0,topMargin+65, paintRun);

x=coX(energy[0]); y=coY(dat [0] [0]);

pathl.moveTo(x,y); for(int

ie=l;ie<nDatos;ie++){ x=coX(energy[ie]);

y=coY(dat[ie][0]); pathl.lineTo(x,y); } canvas.drawPath(pathl,paint2);

// dibuja puntos experimentales for (int

i=0;i< nDatosExp;i + + ){

x=coX(energyExp[i]); y=coY(expdat[i]);

int yl=coY(expdat[i]-expdatError[i]); int

y2=coY(expdat[i]+expdatError[i]);

canvas.drawCircle (x, y, 5 , paint) ,-

canvas.drawLine(x,yl,x,y2, paint);

Page 273: Android
Page 274: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I SA IRAVÉS OE EJEMPLOS

// aiDuja puntos ajustados

y=coY(deltaDeg[i]);

canvas . drawCircle (x,jr, 5 , paint2) ;

// Marcas en el eje x for (int i = 0; i<7;i + +) {

canvas.drawLine(coX(50*i),coY(dO) ,

coX(50*i),coY{dO+5>,paintl);

canvas.drawText(""+50*i,

coX<50*i),coY(d0)+20, paint); }

// Marcas en el eje y for (int i=0;i<18;i++){

canvas.drawLine(coX(0),coY(10 * i) ,

coX(0+5),coY(10 * i) , paintl);

canvas.drawText(""+10*1,0,coY(10*i), paint); }

// dibuja linea del cero canvas.drawLine(coX(0) , coY(0)

,

coX(350),coY(0),paintl);

// escribe parámetros del potencial

texto="R"+spin+"0 ="+xvar[2];

canvas.drawText(texto, 20, y0+40, paint);

texto="La"+spin+"0 ="+xvar[0] ,-

canvas.drawText(texto, 20, y0+60, paint);

texto="R"+spin+"l ="+xvar[3];

canvas.drawText(texto, 20, y0+80, paint);

texto="La"+spin+"l ="+xvar[l];

canvas.drawText(texto, 20, y0+100, paint);

canvas.drawText("Emax="+Emax, 20, y0+120( paint);

int i i=2;

// escribe puntos experimentales

texto="ndatosExp="+nDatosExp;

canvas.drawText(texto,width/2+10,y0+20*ii,paint); for

(int i=0;i<nDatosExp;i++){ ii + + ;

texto="/"+energyExp[i]+"/"

+expdat[i]+"/"+expdatError[i];

canvas.drawText(texto,width/2 + 10,y0+2 0*ii, paint); }

}

int coX(double e){

double xdouble=x0+(xl-xO)*(e-eO)/(el-eO);}

int coY(double d){

double ddouble=yO+(yl-yO)*(d-dO)/(dl-dO);

return (int) ddouble;

Page 275: Android

250 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

@Override

public void run() {

// Comienza buscando el minimo con paso inicial

double paso=0.5; int dt=2 0 0;

while(continuar){

texto2="Paso="+paso;

minimiza(paso);

paso=paso/2.0;

postlnvalidate();

try{ Thread.sleep(dt);}

catch(InterruptedException e){;}

if(paso/2.<resolución)continuar=false;

} ■

texto3="MINIMO ENCONTRADO!"; postlnvalidate(); }

}

void leerDatos(){

int numeroFichero=R.raw.phaselsO;

if(spin==l) numeroFichero=R.raw.phase3sl;

InputStream inputl=

getResources().openRawResource(numeroFichero);

InputStreamReader streaml=

new InputStreamReader(inputl);

BufferedReader bufferl=

new BufferedReader(streaml,8192);

int iLinea=0;

int iDato=0;

try {

String linea; while(true){

linea=bufferl.readLine();

if(linea==null)break; iLinea++;

if(iLinea>4){

StringTokenizer tokens =

new StringTokenizer

(linea) energy[iDato]=

Double.parseDouble(tokens.nextToken());

// lee cinco columnas

// con varios cálculos de desfasajes

for (int j = 0; j<5; j+ + ){ dat[iDato] [j ] =

Double.parseDouble(tokens.nextToken( ) ) 7 } iDato++;

} }

Page 276: Android

251 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS

inputl. close ()

streaml.close();

bufferl.close();

}catch(Exception e){ texto="\n"+e; } nDatos=iDato; texto=texto+"Datos: "+nDatos;

// calcula puntos experimentales

nDatosExp=0;

for (int i=0;energyExp[i]<=Emax;i++){

for (int j = 0; j<nDatos; j++){

double diff=energyExp[i]-energy[j];

if (Math.abs(diff)<0.01){ double

datMin=dat[j][0 ]; double

datMax=datMin; for(int k=l;k<5;k++){

double dato=dat[j] [k] ; if

(datMax < dato)datMax=dato;

if(datMin > dato)datMin=dato; }

expdat[i]=(datMax+datMin)/2.0;

expdatError[i]=(datMax-datMin)/2.0;

// tolerancia

if(expdatError[i]<tolerancia)

expdatError[i]=tolerancia;

nDatosExp++;

}

}

}

}

Page 277: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPI <)B

void leerPreferencias(){

// lee lambadOO en el fichero de preferencias

misDatos=getSharedPreferences ("preferencias11 y 0)

lambda [0] [0] =misDatos . getFloat (" lambdaC 0 11,

0) ; lambda [0] [1] =inisDatos.getFloat ("lambdaOl",

0) ; lambda[1] [0]=misDatos.getFloat("lambdalO", 0);

lambda [1] [1]=misDatos.getFloat("lambdalL",0);

Rdelta[0] [0]=misDatos.getFloat <"ROO",0)■

Rdelta[0][1]=misDatos.getFloat("ROI",0);

Rdelta [1] [0] =misDatos .getFloat ( "RIO 11, 0) ;

Rdelta[1][1]=misDatos.getFloat("Rll",0);

Emax=misDatos.getFloat("Emax" , 0);

tolerancia=misDatos.getFloat("tolerancia",0);

resolucion=misDatos.getFloat("resolución",0)?

// variables iniciales para minimizar

xvar[0]=lambda[spin][0];

xvar[1]=lambda[spin][1];

xvar[2]=Rdelta[spin][0];

xvar[3]=Rdelta[spin][1];

double minimiza(double paso){

int dimension= nparametros; double[]

xmas=new double[dimensión]; double []

xmenos=new double[dimensión] ; double[]

x=new double[dimensión];

for (int i=0;i<dimension;i++)x[i]=xvar[i]; double

minimo=chiCuadro(x); double oldmin=minimo;

boolean esMinimo=false;

while (lesMinimo){

for (int i=0;i<dimension;i++){

// calcula puntos desplazados dirección +-i for(int

j=0;j«dimensión;j++){ double kroneker=0; if

(i==j)kroneker=l; xmas[j]=x[j]+paso*kroneker;

xmenos[j]=x[j]-paso*kroneker; }

// si R1 < R0 no nos movemos if(xmas[3]<xmas[2])

xmas[2]=xmas[3];

double valuemas=chiCuadro(xmas);

if(valuemascminimo) { minimo=valuemas;

for (int j=0;j<dimension;j++)xvar[j]=xmas[j]; }

Page 278: Android

if (xmenos [3] <xmenos [2] )xmenos [3] =xmenos [2]

253 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A IRAVÉ9 DE EJEMPLOS

double valuemenos=chiCuadro(xmenos);

if(valuemenoscminimo){ minimo=valuemenos;

for (int j=0;j<dimension;j++)xvar[j]=xmenos[j]; } textol="Minimo="+minimo;

}

// si el punto no se ha desplazado ES EL MINIMO

if(minimo==oldmin) esMinimo=true; else {

oldmin=minimo;

for(int i=0;i<dimension;i++){x[i]=xvar[i];} } } return minimo;

double chiCuadro(double[] parámetros){

double valor=0;

for (int i=0;i<nDatosExp;i++){ double

Elab=energyExp[i]; deltaDeg[i]=

desfasaje(Elab,parámetros); double sumando =

(deltaDeg[i]-expdat[i] )/expdatError[i];

valor=valor + sumando*sumando; } return valor/nDatosExp;

}

// Calcula el desfasaje en onda S. Potencial delta-shell

double desfasaje(double Elab, double[] parámetros){

double delta=0;

double Erel=Elab/2;

double muc2=939.0/2.0;

double hbarc=197.32;

double hbarc2=hbarc*hbarc;

double twoMuH2=2.0*muc2/hbarc2;

Page 279: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPI <)B

double epsilon=twoMuH2*Erel; double

k=Math.sqrt(epsilon);

for (int i=0;i<ndeltas;i++){

double kr=k*parametros[i+ndeltas]; //

lamda esta dividida por 2mu en double

alfak=parametros[i]/k; double ctan=l.

O/Math., tan (kr+delta) ; double

denominator=ctan+alfak; double

unotan=l.0/denominator;

delta=Math.atan(unotan)-kr;

// check delta is between -pi,pi for J=0

if(spin==0){ if (delta<=-Math.PI/2){

while(delta<-Math.PI/2)delta=delta+Math.PI; } if(delta>Math.PI/2){

while(delta>Math.PI/2)delta=delta-Math.PI*2; } }

// check delta is between 0,pi for J=1

if(spin==l){ if (delta<0){

while(deltacO)delta=delta+Math.PI; } if(delta>Math.PI){

while(delta>Math.PI)delta=delta-Math.PI*2; } }

double deltaDeg=delta*180/Math.PI;

return deltaDeg; }

@Override

protected void onPause(){

super.onPause();

// detenemos el hilo

continuar=false;

if(hilo.isAlive()) hilo.stop();

// guardamos datos

SharedPreferences.Editor miEditor=misDatos.edit();

lambda[spin] [0]=xvar[0];

Page 280: Android
Page 281: Android

254 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII I R A IK/WI':. D[ I JEMPL08

lambda [spin] [l]=xvar[l] ;

Rdelta [spin] [0]=xvar[2] ;

Rdelta[spin] [l]=xvar[3] ;

miEditor.putFloat("lambdaOO",

(float) format(lambda[0] [0],6));

miEditor.putFloat("lambdaOl",

(float) format(lambda[0] [1] , 6)

) ; miEditor.putFloat("lambdalO",

(float) format(lambda[1] [0] ,6) )

; miEditor.putFloat("lambdall",

(float) format(lambda [1] [1],6))

; miEditor.putFloat("R00",

(float) format(Rdelta[0] [0],6));

miEditor.putFloat("R01",

(float) format(Rdelta[0][1],6));

miEditor.putFloat("R10",

(float) format(Rdelta [1] [0] ,6))

; miEditor.putFloat("Rll",

(float) format(Rdelta [1] [1],6));

miEditor.commit();

Toast.makeText(this,"Datos guardados ", 1) .show();

}

// formatear un numero con varias cifras

float format(double x, int cifras){

String cadena=""+x; if (cadena.length()<=cifras)

return Float.parseFloat(cadena);

if(x<0) cifras=cifras+1;

float y=Float.parseFloat(cadena.substring(0, cifras)) ;

return y;

O 50 100 150 200 250 J00 ROO =1.8806250095367432 ndatcsExp=10 La00 =-0.015625 /1.0/62.002425./0.5 R01 =1.8806250095367432 /3.0/64.537075/0.5 La01 =-0.47562500834465027 /5.0/63.4801 fOS Emax=100.0 /10.0/59.776955/05

/20.0/53.38 63/0.5 /30.0/48.31505/0.5 /40.0/44.05127/0.5

555000000004/0.5 ¡35/0.5 1375/0.669464

999

100 ISO 200 250 300

ROO =1.6312353610992432 ndalos£r.p=10

LaOO =-0.06274414-0625 /1.0/62.502425/05

R01 =1.6312353610992432 /3.0/64. S37075/0.5

La01 =-05055627S 24852753 /5.0/63.480170.S

Emax=100.0 /10.0/59.776955/0.5

/20.0/53.3863/0.5

/30.0/48.31 S 05/05

/40.0/44.05127/05

/50.0/40.26805500Q000004/

0.5 /70.0/33.886135/0.5

/100.0/26.113975/0.6694649

99

Desfasaje Neutron-Protoa SPCN =0

. Mfni mo=í!5.S707 5377680096 Paso=0,015625

.

.

. i

CALCULANDO...

o

(»ertasa je W e irtro n-Píoton, SPIN =0

IVIn ¡rro =4.637529 617 837 76S Paso=i.0517S7312ÍE-5

M1NIM O ENCONTRADO!

Page 282: Android

AHI >1« )||) PROGRAMACIÓN DE DISPOSITIVOS MÓVII lSA TRAVÉS DE EJEMPLOS 255

Figura C.2. Ajuste del desfasaje 's<> para espín igual a cero.

I Hile 22:09 I

HandroicPhysics

Figura C.3. Valores ajustados del desfasaje 's0.

La descripción de los distintos métodos es la siguiente:

• Método onCreate(). Se almacena el valor del espin (cero o uno) en la variable spin

pasada como parámetro extra por la actividad principal. Luego se lee el fichero de

preferencias en el método leerPreferencias() y se leen los datos experimentales en

el método leerDatosQ. Se instancia el

Page 283: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 256

objeto plot de tipo View, donde se dibuja la gráfica que, a su vez, implementa la

interfaz Runnable. Finalmente, se inicia un hilo para realizar el ajuste por mínimos

cuadrados.

• Clase Plot. Se utiliza para dibujar la gráfica y para ¡mplementar la interfaz

Runnable. En el método onSizeChanged() se calculan las dimensiones de la

pantalla y las de la gráfica. El método onDraw() dibuja la gráfica y escribe los

valores de los parámetros del potencial, los datos experimentales que se están

ajustando, el valor del mínimo y el paso de búsqueda.

• Método run(). Implementado en la clase Plot. Comienza con un paso de búsqueda

y ejecuta el método minimiza(paso) para encontrar el mínimo con ese paso. Luego

reduce el paso a la mitad y se repite el proceso hasta llegar al mínimo con la

resolución deseada.

• Método minimiza(paso). Dado un paso de búsqueda, busca todos los puntos

adyacentes, sumando y restando el paso a los parámetros del potencial, y calcula

la función chi cuadrado en todos ellos ejecutando el método chiCuadro().

• Método chiCuadro(). Calcula la función chi cuadrado haciendo un loop sobre las

energías experimentales y llamando al método para calcular los desfasajes.

• Método desfasaje(). Calcula el desfasaje para una energía y parámetros del

potencial dados. Se resta o suma pi, teniendo en cuenta que para el canal 'S0 el

desfasaje debe estar entre (-3 1 /2 , it/2), mientras que, para el canal 3Sh el desfasaje

está entre (0, jt).

SSWZMÍI Phase Shifts

Desfasaje Neutron-Proton. SPrÑ=l

R10 =1.171875 ndatosExp=10

LalO =-0.0625 A.0/147.744505/0.5

RII =1.4048999547958374 /3.0/128.800855/0.5

la11 =-0.9100000262260437 /5.0/118.21848/0.5

Eniax=100.0 /10.0/102.704755/0.5

/20.0/86.283715/0.5

/30.0/76.256455/0.5

/40.0/68.896695/0.5

¡595000000005/0.5 R10 =0.681396484375 ndatosExp=10

la10 =-0.82086181640625 /1.0/147.744505/0.5 R11 =1.6256335973739624 ('3.0/128.800855/0.5 Lai 1 =-0.6616784930229187 /5.0/118.21848/0.5 Emax°100.0 /10.0/102.704755/0.5

/20.0/86.283715/0.5 /30.0/76.2564S5/0.5 /40.0/68.896695/0.5 /S0.0/63.015S9S000000005/0.5 /70.0/53.807945000000004/0.5 /100.0/43.52132/0.5747600000

Figura C.4. Ajuste del desfasaje 3S, para espin igual a uno.

Phase Shifts

Desfasaje Ñeutron-Proton. 5PÌN=»Ì Mlnimo=l.128125382316351 Paso=0.015625 CALCULANDO...

Mlnlmo=0.07593826423255853

Paso=3.0517578125E-5

MINIMO ENCONTRADO!

Page 284: Android

AHI >1« )||) PROGRAMACIÓN DE DISPOSITIVOS MÓVII lSA TRAVÉS DE EJEMPLOS 257

Después de ajustar el canal ‘S0 se pulsa la teda back para volver a la actividad .interior y

se pulsa el botón B para calcular los parámetros en el canal 3S,. El proceso y resultado de la

mlnimlzación se muestra en la figura C.4. Encontrado el mínimo se vuelve a pulsar back,

volviendo de nuevo a la actividad principal con lodos los parámetros ajustados, figura C.5.

lì ¡BU 22:39

HandroicPhysics

Interacción Neutrón-Protón

i 0<„,

Figura C.5. Valores ajustados del desfasaje 3Si.

c.3. Energía del Helio-4

l iil-.ando el botón C de la actividad principal se calcula la energía del núcleo de llullo-4

usando el potencial que se ha ajustado. El núcleo de helio consiste en i u.itro partículas: dos

protones y dos neutrones. Supondremos que la interacción «nlro cada pareja de partículas es

la que hemos ajustado en la sección anterior, lIM»mediada entre los dos canales de espin.

Para calcular la energía se utiliza el lluiii.ido método variacional. Suponemos que la función de

onda total del helio es "l producto de cuatro funciones de onda para cada una de las

partículas. Cada Imiclón de onda individual supondremos que es una Gaussiana del tipo:

u(r)= exp(-c¿ r2'/2),

con un parámetro « que debemos encontrar minimizando la energía:

V(r)=Z¡X¡/2|j ¿(r-R¡) (Pulse para ajustar ^¡y R¡)

1.6311 0.6813

-0.0627 .. ....... ..........

-0.8208

1.6311 1.6256

-0.5055 -0.6616

Emay(MeV) Tolerancia Resolución

100.0 0.5 1.0E-5

J.E. Amaro, 2011

Page 285: Android

258 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVILI .".Al NAVI'S DE EJEMPLOS

Donde el primer término es la energía cinética y el segundo la energía potencial. El

mínimo de esta función, con respecto al parámetro a, nos proporciona la energía del

núcleo de Helio. El parámetro b = L/a es una estimación del radio del helio.

El siguiente programa He4 .java es la actividad que realiza este cálculo, que se

ejecuta pulsando el botón c.

package es.ugr.amaro.handroicphysics;

import android.app.Activity;

import android.content.Context;

import android.content.SharedPreferences;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.os.Bundle;

import android.view.View;

public class He4 extends Activity!

// parametros del potencial double

lambda [] [] =new double [2] [2] ;

// centros de las deltas

double Rdelta[] [] =new double [2] [2] ;

Thread hilo;

double bmin,emin;

double cinética,potencial;

(¡»Override

public void onCreate(Bundle savedlnstanceState){

super.onCreate(savedlnstanceState) ;

leerPreferencias() ;

Gráfico grafico=new Grafico(this),■

setContentView(gráfico); hilo=new

Thread(gráfico); hilo.start(); }

@Override

protected void onPauseO {

super.onPause();

// detenemos el hilo}

class Grafico extends View implements Runnable{

int width,height;

Paint paint1,paint2,paint3,paint4,paint,paintRun;

Path pathl,path2,path3;

int topMargin=4 0;

int margin=40;

Page 286: Android

if(hilo.isAlive0) hilo.s t o p ( ];

AMI DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 259

int xO,xl,yO,yl,x,y;

double bO,bl,eO,el;

String texto;

String textol="textol";

String texto2="texto2";

String texto3="texto3";

// matriz para dibujar la energia int

intervalos=200;

double [] bMatriz=new double[intervalos]; double []

eMatriz=new double[intervalos]; double []

potMatriz=new double[intervalos]; double []

cinMatriz=new double[intervalos];

public Grafico(Context context) { super(context);

paint=new Paint(); paint.setColor(Color.BLACK);

paint.setTextSize(16); paintRun=new Paint();

paintRun.setColor(Color.RED);

paintRun.setTextSize(20); paintl=new Paint();

paintl.setColor(Color.BLACK);

paintl.setStyle(Paint.Style.STROKE);

paintl.setStrokeWidth(1); paint2=new PaintO;

paint2.setColor(Color.RED);

paint2.setStyle(Paint.Style.STROKE);

paint2.setStrokeWidth(3); paint3=new PaintO;

paint3.setColor(Color.BLUE);

paint3.setStyle(Paint.Style.STROKE);

paint3.setStrokeWidth(3); paint4=new PaintO;

paint4.setColor(Color.GREEN);

paint4.setStyle(Paint.Style.STROKE);

paint4.setStrokeWidth(3);

pathl=new Path(); path2=new

PathC); path3=new Path();

b 0 = 0 ; b 1 = 5 ;

e0=-150; e 1 = 5 0 ;

// llena una matriz para dibujar la energia double

paso=(bl-bO)/intervalos; for(int i = l; i<intervalos i++)

{ bMatriz[i]=bO+paso*i; eMatriz[i]=energia(bMatriz[i] ) ;

potMatriz [i]=potencial; cinMatriz[i]=cinetica; }

}

@Override

protected void onSizeChanged(

int w, int h, int oldw, int oldh){

width=w; height=h; xO=margin;

Page 287: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 260

xl=width-margin; yO=height-

margin; yl=topMargin; } @Override

protected void onDraw (Canvas canvas){

canvas.drawColor(Color.WHITE); texto="Energia del

Helio-4"; canvas.drawText(texto,xl/2,20,paint);

canvas.drawRect(xO,yO,xl,yl,paintl);

textol="bmin="+format(bmin,6);

texto2="Emin="+format(emin,6);

canvas.drawText(textol,width/2,85,paint);

canvas.drawText(texto2,width/2,105,paint);

canvas.drawText(texto3,width/2,65, paintRun);

// dibuja funcion energia x=coX(bMatriz[1]);

y=coY(eMatriz[1] ) ; pathl.moveTo(x,y);

for(int i=2;i<intervalos;i++){

x=coX(bMatriz[i]);

Page 288: Android
Page 289: Android

I 'U< KiHAMACIÓN DE DISPOSITIVOS MÓVIL I S A IUAVI ' I I I Ml MPLQK

y=coY(eMatriz[i] ) ; pathl.lineTo<x,y) ; } canvas.drawPath(pathl,paint2);

// dibuja energía cinética x=coX(bMatriz[1]);

y=coY(cinMatriz[1] ) ; path2.moveTo(x,y); for(int

i=2;i<intervalos;i + +){ x=coX(bMatriz[i]); y=coY(cinMatriz

[i] ) ; path2.lineTo(x,y); } canvas.drawPath(path2,paint3);

// dibuja energia potencial x=coX(bMatriz[1]);

y=coY(potMatriz[1] ) ; path3.moveTo(x,y); for(int

i=2;icintervalos;i++){ x=coX(bMatriz [i]) ; y=coY(potMatriz

[i]); path3.lineTo(x,y); }

canvas.drawPath(path3,paint4);

// dibuja punto minimo

canvas.drawCircle(coX(bmin), coY(emin), 5, paint)

// marcas eje x

for (int i = l; i<6;i + +){

canvas.drawLine(coX(i),coY(eO),

coX(i),coY(eO)-5,paintl);

canvas.drawText(""+i,

coX(i),y0+2 0, paint); }

// marcas eje y

for (int i=-15;i<5;i++){

canvas.drawLine(coX(bO),coY(10*i),

coX(bO)+5,coY(10*i), paintl);

canvas.drawText(""+10*i,0,coY(10*i), paint); }

// dibuja linea del cero canvas.drawLine(coX(bO),coY(0) ,

coX(bl),coY(0),paintl);

// escribe contenidos de sharedpreferences int i i = 0;

Page 290: Android
Page 291: Android

262 ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVII ISA IRAVf S DF EJEMPLOS

for (int i=0;i<2;i++){ for (int

j=0;j<2;j++){

texto="R"+i+"="+Rdelta[i] [j];

canvas.drawText(texto,

xl/2, yO/2+20*(ii+1), paint);

i i + + ;

texto="LaM+i+j+"="+lambda[i][j];

canvas.drawText(texto,

xl/2, y0/2+20*(ii+1), paint)

i i + + ;

}

}

}

int coX(double b){

double xdouble=x0+(xl-xO)*(b-bO)/(bl-bO); return

(int) xdouble; }

int coY(double e){

double ddouble=y0+(yl-yO)*(e-eO)/(el-eO) ; re turn

(int) ddoub1e; }

@Override

public void run() {

// Comienza buscando el minimo con paso=l double

paso=l; int dt=50; bmin=l;

emin=energia(bmin); double resolucion=0.01;

while(paso>resolucion){ minimiza(paso);

paso=paso/2.0; texto2="paso="+paso;

postlnvalidate() ; try{ Thread.sleep(dt);}

catch(InterruptedException e){;}

}

texto3="MINIMO ENCONTRADO!"; postlnvalidate() ; }

}

void minimiza(double paso){ boolean

found=false;

Page 292: Android

Mil II'1 ill) I'KOGRAMACIÓN 01 DISPOSITIVOS MÓVIU í; A TRAVÉS D£ I Jl Ml»l QS 263

while(!found){ double braas=bmin+paso; double

bmenos=bmin-paso; double emenos=energia (bínenos] ;

double emas=energia(bmas); if(emenos<emin){

bmin=bmenos; emin=emenos;

}else if(emas<emin){ bmin=bmas; emin=emas;

}else

found=true; }

}

double energia(double b){ final

double hbarc=197.3; final

double mc2=93 9;

double sq2pi=Math.sgrt(2./Math.PI);

double hbc2mc2=hbarc*hbarc/mc2;

double alfa=l/b;

double alfa2=alfa*alfa;

double alfa3=alfa2*alfa;

double factor=sg2pi*6.*hbc2mc2*alfa3;

cinética =9.0/4.*hbc2mc2*alfa2; potencial=0.;

double r,r2,exponente,exponencial,lambdaMedio;

for (int i=0;i<2;i++){ for (int j=0 ; j<2;j+ + ){

r=Rdelta [i] [j] ; r2=r*r;

exponente=-alfa2*r2/2.0;

exponencial=Math.exp(exponente);

lambdaMedio=lambda[i] [j]/2.;

potencial=

potencial+factor*lambdaMedio*r2*exponencial; }}

double energy=cinetica+potencial? return energy; }

void leerPreferencias(){

SharedPreferences misDatos

= getSharedPreferences("preferencias",0);

lambda[0] [0]=misDatos.getFloat

<"lambda00",0) lambda[0]

[1]=misDatos.getFloat("lambda01",0) lambda[1]

[0]=misDatos.getFIoat("lambda10",0)

lambda[1][1]=misDatos.getFloat("lambdall",0)

Rdelta[0] [0]=misDatos.getFloat("R00" , 0)

Rdelta[0] [1]=misDatos.getFloat("R01" , 0)

Rdelta[1] [0]=misDatos.getFloat("R10",0)

Rdelta[1][1]=misDatos.getFloat("Rll",0)

Page 293: Android

ANDROID: PROGRAMACIÓN DE DISPOSITIVOS MÓVIII S A TRAVÉS DE EJEMPLOS 264

// formatear un numero con varias cifras

String format(double x, int cifras){

String cadena=""+x;

if (cadena. length.() <=cifras) return

cadena; if(x<0) cifras=cifras+l; return

cadena.substring(0,cifras); }

Figura C.6. Cálculo de la energía del núcleo de Hello-4.

Esta actividad dibuja la energía cinética (curva superior, positiva), energía potencial

(curva inferior, negativa) y energía total (curva intermedia) del helio en función del radio b

(en fm). El mínimo se encuentra variando este parámetro en el método minimiza

(paso) con un paso inicial, que se va reduciendo a la mitad en el método run() hasta

que se alcanza la resolución buscada. El resultado se ve en la figura C.6. El valor del

mínimo encontrado en el ejemplo de la figura es de:

E =-28.488 MeV

muy próximo al valor experimental.

La aplicación completa y el código fuente pueden descargarse de la página web:

http://www.ugr.es/~amaro/android

El lector puede ejecutar esta aplicación introduciendo distintos valores iniciales para los

lidia 22:39 I Energia del He4

^ Energia del Helio-4

40 30 \ MINIMO ENCONTRAD 1 \

bmln=1.1718 [ \ Emin=-28.488

3:

20 I x

10 0 I

-10 . I >—'

-20 -30

V/

-40 / • i /

-50 -60 -70 -80 -90 -100

R0=1.631100058555603 La00=-0.06270000338554382 R0=1.631100058555603 LaOI =0.5055000185966492 / Rl =0.6812999844551086

Lai0=-0.8208000063896179 R1 =1.625599980354309 La11=-0.6615999937057495

-110 /

-120

-130 • \rJ

-140

-150

12 3 4 5

Page 294: Android

I'KOORAMACIÓN DE DISPOSITIVOS MÓVILES A TRAVÉS DE EJEMPLOS 265

parámetros, especialmente la energía máxima, la tolerancia y la resolución, para ajustar

distintos potenciales y con ellos recalcular la energía del helio.

BIBLIOGRAFÍA

Ableson, Frank, Sen, Robi, King, Chris (2011) Android in Action. Manning

Publications Co.

Alonso, Marcelo y Finn, Edward J. (1976) Fisica Vo¡ I: Mecánica. Fondo Educativo

Interamericano.

Burnette Ed. (2008) Hello, Android. Introducing Google's Mobile Development Platform.

The Pragmatic Bookshelf.

DiMarzio, J. F. (2008) Android. A Programmer's Guide. The McGraw-Hill Companies.

Felker, Donn and Dobbs, Joshua (2011) Android Application Development For Dummies.

Wiley Publishing, Inc.

Gironés, Jesús Tomás (2011) El Gran Libro de Android. Marcombo.

Hashimi, Sayed Y., Komatineni, Satya and MacLean, Dave (2010) Por Android 2. Apress.

James Steele, Nelson To. (2011) The Android Developer's Cookbook, Building Applications

with the Android SDK. Pearson Education, Inc.

Lauren Darcey, Shane Conder. (2010) Sams Teach Yourself Android Application

Development in 24 Hours. Sams publishing.

Meier, Reto (2010) Professional Android 2 Application Development. Wiley Publishing, Inc.

Murphy, Mark L. (2010) Beginning Android 2. Apress.

' .hawn Van Every (2009) Pro Android Media. Developing Graphics, Music, Video, nnd Rich

Media Apps for Smartphones and Tablets. Apress.

Wtil-Meng Lee. (2011) Beginning Android Application Development. Wrox I ’mgrammer to

Programmer. John Wiley & Sons.• Abrir el explorador de archivos del proyectol.

• Vuelve a la ventana Import Projects con una lista de los proyectos a importar.

Comprobar que el nuestro está marcado y pulsar Finish.