Está en la página 1de 53

Programación de 

dispositivos móviles

Tema 6: Programación de 
dispositivos móviles
1.Programación de dispositivos móviles
2.Limitaciones de los dispositivos móviles
3.Sistemas operativos móviles
4.Desarrollo de aplicaciones móviles
5.Java 2 Mobile Edition
6.Configuración CDC
7.Configuración CLDC
8.Paquetes opcionales en J2ME
9.MIDP: MIDlets
10.MIDP: Interfaces Gráficas de Usuario
11.MIDP: Persistencia
12.MIDP: Conexión por red
13.Persistencia II: Ficheros
14.Para terminar
Programación de 
dispositivos móviles

Programación de dispositivos móviles

La generalización en los últimos años de teléfonos 
móviles, smartphones, PDAs, etc. ha generado un 
importante necesidad de aplicaciones para este tipo 
de dispositivos

Las prestaciones de los dispositivos móviles se 
incrementan día a día, posibilitando la implementación 
de aplicaciones muy interesantes

Acceso a Internet y conectividad mediante Bluetooth

Envío de mensajes cortos

Aceleración 2D y 3D

Reproducción de video y sonido

Cámara integrada

Información de localización GPS

Sensores de orientación
Programación de 

etc. dispositivos móviles
Programación de 
dispositivos móviles

Limitaciones de los dispositivos móviles

La necesidad de ahorrar energía obliga a utilizar 
procesadores con una capacidad de cómputo limitada 
y baja frecuencia de reloj

El uso intensivo de cálculos, gráficos, sonido, 
conexiones inalámbricas etc. limita la vida de la 
bateria

La memoria disponible es muy limitada en 
comparación con la de un ordenador ordinario

El almacenamiento de datos persistente también es 
muy limitado: memoria interna + tarjetas SD o similar

Limitaciones de los 
dispositivos móviles
Programación de 
dispositivos móviles

Sistemas operativos móviles

Son sistemas operativos específicos para este tipo de 
dispositivos, que tienen en cuenta las limitaciones que 
hemos visto antes

Symbian es el S.O. instalado en mayor número de 
dispositivos móviles en la actualidad, sobre todo 
teléfonos móviles

Dos plataformas: S60 y UIQ

Sistemas operativos 
S60 UIQ
móviles
Programación de 
dispositivos móviles


Windows Mobile, con mayor difusión en el mercado 
de PDAs


Palm OS, utilizado por el fabricante de PDAs Palm 
Inc.

Sistemas operativos 
móviles
Programación de 
dispositivos móviles


Android, es un S.O. para móviles presentado 
recientemente por Google. Utiliza un kernel Linux


Otros S.O. móviles: RIM Blackberry y otros S.O. 
basados en kernel linux

Sistemas operativos 
móviles
Programación de 
dispositivos móviles

Desarrollo de aplicaciones móviles

Gran disparidad de plataformas de desarrollo

Symbian (S60 y UIQ): C++ con librerías nativas

Windows Mobile: .NET Compact Framework, una 
versión limitada de .NET

PalmOS: C/C++, con librerías nativas

Android: Java con librerías nativas (no J2ME)

Java Mobile Edition (J2ME) para múltiples 
plataformas, especialmente Symbian

Otras: Python

Sistemas operativos 
móviles
Java 2 Mobile  Edition

Java 2 Mobile Edition

La única opción real que permite un desarrollo 
multiplataforma para dispositivos móviles

Tiene una estructura altamente modular para 
adaptarse a las características de cada dispositivo

Sistemas operativos 
móviles
Java 2 Mobile  Edition


Las configuraciones (CDC y CDLC) definen el 
entorno mínimo necesario para la ejecución de 
aplicaciones java en un grupo amplio de dispositivos 
móviles (JVM/KVM+paquetes básicos)

Los perfiles definen paquetes adicionales para 
soportar funcionalidades básicas imprescindibles de 
cada familia de dispositivos

Los paquetes opcionales sirven para cubrir 
funcionalidades específicas: Bluetooth, soporte 3D, 
etc.

Sistemas operativos 
móviles
Configuración CDC
 

Configuración CDC

CDC (Connected Device Configuration). Para PDAs 
de última generación o smartphones avanzados

Requiere una máquina virtual java compatible con 
J2SE 1.4.2 y los siguientes paquetes:

java.lang ●
java.util

java.lang.ref ●
java.util.zip

java.lang.reflect ●
java.util.jar

java.math ●
java.net

java.text ●
java.security

java.io ●
java.security.cer

javax.microedition.io

Sistemas operativos 
móviles
Configuración CDC
 


Los dispositivos que utilizan el CDC admiten tres 
perfiles: Foundation Profile, Personal Basis Profile y 
Personal Profile

El Foundation Profile  proporciona soporte básico de 
red y E/S

El Personal Basis Profile contiene todas las clases del 
Foundation Profile más soporte limitado de Javabeans 
y AWT

El Personal Profile incluye los dos perfiles anteriores 
más soporte completo de AWT y Javabeans

Una aplicación J2SE implementada cuidadosamente 
puede ser ejecutable en la configuración CDC

Sistemas operativos 
móviles
Configuración CLDC

Configuración CLDC

CLDC (Connected Limited Device Configuration). 
Para dispositivos con potencia de cálculo, memoria, 
batería y acceso a red limitados

Incluye una máquina virtual java reducida (KVM) y los 
siguientes paquetes:

java.lang (reducida)

java.lang.ref (reducida)

java.util (reducida)

java.io (reducida)

java.microedition.io

Sólo incluye las clases básicas

EEDDs: Vector, Hashtable y Stack

Sistemas operativos 
móviles
Configuración CDLC


Mobile Information Device Profile (MIDP) es el perfil 
más común con CLDC

MIDP permite la implementación de aplicaciones con 
la siguiente funcionalidad:

Interfaz de usuario sencilla, adaptada a móviles

API especializado para juegos

Persistencia básica

Conexión por red

Sonido

La mayoría de los móviles actuales soportan CLDC
+MIDP. Mucho éxito por la implementación de juegos

La programación MIDP para configuración CLDC 
requiere la instalación del Sun Java Wireless Toolkit

Netbeans proporciona soporte mediante el Mobility 
Pack
Sistemas operativos 
móviles
Paquetes opcionales 
en J2ME

Paquetes opcionales en J2ME

Permiten extender la funcionalidad básica de los 
perfiles para aprovechar todas las posibilidades del 
dispositivo

Wireless Messaging API (WMA) JSR­120, JSR­205. 
Envío de mensajes SMS.

Mobile Media API (MMAPI) JSR­135. Soporte de 
audio y video, tanto reproducción como captura 

Location API JSR­179. Localización geográfica del 
dispositivo, mediante GPS u otros mecanismos

Sistemas operativos 
móviles
Paquetes opcionales 
en J2ME


Personal Information Management and File 
Connection API JSR 75. Acceso a la lista de contactos 
del teléfono móvil y al sistema de ficheros

Security and Trust Services API JSR 177. 
Tratamiento de información privada, ejecución segura, 
 identificación y autentificación etc.

Mobile 3D Graphics JSR 184. Soporte de gráficos 3D

J2ME Web Services API (WSA) JSR­172. Soporte de 
servicios web en dispositivos móviles

Bluetooth API JSR 82

J2ME RMI JSR 66. Llamada a operaciones de 
objetos remotos

Sistemas operativos 
móviles
MIDP: Midlets

MIDP: MIDlets

Una aplicación MIDP requiere la implementación de 
un MIDlet, cuya estructura recuerda los Applets y 
Servlets de J2SE
import javax.microedition.midlet.MIDlet;

public class EjemploMidlet extends MIDlet {


public void startApp() {
// Arrancar aplicación
}

public void pauseApp() {


// Parar aplicación
}

public void destroyApp(boolean unconditional) {


// Eliminar recursos
}
}

Sistemas operativos 
móviles
MIDP: Midlets


De manera similar a un Applet, un MIDlet requiere la 
implementación de tres operaciones de la clase 
MIDlet:

startApp(). Es llamada automáticamente cuando la 
aplicación debe comenzar su ejecución

pauseApp(). El dispositivo puede solicitar la parada 
temporal de la aplicación en cualquier momento. La 
reanudación implicará una nueva llamada a 
startApp() o la terminación definitiva mediante la 
llamada a destroyApp()

destroyApp(). Es invocada para solicitar la 
liberación de los recursos del MIDlet y cualquier 
tarea necesaria antes de su eliminación de memoria
Sistemas operativos 
móviles
MIDP: Midlets


Un conjunto de MIDlets se distribuye en un fichero jar

El MANIFEST del fichero jar es más complicado que 
los que conocemos

Primero se indica el nombre global del conjunto de 
MIDlets del fichero jar, su versión, author y las 
versiones de CLDC y MIDP necesarias

Después cada MIDlet se describe mediante un 
nombre, el icono correspondiente y el nombre de la 
clase que lo implementa

MIDlet-Name: EjemplosMIDP
MIDlet-Version: 1.0
MIDlet-Vendor: ajrueda
MicroEdition-Configuration: CLDC-1.1
MicroEdition-Profile: MIDP-2.0
MIDlet-1: Ejemplo,ejemplo.png,EjemploMidlet

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

MIDP: Interfaces Gráficas de Usuario

MIDP proporciona una forma sencilla de construir 
interfaces de usuario adaptada a las limitaciones de 
pantalla, potencia de cálculo y batería de los 
dispositivos móviles

En comparación con toolkits como Swing, la variedad 
y número de componentes existentes es muy pequeño

La interfaz se construye a base de distintas pantallas, 
en lugar de ventanas o diálogos

Las acciones del usuario definen la transición de una 
pantalla a otra

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario


Es importante tener en cuenta el pequeño tamaño de 
la pantalla del dispositivo a la hora de diseñar la 
interfaz

La mayoría de los dispositivos dispone de un par de 
botones de acción cuyo efecto se puede programar 
para cada pantalla

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario


Para empezar hay que obtener el objeto Display que 
permite manejar la pantalla del dispositivo

La operación estática getDisplay() de esta clase 
devuelve el objeto
Display d = Display.getDisplay()

A continuación podemos establecer la pantalla actual 
mediante:
d.setCurrent(Displayable pantalla)

Una vez obtenido el display, el MIDlet sigue el 
siguiente esquema de funcionamiento:
1. Crear una pantalla
2. Mostrarla mediante setCurrent()
3. Esperar las acciones del usuario
4. Elegir otra pantalla en función de estas acciones (volver a 1)

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario


Las clases que implementan la interfaz Displayable 
son las siguientes:

TextBox List Alert Form

Sistemas operativos 
Canvas móviles
MIDP: Interfaces Gráficas 
de Usuario

Crear y activar una pantalla TextBox es muy sencillo:

TextBox t = new TextBox( Escribe un poema , , 500, TextField.ANY);

d.setCurrent(t);


Un Alert es similar a un messageBox de Swing, 
admitiendo distintos tipos.

El tiempo de visualización del Alert es configurable 
mediante setTimeout()

Al llamar a setCurrent() es necesario indicar el 
siguiente displayable a mostrar tras el Alert
Alert a = new Alert( Error , Error al salvar la información ,
null, AlertType.ERROR);
a.setTimeout(5000);

d.setCurrent(a, siguienteDisp);
Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

El displayable Form permite definir una pantalla con 

múltiples Item (o componentes):

StringItem. Similar a un label de Swing

Spacer. Un espacio con un ancho y alto determinado. Útil para distribuir los 
componentes

TextField. Un editor de texto con una etiqueta asociada

ImageItem. Una imagen con una etiqueta

DateField. Un editor que permite introducir una fecha/hora

Gauge. Sirve para representar de manera gráfica un valor entero

ChoiceGroup. Sirve para seleccionar valores de una lista predeterminada. Puede 
ser múltiple, exclusiva o popup

Cualquier Item definido por el usuario

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

Los Form permiten crear interfaces mucho más ricas:

Form f = new Form("Ficha deportiva");


f.append(new TextField("Apellidos", null, 40, TextField.ANY));
f.append(new TextField("Nombre", null, 40, TextField.ANY));
f.append(new DateField("Fecha de nacimiento", DateField.DATE));
f.append(new TextField("E-mail", null, 20, TextField.EMAILADDR));

String[] tipos = {"Profesor", "Alumno"};


f.append(cg = new ChoiceGroup("Tipo", ChoiceGroup.EXCLUSIVE, tipos, null));

d.setCurrent(f);

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario


Para asociar acciones a los botones del dispositivo se 
utiliza la clase Command

Las activación de un comando es capturada por un 
CommandListener, cuya única operación es 
commandAction()
class listenerTextBox implements CommandListener {
public commandAction(Command cm, Displayable ds) {
if (cm == cFin) {
// Procesar el comando
}
}
}

TextBox t = new TextBox( Escribe un poema , , 500, TextField.ANY);

t.addCommand(cFin = new Command( Fin , Command.OK, 0));


t.setListener(new listenerTextBox());

d.setCurrent(t);

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

Siguiendo el ejemplo que hemos desarrollado en la asignatura, vamos a crear un 
visor móvil de nuestra cuenta

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class MidletCuenta extends MIDlet {


private Cuenta c;

private Display d;
private TextField tCodigo;
private Command cEntrar, cSalir, cVolver, cMovimientos;

private Form fPeticionCodigo, fInfoCuenta;


private List lMovCuenta;

public MidletCuenta() {
d = null;
}

void crearComandos() {
cEntrar = new Command("Entrar", Command.OK, 0);
cSalir = new Command("Salir", Command.EXIT, 1);
cVolver = new Command("Volver", Command.BACK, 0);
cMovimientos = new Command("ver Mov.", Command.SCREEN, 0);
}

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

public void startApp() {


if (d == null) {
d = Display.getDisplay(this);
}
crearComandos();
crearFormPeticionCodigo();
d.setCurrent(fPeticionCodigo);
}

void crearFormPeticionCodigo() {
fPeticionCodigo = new Form("Información de cuentas");
fPeticionCodigo.append(tCodigo = new TextField("Código de cuenta ",
null, 10, TextField.NUMERIC));
fPeticionCodigo.addCommand(cEntrar);
fPeticionCodigo.addCommand(cSalir);
fPeticionCodigo.setCommandListener(new listenerPeticionCodigo());
tCodigo.setLayout(Item.LAYOUT_2 | Item.LAYOUT_CENTER);
}

class listenerPeticionCodigo implements CommandListener {


public void commandAction(Command cm, Displayable s) {
if (cm == cEntrar) {
// Cargar la cuenta aquí

crearFormInformacionCuenta();
d.setCurrent(fInfoCuenta);
} else if (cm == cSalir) {
destroyApp(true);
notifyDestroyed();
}
}
}

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

void crearFormInformacionCuenta() {
// Crear formulario de información dae la cuenta
fInfoCuenta = new Form("Información de cuenta");
fInfoCuenta.append(new StringItem("Código:",
Long.toString(c.leerNumero())));
fInfoCuenta.append(new StringItem("Titular:",
c.leerTitular()));
fInfoCuenta.append(new StringItem("Interés:",
Float.toString(c.leerInteres())));
fInfoCuenta.append(new StringItem("Saldo:",
Float.toString(c.leerSaldo())));

fInfoCuenta.addCommand(cMovimientos);
fInfoCuenta.addCommand(cVolver);
fInfoCuenta.setCommandListener(new listenerInformacionCuenta());

// Crear lista de movimientos


lMovCuenta = new List("Ultimos movimientos", List.IMPLICIT);
Movimiento m;
int nMov, nm;
for (nMov = 10, nm = c.numMovimientosHistorico() - 1; nMov > 0
&& nm >= 0; nm--, nMov--) {
m = c.leerMovimientoHistorico(nm);
lMovCuenta.append(cadenaDate(m.fecha) + ' ' + m.tipo + ' ' +
m.importe + ' ' + m.saldo, null);
}

lMovCuenta.addCommand(cVolver);
lMovCuenta.setCommandListener(new listenerInformacionMovimientos());
}

Sistemas operativos 
móviles
MIDP: Interfaces Gráficas 
de Usuario

class listenerInformacionCuenta implements CommandListener {


public void commandAction(Command cm, Displayable s) {
if (cm == cVolver) {
d.setCurrent(fPeticionCodigo);
}
else if (cm == cMovimientos) {
d.setCurrent(lMovCuenta);
}
}
}

class listenerInformacionMovimientos implements CommandListener {


public void commandAction(Command cm, Displayable s) {
if (cm == cVolver) {
d.setCurrent(fInfoCuenta);
}
}
}

Sistemas operativos 
móviles
MIDP: Persistencia

MIDP: Persistencia

La capacidad de almacenamiento persistente de un 
dispositivo móvil puede ser muy limitada

El soporte de tarjetas de memoria, cada vez más 
común, ha aumentado mucho las prestaciones (8Gb 
en iPhone o Nokia N95) posibilitando una estructura 
de ficheros similar a la de un ordernador convencional

Sin embargo el perfil MIDP es conservador y 
proporciona un soporte sencillo de persistencia a 
través de registros de bloques de bytes

Sistemas operativos 
móviles
MIDP: Persistencia


Un MIDlet puede abrir un almacén de registros con un 
 nombre arbitrario mediante:
RecordStore RecordStore.openRecordStore(“nombre”, true);

El segundo parámetro indica que el almacén debe 
abrirse si no existe

A través de las operaciones del objeto RecordStore 
podremos manejar los registros

Normalmente un almacén no se comparte con otros 
MIDlets, aunque puede habilitarse este acceso

El almacén de registros se cierra mediante:
closeRecordStore()

Sistemas operativos 
móviles
MIDP: Persistencia


El acceso a los registros se realiza a través de un 
identificador numérico, que es devuelto al añadir un 
registro:
int addRecord(byte[] datos, int offset, int numBytes)

Para recuperar un registro debemos indicar su 
identificador:
int getRecord(int id, byte[] buffer, int offset)
Modificar un registro ya existente:

void setRecord(int id, byte[] nuevosDatos, int offset, int numBytes)
Eliminar un registro:

void deleteRecord(int id)

Sistemas operativos 
móviles
MIDP: Persistencia


Es posible recorrer los registros de un almacén 
creando una enumeración:
RecordStore rs = RecordStore.openRecordStores( ejemplo , true);

RecordEnumeration re = re.enumerateRecords(null, null, false);


while (re.hasNextElement()) {
byte[] datos = re.nextRecord();
// Operar con los datos
}

re.destroy();
rs.closeRecordStore();


La operación enumerateRecords() admite la 
especificación de clases de filtrado y ordenación de 
los registros del almacén

Sistemas operativos 
móviles
MIDP: Persistencia

Vamos a crear un gestor de persistencia para las cuentas corrientes mediante un 
almacén de registros

import java.io.*;
import java.util.*;
import javax.microedition.rms.*;

public class DAOCuentaRS {


static DAOCuentaRS instancia = null;

public static DAOCuentaRS obtenerInstancia() throws RecordStoreException {


if (instancia == null) {
instancia = new DAOCuentaRS();
}
return instancia;
}

private DAOCuentaRS() {}

public boolean existe(long numero) throws RecordStoreException, IOException {


RecordStore rs = null;
try {
rs = RecordStore.openRecordStore("cuentas", true);
return (buscarRegistroCuenta(rs, numero) != -1);
} finally {
if (rs != null) rs.closeRecordStore();
}
}

Sistemas operativos 
móviles
MIDP: Persistencia

public Cuenta cargar(long numero) throws RecordStoreException, IOException {


RecordStore rs = null;
DataInputStream dis = null;
Cuenta c = null;

try {
rs = RecordStore.openRecordStore("cuentas", true);

int idReg = buscarRegistroCuenta(rs, numero);


if (idReg == -1) {
return null;
}

dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(idReg)));


c = new Cuenta(dis.readLong(), dis.readUTF(), dis.readFloat());
c.saldo = dis.readFloat();

int nMov = dis.readInt();


for (int nm = 0; nm < nMov; nm++) {
c.movimientos.addElement(new Movimiento(new Date(dis.readLong()),
dis.readChar(), dis.readFloat(), dis.readFloat()));
}
}
finally {
if (dis != null) dis.close();
if (rs != null) rs.closeRecordStore();
}

return c;
}

Sistemas operativos 
móviles
MIDP: Persistencia

public void salvar(Cuenta c) throws RecordStoreException, IOException {


RecordStore rs = null;
ByteArrayOutputStream bos = null;
DataOutputStream dos = null;

try {
rs = RecordStore.openRecordStore("cuentas", true);
dos = new DataOutputStream(bos = new ByteArrayOutputStream());

dos.writeLong(c.leerNumero()); dos.writeUTF(c.leerTitular());
dos.writeFloat(c.leerInteres()); dos.writeFloat(c.leerSaldo());

Movimiento m;
int nMov = c.numMovimientosHistorico();
dos.writeInt(nMov);
for (int nm = 0; nm < nMov; nm++) {
m = c.leerMovimientoHistorico(nm);

dos.writeLong(m.fecha.getTime()); dos.writeChar(m.tipo);
dos.writeFloat(m.importe); dos.writeFloat(m.saldo);
}

int idReg = buscarRegistroCuenta(rs, c.leerNumero());


if (idReg != -1) {
rs.setRecord(idReg, bos.toByteArray(), 0, bos.size());
} else {
rs.addRecord(bos.toByteArray(), 0, bos.size());
}
}
finally {
if (dos != null) dos.close();
if (rs != null) rs.closeRecordStore();
}
}
Sistemas operativos 
móviles
MIDP: Persistencia

private int buscarRegistroCuenta(RecordStore rs, long numero)


throws RecordStoreException, IOException {
RecordEnumeration re = null;
DataInputStream dis = null;
long recNum;
int id;

try {
re = rs.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
id = re.nextRecordId();
dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(id)));
recNum = dis.readLong();
if (recNum == numero) {
return id;
}
dis.close();
dis = null;
}
} finally {
if (dis != null) dis.close();
if (re != null) re.destroy();
}

return -1;
}
}

Sistemas operativos 
móviles
MIDP: Persistencia

En el MIDlet debemos crear un atributo para referenciar el gestor de persistencia, 
y realizar su inicialización en startApp()
public void startApp() {
if (d == null) {
d = Display.getDisplay(this);
}

if (dc == null) {
try {
dc = DAOCuentaRS.obtenerInstancia();
}
catch(Exception e) {
d.setCurrent(new Alert("Error",
"No es posible abrir el almacén de registros",
null, AlertType.ERROR));
destroyApp(true);
notifyDestroyed();
return;
}
}

// Crear las cuentas de ejemplo si no existen


crearCuentasEjemplo();

crearComandos();
crearFormPeticionCodigo();
d.setCurrent(fPeticionCodigo);
}

Sistemas operativos 
móviles
MIDP: Persistencia

class listenerPeticionCodigo implements CommandListener {


public void commandAction(Command cm, Displayable s) {
if (cm == cEntrar) {
try {
c = dc.cargar(Long.parseLong(tCodigo.getString()));
if (c == null) {
d.setCurrent(new Alert("Error", "Cuenta inexistente",
null, AlertType.ERROR), fPeticionCodigo);
return;
}
} catch(Exception e) {
d.setCurrent(new Alert("Error", "Error de lectura de cuenta",
null, AlertType.ERROR), fPeticionCodigo);
return;
}

crearFormInformacionCuenta();
d.setCurrent(fInfoCuenta);
} else if (cm == cSalir) {
destroyApp(true);
notifyDestroyed();
}
}
}

Sistemas operativos 
móviles
MIDP: Conexión por red

MIDP: Conexión por red

MIDP es especialmente potente en lo que se refiere a 
 la conexión por red mediante sockets, http y otros 
protocolos

La clase Connection representa una conexión 
genérica y es extendida a tres conexiones que 
admiten E/S mediante streams: InputConnection, 
OutputConnection y StreamConnection

La clase StreamConnection es extendida a varias 
clases que representan distintos tipos de conexiones: 
CommConnection, HttpConnection, httpsConnection, 
SocketConnection, etc.
Sistemas operativos 
móviles
MIDP: Conexión por red


La clase Connector es una factoría que a partir de un 
url devuelve la clase de conexión correspondiente:
Connection Connector.open(String url)

HttpConnection con1;
con1 = (HttpConnection) Connector.open( http://www.google.es/search?hl=es&q=j2me );

SocketConnection con2;
con2 = (SocketConnection) Connector.open( socket://miservidor:79 );


La conexión debe cerrarse al final con close()

A partir de la conexión podemos obtener un stream 
de lectura o escritura
HttpConnection con1;
con1 = (HttpConnection) Connector.open( http://www.google.es/search?hl=es&q=j2me );

InputStream is = con1.openInputStream();
// Utilizar el stream
con1.close();

Sistemas operativos 
móviles
MIDP: Conexión por red

El siguiente gestor de persistencia obtiene los datos de la cuenta desde un 
servidor web

import java.io.*;
import java.util.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;

public class DAOCuentaNC {


static DAOCuentaNC instancia = null;

public static DAOCuentaNC obtenerInstancia() {


if (instancia == null) {
instancia = new DAOCuentaNC();
}
return instancia;
}

private DAOCuentaNC() {
}

public boolean existe(long numero) {


try {
cargar(numero);
}
catch(Exception e) {
return false;
}
return true;
}
Sistemas operativos 
móviles
MIDP: Conexión por red

public Cuenta cargar(long numero) throws IOException {


InputConnection ic = null;
DataInputStream dis = null;
Cuenta c = null;

try {
ic = (InputConnection) Connector.open(urlCuenta(numero));
dis = ic.openDataInputStream();
c = new Cuenta(dis.readLong(), dis.readUTF(), dis.readFloat());
c.saldo = dis.readFloat();

int nMov = dis.readInt();


for (int nm = 0; nm < nMov; nm++) {
c.movimientos.addElement(new Movimiento(new Date(dis.readLong()),
dis.readChar(), dis.readFloat(), dis.readFloat()));
}
} catch(Exception e) {
// No se encuentra la cuenta
return null;
} finally {
if (ic != null) ic.close();
}

return c;
}

private String urlCuenta(long codigo) {


return "http://robin.ujaen.es/asignaturas/progav/cuentas/" +
Long.toString(codigo) + ".cnt";
}
}
Sistemas operativos 
móviles
Persistencia II: Ficheros

Persistencia II: Ficheros

El File Connection and PIM API (JSR 75) define un 
nuevo tipo de conexión denominado FileConnection 
que permite trabajar con ficheros de manera similar a 
un ordenador convencional

Este API no está disponible en todos los dispositivos

El acceso al sistema de ficheros requiere permisos 
especiales si la aplicación no está certificada, para 
evitar daños en el mismo

Sistemas operativos 
móviles
Persistencia II: Ficheros

El siguiente ejemplo lee una imagen guardada en el dispositivo
FileConnection fc;
InputStream is;

fc = (FileConnection) Connector.open( /Imagenes/flower.jpg , Connector.READ);


is = fc.openInputStream();
Image mi = Image.createImage(is);
// Utilizar la imagen

is.close();


La clase FileConnection permite abrir un stream de 
E/S al fichero pero también contiene operaciones para 
la creación, renombrado y borrado de ficheros y 
directorios

Sistemas operativos 
móviles
Persistencia II: Ficheros


No obstante existe un problema importante: la 
estructura del sistema de ficheros de cada dispositivo 
no es estándar

Cada dispositivo contiene una raíz para cada uno de 
los medios de almacenamiento: memoria interna 
(/root, /internal, /InternalMemory) y tarjetas de 
memoria (/SDCard1, /MemoryCard)

Es posible enumerar las distintas raices existentes 
mediante el registro del sistema de ficheros:
Enumeration raicesSF = FileSystemRegistry.listRoots();
while (raicesSF.hasMoreElements()) {
raizSF = (String) raicesSF.nextElement();
// Hacer algo con la raiz encontrada
}

Sistemas operativos 
móviles
Persistencia II: Ficheros

Este gestor de persistencia utiliza el API JSR 75
import java.io.*;
import java.util.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;

class FileConnectionAPIInexistente extends Exception {}

public class DAOCuentaFC {


static DAOCuentaFC instancia = null;
String raizSF;

public static DAOCuentaFC obtenerInstancia() throws FileConnectionAPIInexistente {


if (instancia == null) {
String versionFCAPI = System.getProperty(
"microedition.io.file.FileConnection.version");
if (versionFCAPI == null) {
throw new FileConnectionAPIInexistente();
}
instancia = new DAOCuentaFC();
}
return instancia;
}

private DAOCuentaFC() {
obtenerRaizSistemaFicheros();
}

Sistemas operativos 
móviles
Persistencia II: Ficheros

public boolean existe(long numero) {


try {
cargar(numero);
}
catch(Exception e) {
return false;
}
return true;
}

public Cuenta cargar(long numero) throws IOException {


FileConnection fc = null;
DataInputStream dis = null;
Cuenta c = null;

try {
fc = (FileConnection) Connector.open(urlCuenta(numero), Connector.READ);
if (!fc.exists()) {
return null;
}

dis = fc.openDataInputStream();
c = new Cuenta(dis.readLong(), dis.readUTF(), dis.readFloat());
c.saldo = dis.readFloat();

Sistemas operativos 
móviles
Persistencia II: Ficheros

int nMov = dis.readInt();


for (int nm = 0; nm < nMov; nm++) {
c.movimientos.addElement(new Movimiento(new Date(dis.readLong()),
dis.readChar(), dis.readFloat(), dis.readFloat()));
}
}
finally {
if (fc != null) fc.close();
}

return c;
}

public void salvar(Cuenta c) throws IOException {


FileConnection fc = null;
DataOutputStream dos = null;

try {
fc = (FileConnection) Connector.open("file:///" + raizSF +
"cuentas", Connector.READ_WRITE);
if (!fc.exists()) {
fc.mkdir();
}
fc.close();

fc = (FileConnection) Connector.open(urlCuenta(c.leerNumero()),
Connector.READ_WRITE);
if (!fc.exists()) {
fc.create();
}

Sistemas operativos 
móviles
Persistencia II: Ficheros
dos = fc.openDataOutputStream();

dos.writeLong(c.leerNumero());
dos.writeUTF(c.leerTitular());
dos.writeFloat(c.leerInteres());
dos.writeFloat(c.leerSaldo());

Movimiento m;
int nMov = c.numMovimientosHistorico();
dos.writeInt(nMov);
for (int nm = 0; nm < nMov; nm++) {
m = c.leerMovimientoHistorico(nm);

dos.writeLong(m.fecha.getTime());
dos.writeChar(m.tipo);
dos.writeFloat(m.importe);
dos.writeFloat(m.saldo);
}
} finally {
if (fc != null) fc.close();
}
}

private String urlCuenta(long codigo) {


return "file:///" + raizSF + "cuentas/" +
Long.toString(codigo) + ".cnt";
}

private void obtenerRaizSistemaFicheros() {


Enumeration raicesSF = FileSystemRegistry.listRoots();
if (raicesSF.hasMoreElements()) {
raizSF = (String) raicesSF.nextElement();
}
}
} Sistemas operativos 
móviles
Persistencia II: Ficheros


Otro problema adicional son las restricciones de 
seguridad existentes en algunos dispositivos, que sólo 
permiten el acceso a determinados directorios 
públicos (/Imagenes, /Sonidos, etc.)

Sistemas operativos 
móviles
Para terminar

Para terminar

Hemos estudiado MIDP a nivel básico

En función de las necesidades de la aplicación móvil 
a implementar será necesario estudiar con mayor 
profundidad algunos de los APIs que hemos visto y 
otros nuevos

PIM API JSR 75

API MIDP para juegos

Mobile Media API JSR JSR 184

Wireless Messaging API JSR 135

Bluetooth API JSR 82

Sistemas operativos 
móviles

También podría gustarte