Programación Java - David Bueno Vallejo

Anuncio
Master Universitario en Informática
Aplicada a las Telecomunicaciones Móviles
Programación Java
J2ME: Java para dispositivos móviles
Febrero 2006
David Bueno Vallejo
Plan
•
•
•
•
•
•
•
•
•
Introducció
Introducción
Instalació
Instalación
Primer Programa
Interfaz de Usuario en J2ME
– Commands
– Screen (Alertas, formularios, imá
imágenes, choicegroup,
choicegroup, ticker)
ticker)
– GameCanvas (lectura de teclado, dibujar en pantalla, sprites,
sprites,
tiledLayer,
tiledLayer, tiledManager,
tiledManager, scroll,
scroll, colisiones)
RMS
HTTP
Vibració
Vibración e Iluminació
Iluminación
Otros: bluetooth/
bluetooth/obex,
obex, servicios Web, Grá
Gráficos 3D,
sonido y mú
música
Referencias
2
1
Introducción
• Se
•
llama J2ME (Java Micro Edition)
Edition) a las
implementaciones de Java par dispositivos mó
móviles
Hay varias implementaciones dependiendo del tipo de
dispositivo
Teléfonos, PALM, Blackberry
PDAs Pocket PC
Blackberry
CLDC y MIDP
Personal Java (jdk 1.22)
API propia
• En este tema se ve la implementació
implementación relacionada con
Telé
Teléfonos Mó
Móviles, PALM y Blackberry (API MIDP)
3
Introducción
El universo de J2ME.
Imagen de [Knudsen2003]
4
2
Introducción
Componentes software de MIDP.
Imagen de [Knudsen2003]
5
Instalación
• Java Development Kit (JDK)
Descripció
Descripción: Entorno de desarrollo de java para PC. Versió
Versión 1.4.2 o
superior (ú
(última 1.5 y 1.6 Beta)
Descarga: http://java.sun.com/j2se/downloads.html
j2sdkj2sdk-1_4_21_4_2-windowswindows-i586.exe
i586.exe y j2sdkj2sdk-1_4_21_4_2-doc.zip (docs)
docs)
Instalació
Instalación:
• Ejecutar el instalador y seleccionar la carpeta por defecto. P.ej:
P.ej:
c:\
c:\jsdk1.4.2
jsdk1.4.2
• Descomprimir la documentació
documentación en esa carpeta
• Actualizar la variable de entorno PATH=c:\
PATH=c:\jsdk1.4.2
jsdk1.4.2\\bin\
bin\
6
3
Instalación
• J2ME Sun Java Wireless Toolkit
Descripció
Descripción: Entorno para compilar y generar .jar
.jar y .jad
.jad incluye
emuladores
Descarga:
http://java.sun.com/products/sjwtoolkit/download
http://java.sun.com/products/sjwtoolkit/download--2_3.html
sun_java_wireless_toolkitsun_java_wireless_toolkit-2_32_3-betabeta-windows.exe
(Admite bluetooth,
,
multimedia,
API
3D, posicionamiento,…
bluetooth
posicionamiento,…)
Instalació
Instalación:
• Ejecutar el instalador y seleccionar destino: c:\
c:\WTK23
7
Primer Programa: Hola Mundo
• A continuació
continuación se va a realizar el primer programa:
HolaMundo
• Primero se compilará
compilará y ejecutará
ejecutará en el PC en un
emulador
• Despué
Después se enviará
enviará al mó
móvil y se ejecutará
ejecutará en él.
• Los pasos son los siguientes:
1. Con un editor de texto escribir el programa de la
transparencia
siguiente.
Guardarlo
como
HolaMundo.java
8
4
Primer Programa: Código y explicación
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVHolaMundo extends MIDlet implements CommandListener {
private Display pantalla ;
private TextBox texto1 ;
private Command salir;
public DBVHolaMundo() {
pantalla = Display.getDisplay(this); // Devuelve un manejador de la pantalla
salir = new Command("Salir", Command.SCREEN, 1); // Crea un nuevo comando para Salir
texto1 = new TextBox("Hola Mundo", "Mi primer MIDlet", 40, 0); // Crea un cuadro de texto
texto1 .addCommand(salir); // Añade el comando al cuadro de texto
texto1 .setCommandListener(this); // Indica que la gestión de evento se hace en esta clase
}
public void startApp() { // Se ejecuta al comenzar la aplicación
pantalla .setCurrent(texto1); // Muestra en la pantalla el texto y el comando
}
public void pauseApp() { } // Se ejecuta si se interrumpe la aplicación
public void destroyApp(boolean unconditional) { } // Se ejecuta al terminar
public void commandAction(Command c, Displayable displayable) { // Gestiona los eventos
if (c == salir) { // Si el evento es pulsar el botón salir, termina
destroyApp(false);
notifyDestroyed();
}
}
}
9
Primer Programa: Proyecto
2. Abrir el programa Ktoolbar (c:\
(c:\j2me\
j2me\WTK21\
WTK21\bin)
bin)
1. Seleccionar New Project
•Esto crea la siguiente estructura en c:\
c:\j2me\
j2me\WTK23\
WTK23\apps\
apps\HolaMundo
•Hay que guardar en src el có
código (.java) (HolaMundo.java
(HolaMundo.java anterior)
•En classes se guardará
guardarán los (.class
(.class))
•En bin se guardará
guardarán los ficheros que hay que enviar al mó
móvil (.jad
(.jad y .jar
.jar))
10
5
Primer Programa: Generación
2. Ktoolbar
2. Compilar/Enlazar el có
código con el botó
botón Build
11
Primer Programa: Ejecución en emulador
2. Ktoolbar
3. Seleccionar el emulador en el desplegable Device
4. Ejecutar mediante el botó
botón Run
•Siguiendo estos pasos se pueden probar todos los
programas que se realicen en el emulador. El siguiente paso
será
será pasar el programa al telé
teléfono
12
6
Primer Programa: Preparación para el móvil
2. Ktoolbar
5. Editar datos del proyecto: (Project
(Project Settings Required)
Required)
Nombre del
proveedor
Nombre del perfil. Por
defecto es MIDP-2.0. Si
el teléfono sólo es
compatible con MIDP-1.0
es IMPRESCINDIBLE
cambiarlo. (Por ejemplo,
para el Nokia 3650)
6. Generar los fichero .jad
.jad y .jar
.jar:: Project Package Create Package
7. Los 2 ficheros a enviar al telé
teléfono son: HolaMundo.jad
HolaMundo.jar,
HolaMundo.jar, guardados en c:\
c:\j2me\
j2me\WTK21\
WTK21\apps\
apps\HolaMundo\
HolaMundo\bin
y
13
Primer Programa: Envío al teléfono bluetooth
3. Enviar los 2 ficheros al telé
teléfono por bluetooth
1. Instalar dispositivo bluetooth en PC (Como ejemplo se
explicará
explicarán los pasos para el dispositivo Bluetooth 3Com)
2. Arrancar en el PC el Bluetooth Connection Manager (o
programa similar que traiga el Bluetooth)
Bluetooth)
3. Encender en el telé
teléfono el bluetooth (Normalmente:
Conexiones Bluetooth Activar)
Activar)
4. Si todo va bien ☺ el PC verá
verá el
telé
teléfono. Con el botó
botón derecho
sobre el icono seleccionar enviar
archivo
5. Seleccionar los 2 ficheros
HolaMundo.jad y HolaMundo.jar
y enviarlos al telé
teléfono
14
7
Primer Programa: Envío al teléfono bluetooth
3. Enviar los 2 ficheros al telé
teléfono por bluetooth
6. En el telé
teléfono se recibirá
recibirán 2 mensajes. Uno por cada fichero.
Aceptarlos.
7. En el menú
menú mensajes Buzon de entrada del telé
teléfono Abrir el
fichero HolaMundo.jad.
HolaMundo.jad. Aparecerá
Aparecerá un mensaje como:
¿Instalar HolaMundo 1.0 suministrado por David Bueno?
8. Donde el nombre de la aplicació
aplicación, la versió
versión y el suministrador
son los que se hayan seleccionado al editar los datos del
proyecto
9. Si la instalació
instalación es correcta, se podrá
podrá ejecutar la aplicació
aplicación en
el menú
ú
del
telé
é
fono
Aplicaciones
Hola
Mundo
men
tel
15
Primer Programa: Envío al teléfono infrarrojos
• NOKIA:
– Si se pasan los ficheros directamente no pueden ejecutarse
– Es necesario descargar el instalar la aplicació
aplicación: NOKIA PC Suite
– Se puede descargar de http://www.nokia.es
http://www.nokia.es (seleccionando el
teé
teéfono y las aplicaciones para éste)
16
8
Primer Programa: Envío al teléfono serie/usb
• SIEMENS:
– Conectar el telé
teléfono al cable serie o usb
– Es necesario descargar el instalar la aplicació
aplicación: Siemens Data
Suite
– Se puede descargar de http://www.siemens
http://www.siemens--mobile.com
(seleccionando el teé
teéfono y las aplicaciones para éste)
– Despué
Después aparecerá
aparecerá el telé
teléfono como una carpeta y habrá
habrá que
copiar los ficheros .jad
.jad y .jar
.jar en la carpeta /java/jam
/java/jam//HolaMundo
17
Primer Programa: Envío al teléfono por Web
• Se necesita un servidor Web accesible desde el exterior
– Dentro de la UMA es necesario tener abierto el puerto 80 en los
servicios centrales de Informá
Informática
• En el servidor web habrá
habrá que configurar 2 tipos MIME:
text/vnd.sun.j2me.app-descriptor
application/java-archive
jad
jar
• En algunos mó
móviles será
será suficiente con descargar el .jar
.jar
• En lo que no sea suficiente, habrá
habrá que descargar el .jad
.jad
pero modificando la linea URL de la siguiente forma:
Antes
MIDlet-Jar-URL: DBVMijar.jar
Después
MIDlet-Jar-URL: http://miweb.com/DBVMijar.jar
18
9
Interfaz de Usuario en J2ME
• Hay 3 formas como un usuario puede interactuar con las
aplicaciones
– Command.
Command.- Son acciones que se asocian a los botones que el
usuario pulsa en el dispositivo para realizar alguna tarea
– Screen.
Screen.- Interfaz de alto nivel con alertas, formularios, cuadros
de texto, radiobuttons,
radiobuttons, checkbox,
checkbox, listas similares a las utilizadas
en HTML
– Canvas.
Canvas.- Interfaz de bajo nivel en la que el usuario trabaja a
nivel de pixel,
pixel, utilizadas para aplicaciones como juegos
19
IU: Display Class
• La pantalla del dispositivo se asocia a un objeto Display
• Un MIDlet está
está asociado a un único objeto Display
• En este objeto se pueden mostrar objetos de tipo
Displayable (Screen y Canvas)
Canvas)
Screen
List
Form
TextBox
Displayable
Canvas
Javax.microedition.lcdui
Alert
GameCanvas
Javax.microedition.lcdui.game
20
10
IU: Display Class
• La referencia al objeto Display se obtiene normalmente
en el constructor o en startApp()
startApp() aunque se declare
como atributo de la clase
public class NombreClase… {
Private Display pantalla;
Public void startApp() {
pantalla= Display.getDisplay(this);
}
}
• Se pueden tener varios objetos de tipo Displayable pero
sólo uno (aunque puede ser compuesto como un form)
form)
que se muestre en el Display.
Display. Para asociarlo a la pantalla
se utiliza setCurrent y se puede cambiar cuando se
quiera TextBox cuadrotexto;
cuadrotexto=new TextBox(“titulo”,”contenido”,30,TextField.ANY);
pantalla.setCurrent(cuadrotexto);
21
IU: Command Class
• Son acciones que se asocian a botones del dispositivo.
Los posibles tipos son:
Command.BACK
Command.CANCEL
Command.EXIT
Command.HELP
Command.ITEM
Command.OK
Command.SCREEN
Command.STOP
Ir a la pantalla anterior
Cancelar la operación actual
Terminar la aplicación
Mostrar ayuda
Asocia una acción a un elemento de la pantalla
Aceptar
Acción genérica para comandos específicos de la aplicación
Para parar la operación actual
• Aunque existan todos esos tipos en realidad no influye el
•
hecho de elegir uno u otro salvo en la posició
posición en la que
aparecerá
aparecerá en pantalla
Para crear una nuevo objeto Command 3 pará
parámetros
(texto, tipo, prioridad [0 es la má
máxima]):
Command miok;
Miok=new Command(“Aceptar”, Command.OK,0)
22
11
IU: Command Class
• Para añ
añadir el Command al display
Pantalla.addCommand(miok);
• Para asociar una acció
acción a un Command hay que implementar la
interfaz CommandListener
public class MiClase extends MIDlet implements CommandListener {
…
public void commandAction(Command c, Displayable displayable) {
if (c == quitar) {
destroyApp(false);
notifyDestroyed();
} else if (c==miok) {
…
}
}
• Como ejemplo un programa con 2 cuadros de texto, uno de los
cuales es una ayuda, en total hay 3 command asociados a las
operaciones de salir de la aplicació
aplicación, ayuda y volver (salir de la
ayuda)
23
Programa: DBVCommands
24
12
Programa: DBVCommands
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVCommands extends MIDlet implements CommandListener {
private Display pantalla ;
private TextBox tintro,tayuda ;
private Command salir, ayuda, volver;
public DBVCommands () {
pantalla = Display.getDisplay(this);
// Preparando la pantalla principal
tintro = new TextBox("Mis Comandos", "Puedes salir o elegir ayuda", 40, 0);
salir = new Command("Salir", Command.EXIT, 0);
ayuda = new Command("Ayuda",Command.HELP,1);
tintro .addCommand(salir);
tintro.addCommand(ayuda);
tintro.setCommandListener(this);
// Preparando pantalla de ayuda
tayuda = new TextBox("Ayuda", "Para salir debe regresar :-)", 40, 0);
volver=new Command("Volver",Command.BACK,1);
tayuda.addCommand(volver);
tayuda.setCommandListener(this);
}
public void startApp() {
pantalla .setCurrent(tintro);
}
public void pauseApp() {
}
25
Programa: DBVCommands
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable displayable) {
if (c == salir) {
destroyApp(false);
notifyDestroyed();
} else if (c==ayuda) {
pantalla.setCurrent(tayuda);
} else if (c==volver) {
pantalla.setCurrent(tintro);
}
}
}
26
13
IU: Screen:Alertas
• Las alertas son cuadros de dialogo que avisan al usuario
•
de algú
algún problema, confirman alguna acció
acción del usuario,
o muestran un recordatorio en la pantalla
Hay varios tipos predefinidos
AlertType.ALARM, AlertType.CONFIRMATION, AlertType.ERROR, AlertType.INFO, AlertType.WARNING
• El constructor de la alerta tiene 4 pará
parámetros: tí
título,
texto, imagen, tipo
Alert mialerta;
mialerta=new Alert(“Titulo”,”Texto de la alerta”, null, AlertType.CONFIRMATION);
• Las alertas pueden ser:
– Modales. Permanecen hasta que el usuario realce alguna acció
acción
mialerta.setTimeout(Alert.FOREVER);
– Temporales. Se cierran pasado algunos segundos
mialerta.setTimeout(5000); // Espera 5 segundos
27
IU: Screen:Alertas
• Por defecto aparecen acciones ‘Command’
Command’ asociadas a
•
las alertas, aunque pueden definirse nuevas con
addCommand para personalizar los resultados
Para mostrar la alerta se cambia el display como siempre
pantalla.setCurrent(mialerta);
• Cuando la alerta se cierra se vuelve a la pantalla anterior
• Si se quiere que al cerrar la alerta se pase a otra
pantalla se utiliza un segundo pará
parámetro de setCurrent
pantalla.setCurrent(mialerta,siguientepantalla);
28
14
IU: Screen:Formularios
• Los formularios permiten recoger datos del usuario
• En un formulario se pueden incluir derivados de la clase
Item
– ChoiceGroup,
ChoiceGroup, CustomItem,
CustomItem, DateField,
DateField, Gauge, ImageItem,
ImageItem,
Spacer, StringItem,
StringItem, TextField
Form miform;
miform=new Form(“Título");
• Se añ
añaden elementos al formulario con Append
TextField usuario;
usuario=new TextField("usuario","",10,TextField.ANY);
miform.append(usuario);
• A continuació
continuación un ejemplo de un formulario que pide un
nombre de usuario y una contraseñ
contraseña. Utiliza una alerta
para mostrar el nombre leí
leído
29
Programa: DBVAcceso
30
15
Programa: DBVAcceso
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVAcceso extends MIDlet implements CommandListener {
private Display pantalla ;
private Form flogin ;
private Alert confirmacion;
private TextField usuario;
private TextField passwd;
private Command salir,aceptar;
private String cad;
public DBVAcceso () {
pantalla = Display.getDisplay(this);
// Preparando la pantalla principal
flogin=new Form("Control Acceso");
usuario=new TextField("usuario","",10,TextField.ANY);
passwd=new TextField("contraseña","",10,TextField.ANY|TextField.PASSWORD);
aceptar = new Command("Enviar", Command.OK, 0);
salir = new Command("Salir", Command.EXIT, 0);
flogin.append(usuario);
flogin.append(passwd);
flogin.addCommand(aceptar);
flogin.addCommand(salir);
flogin.setCommandListener(this);
// Alerta de confirmacion de datos
confirmacion= new Alert ("Confirmación","", null, AlertType.CONFIRMATION);
confirmacion.setTimeout(Alert.FOREVER);
}
31
Programa: DBVAcceso
}
public void startApp() {
pantalla .setCurrent(flogin);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable displayable) {
if (c == salir) {
destroyApp(false);
notifyDestroyed();
} else if (c==aceptar) {
cad="Bienvenido al sistema " + this.usuario.getString();
confirmacion.setString(cad);
pantalla.setCurrent(confirmacion);
}
}
32
16
IU: Screen: Formularios: Imágenes
• Para trabajar con imá
imágenes hay que hacerlo en formato
•
•
•
.png
El programa Paint de Windows guarda cualquier imagen
en este formato
Hay que guardar las imá
imágenes en la carpeta res que
genera J2ME Wireless Toolkit (WT) al crear un proyecto
La referencia a la imagen se hace con esta carpeta como
raiz /.
– Es decir, una imagen dentro de esta carpeta se referencia
“/imagen.png”
imagen.png”
– Una
imagen
en
res/imagenes
se
referencia
res/imagenes
“/imá
/imágenes/imagen.png
genes/imagen.png””
• Las imá
imágenes se añ
añadirá
adirán al fichero .jar
.jar (lo hace WT)
33
IU: Screen: Formularios: Imágenes
• Una objeto imagen se declara y crea:
Image mimagen;
mimagen=Image.createImage("/nombre.png");
catch por si no
• Es importante crear la imagen en un try..
try..catch
se encuentra
try { // Ejemplo de imagen en formulario
mimagen=Image.createImage("/nombre.png");
} catch (java.io.IOException error) {
Alert alerta=new Alert("Error","No se pueda cargar la imagen",null,AlertType.ERROR);
alerta.setTimeout(5000);
pantalla.setCurrent(alerta);
}
34
17
IU: Screen: Formularios: Imágenes
• Para usarla en una alerta se pondrá
pondrá como 3er pará
parámetro
en el constructor de la alerta
intro=new Alert(“Titulo", “Texto...",mimagen,AlertType.INFO);
• Para usarla en un formulario hay que crear un
ImageItem
imagenit=new ImageItem(null,mimagen,ImageItem.LAYOUT_CENTER,"Davilin");
principal.append(imagenit);
• En el siguiente ejemplo se carga una imagen en una
alerta que dura 3 segundos y despué
después se muestra un
formulario con otra imagen
35
Programa: DBVImagenes
3 segs.
36
18
Programa: DBVImagenes (1/3)
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVImagenes extends MIDlet implements CommandListener {
private Alert intro;
private Display pantalla ;
private Form principal ;
private Command salir;
private Image imagen2,imagen1;
private ImageItem imagenit;
private String cad;
public DBVImagenes() {
pantalla = Display.getDisplay(this);
// Preparando la pantalla principal
principal=new Form("Imagenes");
salir = new Command("Salir", Command.EXIT, 0);
principal.addCommand(salir);
principal.setCommandListener(this);
...
37
Programa: DBVImagenes (2/3)
// Creación de la imagen
try { // Ejemplo de imagen en formulario
imagen2=Image.createImage("/david2.png");
imagenit=new ImageItem(null,imagen2,ImageItem.LAYOUT_CENTER,"Davilin");
principal.append(imagenit);
} catch (java.io.IOException error) {
Alert alerta=new Alert("Error","No se pueda cargar la imagen",null,AlertType.ERROR);
alerta.setTimeout(5000);
pantalla.setCurrent(alerta);
}
// Preparacion de la pantalla de bienvenida
try { // Ejemplo de imagen en alerta
imagen1=Image.createImage("/david1.png");
intro=new Alert("Bienvenido", "Bienvenido a mi programa\nCargando...",imagen1,AlertType.INFO);
intro.setTimeout(3000);
} catch (java.io.IOException error) {
Alert alerta=new Alert("Error","No se pueda cargar la imagen",null,AlertType.ERROR);
alerta.setTimeout(5000);
pantalla.setCurrent(alerta);
}
}
38
19
Programa: DBVImagenes (3/3)
public void startApp() {
pantalla.setCurrent(intro,principal);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable displayable) {
if (c == salir) {
destroyApp(false);
notifyDestroyed();
}
}
}
39
IU: Screen:Formularios:ChoiceGroup
• Permite crear botones de tipo radio y checkbox.
checkbox.
• Hay 3 tipos
Choice.EXCLUSIVE
Choice.MULTIPLE
Choice.IMPLICIT
Botones Radio
Botones Checkbox
Menú
• Para crear las selecciones:
miradio=new ChoiceGroup("Mi Radio",Choice.EXCLUSIVE);
miradio.append("opcion1",null); // 2º parámetro es una imagen
miradio.append("opcion2",null);
principal.append(miradio);
• Para procesar elemento seleccionado en radio:
i=miradio.getSelectedIndex();
mensaje=new StringItem("",miradio.getString(i)+"\n");
• Para procesar elementos seleccionados en check:
for (i=0;i<micheck.size();i++) {
if (micheck.isSelected(i)){
mensaje=new StringItem("",micheck.getString(i)+"\n");
principal.append(mensaje);
}
}
40
20
Programa: DBVChoice
41
Programa: DBVChoice (1/3)
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVChoice extends MIDlet implements CommandListener {
private ChoiceGroup miradio, micheck, milista;
private Command procesaradio, procesacheck, salir;
private Display pantalla ;
private Form principal ;
private String cad;
public DBVChoice() {
pantalla = Display.getDisplay(this);
// Preparando la pantalla principal
principal=new Form("Imagenes");
salir = new Command("Salir", Command.EXIT, 0);
procesaradio = new Command("Ver Radio", Command.SCREEN, 0);
procesacheck = new Command("Ver Check", Command.SCREEN, 0);
principal.addCommand(salir);
principal.addCommand(procesaradio);
principal.addCommand(procesacheck);
principal.setCommandListener(this);
// Radio
miradio=new ChoiceGroup("Mi Radio",Choice.EXCLUSIVE);
miradio.append("opcion1",null);
miradio.append("opcion2",null);
principal.append(miradio);
42
21
Programa: DBVChoice (2/3)
// Checkbox
micheck=new ChoiceGroup("Mi Check",Choice.MULTIPLE);
micheck.append("check1",null);
micheck.append("check2",null);
principal.append(micheck);
}
public void startApp() {
pantalla.setCurrent(principal);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable displayable) {
int i;
StringItem mensaje;
if (c == salir) {
destroyApp(false);
notifyDestroyed();
43
Programa: DBVChoice (3/3)
}
}
} else if (c==procesaradio) {
i=miradio.getSelectedIndex();
mensaje=new StringItem("",miradio.getString(i)+"\n");
principal.append(mensaje);
} else if (c==procesacheck){
for (i=0;i<micheck.size();i++) {
if (micheck.isSelected(i)){
mensaje=new StringItem("",micheck.getString(i)+"\n");
principal.append(mensaje);
}
}
}
44
22
IU: Screen:Ticker
•
•
•
Permite mostrar un scroll horizontal.
Se puede asociar a cualquier clase derivada de Screen
Para crearlo y asociarlo, por ejemplo a un formulario
cad=new String("Soy un texto que se desplaza por la pantalla");
miticker=new Ticker(cad);
principal.setTicker(miticker);
• Para modificar su valor
miticker.setString(“Texto nuevo del ticker");
• A continuació
continuación un ejemplo que tiene ticker y un radio y
muestra en el ticker informació
información adicional sobre el
significado del radio
45
Programa: DBVTicker
46
23
Programa: DBVTicker (1/2)
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVTicker extends MIDlet implements CommandListener, ItemStateListener {
private ChoiceGroup miradio;
private Command salir;
private Display pantalla ;
private Form principal ;
private String cad;
private Ticker miticker;
public DBVTicker() {
pantalla = Display.getDisplay(this);
// Preparando el ticker
cad=new String("Soy un texto que se desplaza por la pantalla");
miticker=new Ticker(cad);
// Preparando la pantalla principal
principal=new Form("Formulario");
principal.setTicker(miticker); // Se asocia el ticker al formulario
salir = new Command("Salir", Command.EXIT, 0);
principal.addCommand(salir);
principal.setCommandListener(this);
// Radio
miradio=new ChoiceGroup("Mi Radio",Choice.EXCLUSIVE);
miradio.append("opcion1",null);
miradio.append("opcion2",null);
principal.append(miradio);
principal.setItemStateListener(this); // Listener que se llama si cambia el radio
}
47
Programa: DBVTicker (2/2)
public void startApp() {
pantalla.setCurrent(principal);
}
public void pauseApp() { }
public void destroyApp(boolean unconditional) { }
public void commandAction(Command c, Displayable displayable) {
if (c == salir) {
destroyApp(false);
notifyDestroyed();
}
}
public void itemStateChanged(Item item) { // Listener de RadioButton
int i;
if (item==miradio) {
i=miradio.getSelectedIndex();
if (i==0) { // Dependiendo del radio elegido se cambia en texto del ticker
miticker.setString("La Opcion primera es muy buena");
} else {
miticker.setString("Elegir la 2 te dara buena suerte");
}
} else {
miticker.setString("no se ha elegido miradio");
}
}
}
48
24
IU: Canvas y GameCanvas
• Canvas es la clase bá
básica para trabajar con la pantalla a bajo nivel:
•
•
•
•
Dibujar pixels,
pixels, lineas,
lineas, figuras, etc.
GameCanvas mejora Canvas incluyendo carga de Imá
Imágenes, Sprites,
Sprites,
TiledLayers y un mejor control de los botones del telé
teléfono
Estas clases son la utilizada para hacer los juegos Java que han
hecho tan populares los mó
móviles
La programació
programación de juegos se convierte en algo mucho má
más sencillo
que en cualquier otra plataforma
El programador no tiene que preocuparse de problemas clá
clásicos
como:
– Refresco de pantalla, doble buffering,
buffering, colisiones, gestió
gestión de capas o
mapas
• Las clases anteriores se encargan de todo el ‘trabajo sucio’
sucio’
49
IU: GameCanvas
• Las aplicaciones no suelen utilizar directamente
•
•
GameCanvas,
GameCanvas, sino que heredan de esta clase
Como mínimo hay dos clases:
clases: Una para el midlet
principal y otra para la clase que hereda de GameCanvas
El juego suele ejecutarse en una hebra independiente
con el siguiente bucle principal
// Dentro de la clase que hereda de GameCanvas
public void run() {
Graphics g = getGraphics();
while (jugando == true) {
colision(); // Controla colisiones
leeTeclado(); // Lee acciones del usuario
dibujaPantalla(g); // Dibuja la escena actual
try { Thread.sleep(retraso); } // Retraso entre iteraciones
catch (InterruptedException ie) {}
}
}
50
25
IU: GameCanvas: Lectura de teclado
• Para leer de teclado es necesario leer el estado de las
teclas con:
int keyStates = getKeyStates();
• Hay varias constantes en GameCanvas para cada tecla:
tecla:
DOWN_PRESSED, LEFT_PRESSED, RIGHT_PRESSED, UP_PRESSED, FIRE_PRESSED,
GAME_A_PRESSED, GAME_B_PRESSED, GAME_C_PRESSED, GAME_D_PRESSED
// Metodo para gestionar el teclado
private void leeTeclado() {
int keyStates = getKeyStates();
// Izquierda
if ((keyStates & LEFT_PRESSED) != 0) {
// Acciones cuando pulse izquierda
}
// Derecha
if ((keyStates & RIGHT_PRESSED) !=0 ) {
// Acciones cuando pulse izquierda
}
…
}
51
IU: GameCanvas: Dibujar en la pantalla
• Suele haber un mé
método en el que se realiza todo el
•
refresco de pantalla: imá
imágenes, lineas,
lineas, sprites,
sprites, fondos…
fondos…
Para hacer cualquier dibujo se utiliza un objeto Graphics
que puede obtenerse dentro de GameCanvas con
Graphics g=getGraphics();
• Algunos de las acciones posibles:
g.setColor(0xbbecf3); // Selecciona el color de lo siguiente que se dibuje
g.fillRect(0, 0, ancho, alto); // Dibuja un rectangulo relleno con ese color
g.setColor(0x0000ff);
g.drawLine(0,100,200,0); // Dibuja una línea
// Para escribir un texto, se indican las coordenadas de la pantalla y la
// alineación del texto en la pantalla
g.drawString(“Hola", anchop, altop, Graphics.RIGHT | Graphics.BOTTOM);
52
26
IU: GameCanvas: Sprites
•
•
•
La clase Sprite maneja los personajes del juego
Carga del Sprite en un fichero con 5 posiciones
Se indica el tamañ
tamaño de un elemento
24
Sprite babosin;
Image imagen;
imagen = Image.createImage("/babosin.png");
babosin = new Sprite (image,16,24);
0
1
16
2
3
4
24
80
Fichero: babosin.png
53
IU: GameCanvas: Sprites
• Para mostrar el sprite hay que seleccionar la posició
posición de
•
•
pantalla
Tambié
También cual de los frames se va a mostrar
Y có
cómo quiere mostrarse: Su posició
posición original, invertida
o girada en x grados
Sprite.TRANS_NONE,
Sprite.TRANS_MIRROR,
Sprite.TRANS_ROT90,
Sprite.TRANS_ROT180,
Sprite.TRANS_ROT270, Sprite.TRANS_MIRROR_ROT90, Sprite.TRANS_MIRROR_ROT180,
Sprite.TRANS_MIRROR_ROT270
• Para dibujar se necesita un Graphics g que puede
obtenerse con: Graphics g = getGraphics();
getGraphics();
babosin.setFrame(3); // Selecciona el frame (4ª imagen de las 5)
babosin.setTransform(Sprite.TRANS_NONE); // Muestra la imagen en su posición original
babosin.setPosition(100,100); // Colocará en la pantalla el sprite en la posición (100,100)
babosin.paint(g); // Dibuja el Sprite.
54
27
Programa: DBVGameCanvas
• Se va a mostrar en un programa los elementos
•
•
•
•
relacionados con GameCanvas vistos hasta este punto
Se dibujaran algunas lílíneas y rectá
rectángulos y se moverá
moverá
un Sprite por la pantalla
Se va a utilizar una clase para el midlet
(DBVGameCanvas),
DBVGameCanvas), que será
será muy similar en todos los
programas que usen GameCanvas
Por otro lado, se va a utilizar una clase que hereda de
GameCanvas (BabosinCanvas)
BabosinCanvas) sobre la que recae la
mayor parte de la acció
acción
Esta última tiene una hebra que es iniciada por la clase
principal
55
Programa: DBVGameCanvas
Cursores
56
28
Programa: DBVGameCanvas (1/2)
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVGameCanvas extends MIDlet implements CommandListener {
private Display display;
private BabosinCanvas babosinCanvas;
private Command salir;
public void startApp() {
try {
display = Display.getDisplay(this);
babosinCanvas= new BabosinCanvas();
babosinCanvas.start(); // Inicia la hebra del canvas
salir = new Command("Salir", Command.EXIT, 0); // Boton para salir
babosinCanvas.addCommand(salir);
babosinCanvas.setCommandListener(this);
display.setCurrent(babosinCanvas);
} catch (Exception ex) {
System.out.println(ex);
}
}
public void pauseApp() { }
57
Programa: DBVGameCanvas (2/2)
public void destroyApp(boolean unconditional) {
if (babosinCanvas != null) {
babosinCanvas.stop(); // Para la hebra del canvas
}
}
}
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
System.gc(); // Llama al recolector de basura
destroyApp(true);
notifyDestroyed();
}
}
58
29
Programa: DBVGameCanvas-BabosinCanvas (1/4)
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
public class BabosinCanvas extends GameCanvas implements Runnable {
private boolean jugando; // Indica que la partida esta en curso
private long retraso;
// Retraso entre cada ciclo
private int babosinX, babosinY; // Coordenadas del personaje
private int ancho;
// Ancho de la pantalla
private int alto;
// Alto de la pantalla
private int posbabosin; // babosin actual del personaje (0-4)
private Sprite babosin; // Sprites del personaje
// Constructor
public BabosinCanvas() throws Exception {
super(true);
ancho = getWidth();
alto = getHeight();
babosinX = ancho / 2;
babosinY = alto / 2;
retraso = 20;
// Carga el personaje principal
Image image = Image.createImage("/babosin.png");
babosin = new Sprite (image,16,24);
}
59
Programa: DBVGameCanvas-BabosinCanvas (2/4)
// Crea y arranca la hebra del juego
public void start() {
jugando = true;
Thread t = new Thread(this);
t.start();
}
public void stop() { jugando = false; }
// Bucle principal del juego
public void run() {
Graphics g = getGraphics();
while (jugando == true) {
leeTeclado(); // Lee acciones del usuario
dibujaPantalla(g); // Dibuja la escena actual
try { Thread.sleep(retraso); }
catch (InterruptedException ie) {}
}
}
60
30
Programa: DBVGameCanvas-BabosinCanvas (3/4)
// Metodo para gestionar el teclado
private void leeTeclado() {
int keyStates = getKeyStates();
if ((keyStates & LEFT_PRESSED) != 0) {// Izquierda
babosinX = Math.max(0, babosinX - 1);
posbabosin=(posbabosin+1)%5;
babosin.setFrame(posbabosin);
babosin.setTransform(Sprite.TRANS_NONE);
}
if ((keyStates & RIGHT_PRESSED) !=0 ) {// Derecha
babosinX = Math.min(ancho-16, babosinX + 1);
posbabosin=(posbabosin+1)%5;
babosin.setFrame(posbabosin);
babosin.setTransform(Sprite.TRANS_MIRROR);
}
if ((keyStates & UP_PRESSED) != 0) {// Arriba
babosinY = Math.max(0, babosinY - 1);
babosin.setFrame(0);
}
if ((keyStates & DOWN_PRESSED) !=0) {// Abajo
babosinY = Math.min(alto-24,babosinY + 1);
babosin.setFrame(4);
}
}
61
Programa: DBVGameCanvas-BabosinCanvas (4/4)
// Dibuja la pantalla
private void dibujaPantalla(Graphics g) {
// lineas montañas
g.setColor(0xbbecf3);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(0x0000ff);
g.drawLine(0,getHeight()/2,getWidth()/2,0);
g.drawLine(getWidth()/2,0,getWidth(),getHeight()/2);
g.setColor(0xf5d58d);
g.drawLine(0,(getHeight()/4)*3,getWidth(),(getHeight()/4)*3);
// dibuja el personaje
babosin.setPosition(babosinX,babosinY);
babosin.paint(g);
}
flushGraphics(); // actualiza la pantalla
}
62
31
IU: GameCanvas: TiledLayer
Deco.png
+
=
Image tileImages = Image.createImage("/deco.png"); // Carga la imagen con los elementos de la pantalla
TiledLayer decorado = new TiledLayer(40,24,tileImages,8,8); // reserva espacio para la capa del decorado
// Selecciona los 40x24 elementos del decorado según su posición en deco.png
// 0 indica que no hay nada en esa posición
int[] map=
{42,41,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,42,41,1,2,
264,264,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,264,
264,264,264,0,0,248,249,250,251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,264,
…
}
// Guarda los elementos del mapa en la posición de pantalla que corresponda
for (int i=0; i < mapa.length; i++) {
int columna = i % 40; // Se divide por el número de elementos de una fila=numero de columnas
int fila = i/40;
decorado.setCell(columna,fila,mapa[i]); // Actualiza 1 a 1 todas las celdas
}
63
IU: GameCanvas: TiledLayer
• Para mover un TiledLayer se utiliza setPosition
decorado.setPosition(decox,decoy);
• Para dibujarlo se puede utilizar el mé
método paint de
TiledLayer o un LayerManager que gestiona todas las
capas
private LayerManager controlcapas; // Declaración del LayerManager
…
controlcapas=new LayerManager(); // Crea el control de capas
…
controlcapas.append(decorado); // Añade cada capa que se quiera controlar
…
Controlcapas.paint(g,0,0); // Dibuja todas las capas controladas a partir de (x,y) en la pantalla
64
32
IU: GameCanvas: TiledLayer+Sprite+Image
+
+
=
// Dibuja la imagen de fondo
g.drawImage(fondo,decox/4,decoy/4,0);
decorado.setPosition(decox,decoy); // Actualiza el decorado
controlcapas.paint(g,0,0); // Pinta el decorado
// Actualiza el personaje
babosin.setPosition(babosinX,babosinY);
babosin.paint(g); // pinta el personaje
65
IU: GameCanvas: Scroll Fondos
TRUCO
• En muchos juegos de plataformas los escenarios pueden
estar a diferentes distancias
• Los escenarios má
más lejanos deben moverse a menor
velocidad que los cercanos para producir un movimiento
real
• Es fá
fácil conseguir ese efecto dá
dándole al primer plano
unas coordenadas (x,y
(x,y)) y a cada plano má
más lejano se le
asignará
/distancia)
asignará un (x/distancia,y
(x/distancia,y/distancia)
• En el ejemplo anterior el fondo se desplaza 4 veces má
más
lentamente que el decorado principal
// Dibuja la imagen de fondo
g.drawImage(fondo,decox/4,decoy/4,0);
66
33
IU: GameCanvas: Colisiones
• Se puede mirar en cada momento si un Sprite choca con
•
otro Sprite, Imagen o TiledLayer
Las colisiones se pueden hacer a nivel de pixel
(pixelLevel=true)
pixelLevel=true) o aproximando la imagen a un
rectangulo (pixelLevel=false)
pixelLevel=false)
// Mira si el sprite babosin choca con la imagen situada en x,y
choca=babosin.collidesWith(imagen,x,y,pixelLevel);
// Mira si el sprite babosin choca con la otro Sprite
choca=babosin.collidesWith(enemigo,pixelLevel);
// Mira si el sprite babosin choca con un tiledLayer
choca=babosin.collidesWith(escenario,pixelLevel);
67
Programa: DBVBabosin
• En el siguiente programa se combina todo lo relacionado
•
•
•
•
con GameCanvas:
GameCanvas: Sprites,
Sprites, Imá
Imágenes, TiledLayer,
TiledLayer,
LayerManager,
LayerManager, Control de Teclado…
Teclado…
Con esto se podrí
podría hacer prá
prácticamente cualquier juego
en 2D
Se va a utilizar para el midlet la misma clase que en
(DBVGameCanvas)
DBVGameCanvas)
Por otro lado, se va a utilizar una clase que hereda de
GameCanvas (BabosinCanvas)
BabosinCanvas) en la que se desarrolla el
juego
El programa carga una imagen de fondo, un tiledLayer y
un sprite y cuando se mueven los cursores, el sprite se
desplaza por el fondo que tambié
también se desplaza,
detectando posibles colisiones
68
34
Programa: DBVBabosin
Con los cursores se
desplaza el personaje,
el escenario y el fondo
69
Programa: DBVBabosin (1/6)
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
public class BabosinCanvas extends GameCanvas implements Runnable {
private boolean jugando; // Indica que la partida esta en curso
private long retraso;
// Retraso entre cada ciclo
private int babosinX, babosinY; // Coordenadas del personaje
private int antx,anty; // Coord. anterior del personaje (para colisiones)
private int decox,decoy; // Coordenadas del decorado
private int antdecox,antdecoy;
private int ancho;
// Ancho de la pantalla
private int alto;
// Alto de la pantalla
private int posbabosin; // sprite actual del personaje (0-4)
private LayerManager controlcapas;
private int ultmov; // Ultimo movimiento: 0 nada 1 izq 2 dch 3 arr 4 aba
private TiledLayer decorado; // Escenario
private boolean cayendo=true;
private Image fondo;
private Sprite babosin; // Sprite del personaje principal
70
35
Programa: DBVBabosin (2/6)
// Constructor
public BabosinCanvas() throws Exception {
// Llama al constructor de GameCanvas, al ser true, desabilita
// el manejo estandar del teclado
super(true);
// Lee las coordedanas del dispositivo
ancho = getWidth();
alto = getHeight();
// Coloca el muñeco en una posición que no choque
babosinX = 100;
babosinY = 30;
// Inicializa las coordenadas del decorado a la esquina sup,izq de la pantalla
decox=0; decoy=0;
// inicializa coordenadas anteriores (para deshacer movimientos si choca)
antdecox=decox; antdecoy=decoy; antx=babosinX; anty=babosinY;
ultmov=0;
retraso = 5;
decorado=iniDecorado(); // Carga e inicializa el decorado
fondo= Image.createImage("/fondo2.png"); // Carga imagen de fondo
controlcapas=new LayerManager(); // Crea el control de capas
controlcapas.append(decorado);
Image image = Image.createImage("/babosin.png"); // Carga el personaje principal
babosin = new Sprite (image,16,24);
} // Fin del constructor
71
Programa: DBVBabosin (3/6)
// Controla las colisiones
private void colision() {
if (!babosin.collidesWith(decorado, false)) {
// Si babosin colisiona con el decorado se vuelve a su estado anterior
decox=antdecox;decoy=antdecoy;
babosinX=antx; babosinY=anty;
}
}
// Dibuja todo
private void dibujaPantalla(Graphics g) {
g.setColor(0xffffff); // Dibuja un fondo blanco
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(fondo,decox/4,decoy/4,0); // Dibuja la imagen de fondo
decorado.setPosition(decox,decoy); // Actualiza el decorado
controlcapas.paint(g,0,0); // Pinta el decorado
babosin.setPosition(babosinX,babosinY); // Actualiza el personaje
babosin.paint(g); // pinta el personaje
g.setColor(0x000000); // Pone el color a negro
if (babosin.collidesWith(decorado, true)) {// Texto que indica si choca o no
g.drawString("CHOCA", ancho, alto, Graphics.RIGHT | Graphics.BOTTOM);
} else {
g.drawString("nochoca", ancho, alto, Graphics.RIGHT | Graphics.BOTTOM);
}
// refresca los graficos
flushGraphics();
}
72
36
Programa: DBVBabosin (4/6)
// Inicializa el decorado que es un TiledLayer
private TiledLayer iniDecorado() throws Exception {
// Carga la imagen con los elementos de la pantalla
Image tileImages = Image.createImage("/deco.png");
// reserva espacio para la capa del decorado
TiledLayer tiledLayer = new TiledLayer(40,24,tileImages,8,8);
// Selecciona los 40x24 elementos del decorado segun su posicion den deco.png
// 0 indica que no hay nada en esa posicion
int[] mapa= {
42,41,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,1,2,42,41,42,41,1,2,
264,264,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,264,
264,264,264,0,0,248,249,250,251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,264,
… };
// Guarda los elementos del mapa en la posicion de pantalla que corresponda
for (int i=0; i < mapa.length; i++) {
int columna = i % 40;
int fila = i/40;
tiledLayer.setCell(columna,fila,mapa[i]); // Actualiza 1 a 1 todas las celdas
}
}
return tiledLayer;
73
Programa: DBVBabosin (5/6)
// Maneja la entrada de teclado
private void leeTeclado() {
int estadoTeclado;
// se guardan los valores para restaurar si choca
antdecox=decox; antdecoy=decoy;
antx=babosinX; anty=babosinY;
estadoTeclado = getKeyStates(); // Lee el estado del teclado
babosin.setFrame(0); // selecciona el 1er sprite de babosin
// Mira si se ha movido a la Izquierda
if ( (estadoTeclado & LEFT_PRESSED) != 0) {
//mueve a la izquierda el decorado y babosin
decox+=1;
babosinX = Math.max(0, babosinX - 1);
// Cambia el sprite de babosin tambien posible con babosin.nextFrame()
posbabosin=(posbabosin+1)%5;
babosin.setFrame(posbabosin);
babosin.setTransform(Sprite.TRANS_NONE);
ultmov=1;
}
// Derecha
if ( (estadoTeclado & RIGHT_PRESSED) !=0 ) {
// Igual que izquierda salvo
// babosin.setTransform(Sprite.TRANS_MIRROR);
}
}
74
37
Programa: DBVBabosin (6/6)
}
// Bucle principal del juego
public void run() {
Graphics g = getGraphics();
while (jugando == true) {
colision(); // Controla colisiones
leeTeclado(); // Lee acciones del usuario
dibujaPantalla(g); // Dibuja la escena actual
try { Thread.sleep(retraso); }
catch (InterruptedException ie) {}
}
}
// Crea y arranca la hebra del juego
public void start() {
Thread t;
jugando = true;
t= new Thread(this);
t.start();
}
// para la ejecucion
public void stop() {
jugando = false;
}
75
RMS (Record Management System)
•
•
•
•
•
El almacenamiento en J2ME se realiza a travé
través de RMS
No existen ficheros
RMS permite guardar registros numerados
El contenido de un registro es un array de bytes
La gestió
gestión de todo lo que haya en el registro debe hacerla el
usuario.
– Por ejemplo, si se guarda una cadena y un nú
número será
será el usuario el
encargado de escribirlo y leerlo correctamente convirtiendo los datos
a arrays de bytes
• La clase RecordStore es la encargada de la manipulació
manipulación de los
registros
Id registro
contenido
1
valor1
2
76
38
RMS: RecordStore
• RecordStore permite realizar operaciones con los
•
•
registros del tipo: Crear, Insertar, Borrar, ...
Todas las operaciones que se realizan con RecordStore
necesitan estar en un try..
catch
try..catch
Para crear o abrir:
RecordStore recordstore; // Declaración
try { // Abre un registro llamado ‘contador’ y lo crea si es necesario (2º parametro a true)
recordstore = RecordStore.openRecordStore("contador", true );
}
catch (Exception error) {
alert = new Alert("Error Creando", error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
• En adelante se pondrá
pondrán las sentencias sin el try aunque
debe estar
77
RMS: RecordStore: Escritura Simple
• El caso má
más simple de registros es aquel en el que se
•
•
escribe un único tipo de datos
Para escribir un dato, por ejemplo, un String hay que
convertirlo a un array de bytes
Despué
Después se añ
añade con addRecord:
addRecord:
String outputData = "1"; // Cadena que se va a escribir
byte[] byteOutputData = outputData.getBytes(); // Conversión de la cadena
// Se añade la array de bytes al registro desde el inicio (0) y con longitud (length)
recordstore.addRecord(byteOutputData, 0, byteOutputData.length);
78
39
RMS: RecordStore: Lectura Simple
• Para leer se utiliza getRecord que necesita como mí
mínimo
•
•
el nú
número de registro a leer aunque tiene varias
versiones
Puede ser necesario saber cuantos registros hay en el
RecordStore,
RecordStore, puede consultarse con getNumRecords
Por ejemplo para leer todas las cadenas almacenadas en
el RecordStore:
RecordStore:
// Crea un array de bytes para leer los datos
byte[] byteInputData = new byte[30];
int length = 0; // Almacenará el número de bytes leidos
String cadena=new String("");
// Bucle para los todos los registros que haya (getNumRecords)
for (int x = 1; x <= recordstore.getNumRecords(); x++) {
// Lee el registro de la posición x en el array de bytes al inicio (0)
length = recordstore.getRecord(x, byteInputData, 0);
cadena=cadena + " "+ new String(byteInputData);
}
79
RMS: RecordStore: Borrado y Cierre
• Para cerrar el RecordStore y dejar de usarlo
recordstore.closeRecordStore();
• Para borrar todo el RecordStore (mé
(método static)
static)
RecordStore.deleteRecordStore("contador");
• Para borrar un registro concreto, se indica su posició
posición
recordstore.deleteRecord(3);
80
40
RMS: RecordStore: Emulador
• En el Wireless Toolkit puede accederse a los RecordStore que se
almacenan en:
C:\WTK22\appdb\
• Para cada telé
teléfono emulado hay una carpeta con su nombre, por
ejemplo para el DefaultColorPhone
C:\WTK22\appdb\DefaultColorPhone
• Cada recordset es precedido por run_by_class_storage_
run_by_class_storage_
• Es decir si tenemos un RecordStore llamado contador, que se ha
usado en el telé
teléfono por defecto se encontrará
encontrará en:
C:\WTK22\appdb\DefaultColorPhone\run_by_class_storage_contador.db
• Este fichero binario puede visualizarse con un editor hexadecimal o
borrarse si la aplicació
aplicación empieza a dar problemillas ;;-)
81
Programa: DBVRMSSimple
• Para probar los elementos bá
básicos de registros se va a
•
•
•
mostrar el programa DBVRMSSimple
Este programa crea un RecordStore llamado contador en
el que la primera vez escribe la cadena ‘1’
Y posteriormente escribe ‘2’, ’3’, ...
Dispone de un menú
menú que permite Crear, Insertar, Ver,
Borrar y Salir
82
41
Programa: DBVRMSSimple
Crear
Incrementar
Incrementar
Ver
Salir
83
Programa: DBVRMSimple (1/5)
import javax.microedition.rms.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
import java.lang.Integer;
public class DBVRMSSimple extends MIDlet implements CommandListener
{
private Display display;
private Alert alert;
private Form form;
private Command salir,crear,ver,incrementar,borrar;
private RecordStore recordstore = null;
public DBVRMSSimple() {
display = Display.getDisplay(this);
salir = new Command("Salir", Command.SCREEN,4); // Definición del menú
incrementar = new Command("Incrementar", Command.SCREEN, 2);
crear=new Command("Crear", Command.SCREEN, 1);
ver=new Command("Ver",Command.SCREEN,3);
borrar=new Command("Borrar",Command.SCREEN,3);
form = new Form("Record");
form.addCommand(salir);
form.addCommand(crear);
form.addCommand(incrementar);
form.addCommand(ver);
form.addCommand(borrar);
form.setCommandListener(this);
}
84
42
Programa: DBVRMSimple (2/5)
public void startApp() {
display.setCurrent(form);
}
public void pauseApp() { }
public void destroyApp( boolean unconditional ) { }
public void commandAction(Command command, Displayable displayable) {
// Para cada opción del menú se realiza una acción sobre el RecordSet
if (command == salir) {// Para cerrar el RecordStore
try
{
recordstore.closeRecordStore();
} catch (Exception error)
{
alert = new Alert("Error Cerrando", error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
destroyApp(true);
notifyDestroyed();
} else if (command==crear) {// Para crear el RecordStore e insertar el valor ‘1’
try {
recordstore = RecordStore.openRecordStore("contador", true );
} catch (Exception error) {
alert = new Alert("Error Creando",
error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
85
Programa: DBVRMSimple (3/5)
try {
String outputData = "1";
byte[] byteOutputData = outputData.getBytes();
recordstore.addRecord(byteOutputData, 0,
byteOutputData.length);
}
catch ( Exception error)
{
alert = new Alert("Error Escribiendo 1",
error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
} else if (command == incrementar) {// Para añadir nuevos valores
try { // Se mira cuantos elementos hay y se guarda ese valor+1 en el RecordStore
String outputData = (new Integer(recordstore.getNumRecords()+1)).toString();
byte[] byteOutputData = outputData.getBytes();
recordstore.addRecord(byteOutputData, 0,
byteOutputData.length);
} catch ( Exception error)
{
alert = new Alert("Error Escribiendo",
error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
} else if (command == ver) { // Muestra todos los registros
86
43
Programa: DBVRMSimple (4/5)
}
try {
byte[] byteInputData = new byte[30];
int length = 0;
String titulo=null;
String cadena=new String("");
for (int x = 1; x <= recordstore.getNumRecords(); x++) {
length = recordstore.getRecord(x, byteInputData, 0);
titulo="Leyendo" + (new Integer(x)).toString();
cadena=cadena + " "+ new String(byteInputData);
} // Se muestra el resultado en un alert
alert = new Alert(titulo, cadena, null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
} catch (Exception error) {
alert = new Alert("Error Leyendo", error.toString(),
null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
87
Programa: DBVRMSimple (5/5)
else if (command == borrar) { // Elimina el registro completo
}
}
}
if (RecordStore.listRecordStores() != null)
{
try {
RecordStore.deleteRecordStore("contador");
}
catch (Exception error)
{
alert = new Alert("Error Borrando", error.toString(),
null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
}
88
44
RMS: Datos complejos
• Si se quieren guardar en un Registro datos compuestos
la mejor forma es crear para escritura:
escritura:
– un ByteArrayOutputStream DataOutputStream
• Y el simé
simétrico para lectura
– ByteArrayInputStream
DataInputStream
• Estas estructuras permiten almacenar datos de distintos
•
tipos
La clase DataOutputStream tiene métodos para escribir
todo tipo de elementos:
elementos:
boolean
writeBoolean
Byte
writeByte
Float
writeFloat
Int
writeInt
String
writeUTF
…
…
89
RMS: Escritura de datos complejos
• Si se quiere por ejemplo escribir un número y un String
// Creación de variables necesarias
byte[] outputData;
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
DataOutputStream outputDataStream=new DataOutputStream(outputStream);
outputDataStream.writeInt(numero); // Escritura del número
outputDataStream.writeUTF(nombre); // Escritura del nombre
outputDataStream.flush(); // Enviar los datos al flujo
outputData=outputStream.toByteArray(); // Convierte los datos a un array de bytes
recordstore.addRecord(outputData, 0, outputData.length); // Escribe los datos en el registro
outputDataStream.close();
outputStream.close();
90
45
RMS: Lectura de datos complejos
• Si se quiere leer un nú
número y un String
// Creación de variables necesarias
byte[] byteInputData = new byte[30];
ByteArrayInputStream inputStream;
DataInputStream inputDataStream;
inputStream=new ByteArrayInputStream(byteInputData); // Crea el ByteArray
inputDataStream=new DataInputStream(inputStream);
// Crea el DataInputStream
int length = records.getRecord(i, byteInputData, 0); // Lee el registro i-esimo
numero= inputDataStream.readInt(); // Lee el número
cadena= inputDataStream.readUTF()); // Lee la cadena
inputStream.reset(); // Limpia el buffer para poder seguir leyendo más registros
• El resto de las operaciones de creació
creación y borrado son
•
iguales que para el caso de datos simples
A continuació
continuación un ejemplo en el que se añ
añaden pares
(nombre, puntos) a una lista de records
91
Programa: DBVRMSRecords
Insertar
Listado
Salir
92
46
Programa: DBVRMSRecords (1/5)
import javax.microedition.rms.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
public class DBVRMSRecords extends MIDlet implements CommandListener {
private Alert alert;
private Command salir,listado,nuevorecord, insertar, eliminar;
private Display pantalla;
private Form principal,frecord;
private TextField fnombre,fpuntos;
private RecordStore records = null;
public DBVRMSRecords() {
pantalla = Display.getDisplay(this);
// Preparacion de la pantalla para poner records
frecord=new Form("Nuevo Record");
fnombre=new TextField("Nombre:","",30,TextField.ANY);
fpuntos=new TextField("Puntos:","",30,TextField.NUMERIC);
insertar=new Command("Insertar", Command.SCREEN,0);
frecord.append(fnombre); frecord.append(fpuntos);
frecord.addCommand(insertar); frecord.setCommandListener(this);
// Preparando la pantalla principal
principal=new Form("Administracion");
salir = new Command("Salir", Command.EXIT, 0);
nuevorecord = new Command("Nuevo Record", Command.SCREEN, 0);
listado = new Command("Listado", Command.SCREEN, 0);
eliminar=new Command("Eliminar Todo", Command.SCREEN,0);
93
Programa: DBVRMSRecords (2/5)
principal.addCommand(salir);
principal.addCommand(nuevorecord);
principal.addCommand(listado);
principal.addCommand(eliminar);
principal.setCommandListener(this);
}
public void startApp() {
cargarRecords();
mostrarRecords();
pantalla.setCurrent(alert,principal);
}
public void pauseApp() { }
public void destroyApp( boolean unconditional ) { }
public void commandAction(Command command, Displayable pantallaable)
{
if (command == salir) { // Acción para terminar
if (records!=null) {
cerrarRecords();
}
destroyApp(true);
notifyDestroyed();
} else if (command==nuevorecord) {// Añadir un nuevo record
pantalla.setCurrent(frecord);
} else if (command==listado) { // Ver todos los records
mostrarRecords();
94
47
Programa: DBVRMSRecords (3/5)
} else if (command==eliminar) { // Borrar todos los registros
if (records!=null) {
cerrarRecords();
}
eliminarRegistros();
} else if (command==insertar) { // Añadir un nuevo registro desde el formulario
guardarRecords(Integer.parseInt(fpuntos.getString()),fnombre.getString());
pantalla.setCurrent(principal);
}
}
public void cargarRecords() { // Abre el RecordStore de los records o lo crea si no existe
try {
records = RecordStore.openRecordStore("records", true );
} catch (Exception error) {
alert = new Alert("Error Creando", error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER); pantalla.setCurrent(alert);
}
}
public void cerrarRecords() { // Cierra el RecordStore
try {
records.closeRecordStore();
} catch (Exception error)
{
alert = new Alert("Error Cerrando", error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER); pantalla.setCurrent(alert);
}
}
95
Programa: DBVRMSRecords (4/5)
public void eliminarRegistros() {// Borrar todos los registros
try {
RecordStore.deleteRecordStore("records");
} catch (Exception error) {
alert = new Alert("Error Borrando...", error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER); pantalla.setCurrent(alert);
}
}
public void guardarRecords(int numero,String nombre) {// Añadir un nuevo registro
try {
byte[] outputData;
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
DataOutputStream outputDataStream=new DataOutputStream(outputStream);
if (records==null) { cargarRecords(); }
outputDataStream.writeInt(numero);
outputDataStream.writeUTF(nombre);
outputDataStream.flush();
outputData=outputStream.toByteArray();
records.addRecord(outputData, 0, outputData.length);
outputDataStream.close();
outputStream.close();
} catch ( Exception error) {
alert = new Alert("Error Escribiendo 1", error.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
pantalla.setCurrent(alert);
}
}
96
48
Programa: DBVRMSRecords (5/5)
public void mostrarRecords() {// Ver todos los records
StringBuffer buffer=new StringBuffer();
byte[] byteInputData = new byte[30];
int puntos;
String nombre;
ByteArrayInputStream inputStream;
DataInputStream inputDataStream;
try {
if (records==null) {
cargarRecords();
}
inputStream=new ByteArrayInputStream(byteInputData);
inputDataStream=new DataInputStream(inputStream);
buffer.append("Registros: " + records.getNumRecords());
for(int i=1;i<=records.getNumRecords();i++) {
int length = records.getRecord(i, byteInputData, 0);
buffer.append("\n" + inputDataStream.readInt() + " "+ inputDataStream.readUTF());
inputStream.reset();
}
alert = new Alert("Records", buffer.toString(), null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER); pantalla.setCurrent(alert);
} catch (Exception error) {
alert = new Alert("Error Leyendo", error.toString(), null, AlertType.WARNING);
alert.setTimeout(3000);
pantalla.setCurrent(alert);
}
}
}
97
Problema: Versiones de Prueba
• Cuando se quiere entregar una muestra de un programa
antes de venderlo hay varias opciones:
– Limitar opciones
– Fecha lílímite de uso
– Número limitado de ejecuciones
• Se pide utilizando RMS hacer una aplicació
aplicación que só
sólo
pueda ejecutarse 5 veces
– Cada vez que se ejecuta debe decirnos cuantas pruebas nos
quedan
• Puede ser necesario otro programa que inicialice o
modifique el nú
número de evaluaciones posibles
98
49
Comunicaciones HTTP
• J2ME permite hacer conexiones por HTTP
• Esto permite hacer cualquier tipo de aplicació
aplicación en la que
•
•
•
el dispositivo mó
móvil será
será el cliente
Lo único que hay que hacer es definir un protocolo
propio para interpretar los mensajes entre el cliente y el
servidor
Lo má
más sencillo es que el servidor devuelva texto plano
Por ejemplo, el telé
teléfono pide por el mé
método get la lista
de citas del dí
día, y el servidor las devuelve:
Cliente (Teléfono abre esta dirección)
El servidor devuelve texto plano
http://miservidor.es/citas.jsp?idusuario=bueno&fecha=hoy
Citas para hoy:
9:00-14:00 Curso de J2ME
16:00-20:00 Examen 1ºTeleco
99
Comunicaciones HTTP: Servidor
• El servidor podrá
podrá estar programado en cualquier
lenguaje que permita conexió
conexión http:
– CGI
– ASP
Java: Servlets o JSP
PHP, etc.
• Como ejemplo se verá
verá 2 aplicaciones del servidor que
devuelven texto plano:
plano: “Hola Mundo”
Mundo”, una con Servlets y
servlet
otra en php
import javax.servlet.http.*;
php
<?php
// Enviaremos un texto plano
header('Content-type: text/plain');
echo ("hola mundo");
jsp
?>
<% response.setContentType("text/plain");%>
<%=“Hola Mundo”%>
import javax.servlet.*;
import java.io.*;
public class HitServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String message = "Hola Mundo";
response.setContentType("text/plain");
response.setContentLength(message.length());
PrintWriter out = response.getWriter();
out.println(message);
}
}
100
50
Comunicaciones HTTP: Cliente J2ME
• Para no bloquear la ejecució
ejecución, las conexiones deben
•
realizarse en una hebra independiente
Se utiliza un objeto HttpConnection con la url y los
pará
parámetros del programa servidor
HttpConnection conexion=(HttpConnection) Connector.open("http://localhost/j2mehola.php");
• Los datos se leen en un array de bytes que podrá
podrá
procesarse a voluntad,
voluntad, igual que en RMS
InputStream entrada=null; int longitud; byte[] texto; String cadena;
entrada=conexion.openInputStream();
longitud=(int)conexion.getLength();
if (longitud==-1) { // A veces la longitud se lee incorrectamente
longitud=255;
}
texto=new byte[longitud]; // Reserva array de bytes
longitud=entrada.read(texto);
entrada.close(); // Cierra el flujo de entrada
conexion.close(); // Cierra la conexión
cadena=new String(texto,0,longitud); // Convierte el array de bytes a String
101
Programa: DBVHTTPHolaMundo
La luz verde Indica conexión Web
102
51
Programa: DBVHTTPHolaMundo (1/3)
import
import
import
import
javax.microedition.midlet.*;
javax.microedition.lcdui.*;
javax.microedition.io.*;
java.io.*;
public class DBVHTTPHolaMundo extends MIDlet implements CommandListener, Runnable {
private Alert alert;
private Command salir,conectar;
private Display pantalla;
private Form principal;
private TextField ftexto;
public DBVHTTPHolaMundo() {
principal=new Form("Conexion HTTP"); // Preparacion de la pantalla principal
ftexto=new TextField("Texto Leido:","",30,TextField.ANY);
conectar=new Command("Conectar", Command.SCREEN,0);
salir = new Command("Salir", Command.EXIT, 0);
principal.append(ftexto);
principal.addCommand(conectar);
principal.addCommand(salir);
principal.setCommandListener(this);
}
public void startApp() {
pantalla = Display.getDisplay(this);
pantalla.setCurrent(principal);
ftexto.setString("Pulse conectar...");
}
public void pauseApp() { }
103
Programa: DBVHTTPHolaMundo (2/3)
public void destroyApp( boolean unconditional ) { }
public void commandAction(Command command, Displayable pantallaable) {
if (command == salir) {
destroyApp(true);
notifyDestroyed();
} else if (command==conectar) {
Thread t=new Thread(this); // Inicia la hebra de conexión
t.start();
}
}
public void conectar() {
HttpConnection conexion=null;
InputStream entrada=null;
int longitud;
byte[] texto;
String cadena;
try {
ftexto.setString("Conectando...");
conexion=(HttpConnection) Connector.open("http://localhost/j2mehola.php");
//conexion.setRequestProperty("Connection","close");
ftexto.setString("Abriendo...");
entrada=conexion.openInputStream();
longitud=(int)conexion.getLength();
if (longitud==-1) {
longitud=255;
}
104
52
Programa: DBVHTTPHolaMundo (3/3)
texto=new byte[longitud];
ftexto.setString("Leyendo...");
longitud=entrada.read(texto);
ftexto.setString("Cerrando...");
entrada.close();
conexion.close();
cadena=new String(texto,0,longitud);
ftexto.setString(cadena);
// Modifica el cuadro de texto con el texto recibido
} catch (Exception error) {
alert = new Alert("Error Conectando", error.toString(),
null, AlertType.WARNING);
alert.setTimeout(Alert.FOREVER);
pantalla.setCurrent(alert);
}
}
}
public void run() { // Inicio de la hebra
conectar();
}
105
Curiosidades
• Para hacer vibrar el telé
teléfono a partir de MIDP 2.0
– Display.vibrate(100)
Display.vibrate(100) ..- Tiempo en Milisegundos
– Display.flashBacklight(tiempo).
Display.flashBacklight(tiempo).-- Enciende la luz del telé
teléfono
• Para probar estas caracterí
características se va a mostrar un
•
•
•
programa que permitirá
permitirá usar el telé
teléfono para dar
masajes o como una linterna ::-)
En el emulador la vibració
vibración se muestra con un zumbido
La luz de fondo se muestra con un marco de color
No todos los telé
teléfonos permiten controlar la luz y el
vibrador
106
53
Programa: DBVMasaje
zumbido
107
Programa: DBVMasaje
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DBVMasaje extends MIDlet implements CommandListener {
private Display pantalla ;
private TextBox tintro,tayuda ;
private Command salir, masaje, linterna;
public DBVMasaje(){
pantalla = Display.getDisplay(this); // Preparando la pantalla principal
tintro = new TextBox("Mi linterna mágica", "Elije un masaje o una linterna", 40, 0);
salir = new Command("Salir", Command.EXIT, 0);
masaje = new Command("Masaje",Command.HELP,1);
linterna= new Command("Linterna",Command.SCREEN,1);
tintro .addCommand(salir); tintro.addCommand(masaje);tintro.addCommand(linterna);
tintro.setCommandListener(this);
}
public void startApp() {pantalla .setCurrent(tintro); }
public void pauseApp() { }
public void destroyApp(boolean unconditional) { }
public void commandAction(Command c, Displayable displayable) {
if (c == salir) {
destroyApp(false); notifyDestroyed();
} else if (c==linterna) {
pantalla.flashBacklight(3000); // Enciende la luz 3 segundos
} else if (c==masaje) {
pantalla.vibrate(3000); // Activa la vibración 3 segundos
}
}
}
108
54
Sonidos
• Tonos en la clase Manager
playTone(int nota, int duracion, int volumen)
• Las notas se asocian igual que en un midi,
midi, cada tecla del
•
•
piano es una nota
C(60C(60-440Hz)C#(61)D(62)D#(63)E(64)F(65)F#(66)
G(67)G#(68)A(69)
Volumen má
máximo=100
Manager.playTone(60,1000,100)
109
Para ampliar…
• Servicios Web (jsr172)
• Bluetooth/OBEX (jsr82)
– Para probar los ejemplos bluetooth es necesario en ktoolbar:
ktoolbar:
Edit Preferences Security Security Domain=trusted
• Grá
Gráficos 3D (jsr184)
• Sonidos y Música.
sica. MMAPI(Mobile Media APIAPI-jsr135)
• Uso de push para iniciar aplicaciones desde un servidor
•
en el movil
RecordEnumeration
– Permite ordenar y filtrar los registros de un RecordStore
• Location (jsr179) Localizació
Localización geográ
geográfica (CLDC 1.1)
• Cada especificación jsrXYZ se puede encontrar en:
http://jcp.org/en/jsr/detail?id=XYZ
110
55
Referencias
Libros
• Jonathan Knudsen, “Wireless Java: Developing with J2ME”
J2ME”, 2nd edition.
Ed. APress,
APress, 2003.
• James Keogh, “The Complete Reference: J2ME”
J2ME”, Ed. Osborne, 2003.
• Jason Lam, “J2ME & Gaming”
Gaming”, 2004.
http://www.jasonlam604.com
Artí
Artículos
• Qusay H. Mahmoud,
Mahmoud, “Wireless Application Programming with J2ME and
Bluetooth”
Bluetooth”, 2003
http://developers.sun.com/techtopics/mobility/midp/articles/bluetoot
h1/ y /bluetooth2/
http://developers.sun.com/techtopics/mobility/midp/articles/bluetooth1/
• Jonathan Knudsen, “Creating 2D Action Games with the Game API”
API”,
2003. http://developers.sun.com/techtopics/mobility/midp/articles/game/
http://developers.sun.com/techtopics/mobility/midp/articles/game/
Webs de Interé
Interés
Forum Nokia. http://www.forum.nokia.com
http://www.forum.nokia.com//
Java en sun. http://java.sun.com/
111
Curiosidades
• Para hacer vibrar el telé
teléfono a partir de MIDP 2.0
– display.vibrate(100)
display.vibrate(100) ..- Tiempo en Milisegundos
– Display.flashBacklight(tiempo).
Display.flashBacklight(tiempo).-- Enciende la luz del telé
teléfono
112
56
Descargar