S9 Java per a dispositius mòbils. Sabadell, del 5 al 6 de juliol de 2007 Vicenç Soler i Juan Manuel Fernández, professors de l’Escola Universitària d’Informàtica de Sabadell. Estius Universitaris 06/07 Java Móvil J2ME Java en dispositivos móviles Vicenç Soler Juan Manuel Fernández 1 Estius Universitaris 06/07 Java Móvil J2ME Programa (I) • Java 2, Micro Edition. (1'5h) – • • – • Objetivos: Conocer las diferentes implementaciones de Java para dispositivos móviles. Introducción a la arquitectura J2ME, Presentación de la arquitectura básica de Java i como esta se adapta en función del dispositivo sobre el que se coloca, se presentan los estándares que hay detrás de esta arquitectura y se catalogan para uso futuro del alumno. Dispositivos. (1'5h) • – – – – • Configuraciones: CDC, CLCD CDC CLCD Profiles: Foundation Profile, Personal Profiles, MID Profile. JVMs y Paquetes Opcionales PDA, PocketPCs, Mobile Devices, PIM Objetivos: Catalogar los dispositivos móviles, se pretende que el alumno sea crítico a la hora de desarrollar una aplicación en J2ME para que esta cubra la mayor parte de dispositivos. Pàg: 2 Estius Universitaris 06/07 Java Móvil J2ME Programa (II) • Entornos de desarrollo (2h) – – – • Diferentes entornos IDE. Instalación del Software para desarrollo. Instalación y configuración del Emulador de PALM Objetivos: Evaluar diferentes entornos de desarrollo, se referencia un conjunto amplio de ellos, y se aporta una visión critica sobre ventajas e inconvenientes de estos, finalmente se instala un entorno tanto de desarrollo como de test de aplicaciones. Constricciones para desarrollar aplicaciones es dispositivos móviles (1h) • – – – • CPU Pantalla Memoria Objetivos: Analizar las características del entorno donde se ejecuta la aplicación con el objetivo de evidenciar las sustanciales diferencias de desarrollo que se deben considerar para los dispositivos móviles. Concienciar al alumno de las concesiones necesarias en las aplicaciones J2ME. Pàg: 3 Estius Universitaris 06/07 Java Móvil J2ME Programa (III) • Estructura básica de un Midlet (3h) – – – • Objetivos: Mostar la estructura básica de las aplicaciones para dispositivos móviles, crear una aplicación básica y analizarla, ver los problemas de desarrollo, compilación y deployment de este tipo de aplicaciones. La interfaz de Usuario (6h) • – – • Gestor de aplicaciones Ciclo de vida Estructura de un Midlet En MIDP En PersonalJava Objetivos: Presentar los controles disponibles en J2ME y PersonalJava, familiarizando al alumno con las estructuras necesarias para construir aplicaciones usables. Pàg: 4 Estius Universitaris 06/07 Java Móvil J2ME Programa (IV) • Almacenamiento de Información (3h) – – – – • Objetivos: Presentar las diferentes APIs para la gestión de la información en los dispositivos móviles en general y en algunos en particular, y como estas deben ser tratadas desde las aplicaciones para un correcto ciclo de vida. Se aborda también el almacenamiento externo de esta información. Comunicaciones (3h) • – – • • • • En MIDP Implementación en Palm OS Otros contenedores de información En PersonalJava Framework de comunicaciones en CLCD Comunicaciones en PocketPC Objetivos: Introducción a la intercomunicación de dispositivos móviles, las restricciones que por sus características se encuentran es este tipo de dispositivos. WebServices – Futuro Objetivos: Integración de las aplicaciones y los dispositivos en la empresa, y los mecanismos que se encuentran disponibles para poder realizarla. Objetivos: Análisis del futuro de las aplicaciones Java en los dispositivos móviles, mesa redonda con los alumnos para ver su opinión con respecto a este tipo de dispositivos, y análisis de tendencias del mercado. Pàg: 5 Estius Universitaris 06/07 Java Móvil J2ME Ámbito de Java Java 2 Micro Edition (J2ME) Pàg: 6 Estius Universitaris 06/07 Java Móvil J2ME Java 2, Micro Edition • Configuraciones: – J2ME se define en términos de configuraciones y de perfiles. Una configuración es un core para la funcionalidad básica, mientras que un perfil se define sobre una configuración existente. Así, un perfil proporciona una funcionalidad extendida que explota las capacidades del dispositivo sobre el que se van a ejecutar las aplicaciones. También podemos encontrar los paquetes opcionales, los cuales se definen sobre los perfiles y configuraciones. Pàg: 7 Estius Universitaris 06/07 Java Móvil J2ME Configuraciones de J2ME • • Una configuración es una combinación de una máquina virtual Java y de una colección de los interfaces de programación de aplicaciones (APIs) para una determinada clase del dispositivo. Una configuración proporciona la base para uno o más perfiles en un dispositivo. Un perfil es un sistema de APIs que dota de más funcionalidad y se adapta específicamente a las especificaciones de un determinado dispositivo. Una configuración define un sistema básico de APIs que se debe estar implementado en todos los dispositivos que soporten la configuración (dispositivos de baja potencia, con poca cantidad de memoria, etc.). El perfil que se sustenta sobre la configuración, debe implementar los APIs de la configuración, y los específicos del perfil (profile), como pueden ser los específicos de un PDA, un teléfono móvil, etc. Es importante observar que la configuración especifica las capacidades de la máquina virtual asociada, pero no impone una maquina virtual particular. Los vendedores de perfiles y configuraciones tienen libertad de proporcionar su propia máquina virtual, siempre que se adapte a la especificación (Ex. J9VM IBM, KVM SUN). Pàg: 8 Estius Universitaris 06/07 Java Móvil J2ME J2ME, CDC & CLDC – Hay dos configuraciones definidas actualmente en J2ME: la configuración de dispositivo con conexión limitada (CLDC) y la configuración de dispositivo con conexión (CDC). La CDC se piensa para PDAs y dispositivos de gama alta y con conexiones permanentes o semi permanentes. El CLDC se piensa para PDAs y dispositivos con las conexiones de red intermitentes y con memoria y CPU limitada. • A continuación se presenta un esquema de los perfiles definidos para la CDC y CLDC. – El personal profile se sitúa sobre el personal basis y el foundation profile los cuales extiende la configuración CDC. – El perfil Mobile Information Device (MID) extiende la configuración CLDC, junto con paquetes opcionales como pueden ser el Personal Information Management (PIM) y el FileConnection. Pàg: 9 Estius Universitaris 06/07 Java Móvil J2ME CLDC vs CDC (I) • Connected Limited Device Configuration (CLDC) – El CLDC 1,0 fue definido por JSR30 (Java Specification Request) y lanzado en mayo de 2000. Apunta los dispositivos con unas características básicas. Un dispositivo de CLDC: • • • • • es accionado por las baterías, Pocos recursos de proceso, Conectividad ad-hoc y de poca velocidad, 128 KB de memoria disponible para la JVM y las bibliotecas de CLDC, y tiene por lo menos 32 KB disponible para el runtime y la asignación dinámica de objetos. – Estas características definen una variedad amplia de dispositivos, incluyendo pagers, teléfonos móviles, y PDAs. El CLDC define una base común para estos dispositivos en las áreas siguientes: • • • • • • Paquetes de Java base Capacidades de lenguaje Capacidades de la JVM Conectividad e I/O Seguridad Internacionalización – No cubre otras áreas que puedan ser especificas del dispositivo, por ejemplo el interfaz de usuario, el ciclo de vida de aplicación, gestión de eventos. Estas áreas son cubiertas por los perfiles. – La máquina virtual de Java que proporciona el core de un CLDC cumple las especificaciones de JVMS y JLS con algunas excepciones. Es decir los perfiles o aplicaciones que corran sobre CLDC no dispondrán de las siguientes características: Pàg: 10 Estius Universitaris 06/07 Java Móvil J2ME CLDC vs CDC (II) • Connected Limited Device Configuration (CLDC) – Restricciones referentes a JLS (Java Language Specification) • • • Sin soporte de coma flotante (ninguna operación de coma flotante, literales de coma flotante, tipos, o valores). Sin soporte a la finalización. Soporte básico de excepciones, el número de las clases de error es limitado. – Restricciones referentes a JVMS (Java Virtual Machine Specification) • • • • • • • • • Ningún soporte a coma flotante.. Ningún Interfaz Nativo de Java (JNI). No se soportan los class-loaders de usuario. Inexistencia de la API Reflection. Sin Thread groups ni daemon Threads. Sin soporte a la finalización. Sin Weak References. Método diferente de verificación de classfile Formato de classfile y cargador (loader) diferente. – El CLDC hereda la mayoría de sus clases de J2SE, y define algunas clases especificas de CLDC. Las clases heredadas de J2SE utilizan los nombres comunes de la clase y del paquete. Las clases especificas usan el prefijo javax.microedition. Pàg: 11 Estius Universitaris 06/07 Java Móvil J2ME CLDC vs CDC (III) • Connected Limited Device Configuration (CLDC) – La versión siguiente de CLDC fue definida por JSR139 (Java Specification Request), que fue aprobado en Marzo de 2003. Los cambios en CLDC 1,1 son los siguientes: • • • • • • Se agrega la coma flotante. float y double a java.lang , y algunos métodos en otras clases permiten valores en coma flotante. Las clases afectadas incluyen java.lang.Math, java.io.DataOutputStream, java.io.DataInputStream, y java.util.Random. Soporte básico para referencias Weak de J2SE's. Se agrega el paquete java.lang.ref. Las clases Calendar, Date y TimeZone en java.util son más consistentes con las versiones de J2SE. Se ha agregado la clase Error en java.lang.NoClassDefFoundError. Algunos métodos añadidos a clases existentes, por ejemplo el método intern() a la clase java.lang.String, y el método toString() a la clase java.util.Date. La especificación completa de CLDC 1,1 está disponible de http://www.jcp.org/jsr/detail/139.jsp . • Connected Device Configuration (CDC) – La CDC es un súper conjunto de CLDC. La CDC incluye todas las APIs definidas por el CLDC, incluyendo los paquetes java.* y javax.microedition.*. La CDC se diseña para los dispositivos de más memoria (2 MB o más, disponible para la plataforma de Java) y una conexión mejor de red (desde 9600 bps en adelante). La CDC hereda de PersonalJava, por tanto las aplicaciones de PersonalJava que no utilicen AWT (Abstract Window Toolkit) deberían ser portables a CDC (las capacidades de AWT se definen en los perfiles del CDC). Pàg: 12 Estius Universitaris 06/07 Java Móvil J2ME CLDC vs CDC (IV) • Connected Device Configuration (CDC) – Una implementación de CDC debe soportar totalmente JLS y JVMS. – Los paquetes de la CDC se diseñan para ser un sistema completo de APIs para apoyar la JVM. Se toman de J2SE 1,3, eliminando los APIs deprecados. El sistema de paquetes resultante es el siguiente: • java.io, incluyendo BufferedReader, BufferedWriter, ObjectInputStream, y ObjectOutputStream • java.lang • java.lang.ref • java.lang.reflect • java.math • Clases de java.net de J2SE, incluyendo URL, URLConnection, InetAddress, y SocketPermission • java.security encriptación para la serialización de objetos. Sin soportar firma segura de código, certificados, almacenamiento de claves, JDK 1.1 Identity, e IdentityScope. • java.security.cert • java.text, con soporte mínimo para i18n (internationalization) • java.util, clases de J2SE, incluyendo Array, BitSet, Calendar, LinkedList, Stack, Vector • java.util.jar • java.util.zip • javax.microedition.io – Cualquier implementación de CDC deben soportar la entrada-salida del archivo (I/O) (por lo menos en modo read-only) y datagramas. Pàg: 13 Estius Universitaris 06/07 Java Móvil J2ME Profiles CLDC • • • • Actualmente sólo existe un perfil (profile) para la configuración CLDC. Este profile (MIDP) Mobile Information Device Profile, fue lanzado por SUN en Octubre de 2001 para los dispositivos PALM. El ámbito del perfil esta pensado para dispositivos mucho más limitados en recursos, como pueden teléfonos móviles, y pagers. La ventaja de la elección de este perfil, es que aporta la mínima expresión para todos los dispositivos, de este modo una aplicación que corra sobre este perfil, podrá ejecutarse en todos los dispositivos que lo implementen. Pàg: 14 Estius Universitaris 06/07 Java Móvil J2ME CLCD: MIDP (I) • • La especificación de MIDP define los requisitos adicionales para el dispositivo destino, más allá de los requisitos necesarios para CLDC. Definido en JSR37, MIDP impone la necesidad de 128 KB adicionales de memoria permanente para los componentes de MIDP, 8 KB para los datos persistentes creados y usados por las aplicaciones, y 32 KB para el Java heap. La especificación MIDP 1.0 sobre CLDC 1.0, proporcionan funcionalidad en los apartados siguientes: – – – – – • MIDP no cubre las áreas siguientes: – – – • Gestión de ciclos de vida de la aplicación. Interfaz de usuario Almacenamiento persistente Redes Timers APIs A nivel sistema Instalación y almacenaje de la aplicación Seguridad más allá de lo especificado en CLDC. MIDP proporciona nuevas clases en java.lang, java.util, y javax.microedition.io, y define los nuevos paquetes para el interfaz de usuario, el almacenamiento persistente, y las extensiones para la gestión del ciclo de vida de la aplicación. Estos paquetes se denominan javax.microedition.lcdui, javax.microedition.rms, y javax.microedition.midlet, respectivamente. Pàg: 15 Estius Universitaris 06/07 Java Móvil J2ME CLDC: MIDP (II) • Una aplicación MIDP se llama MIDlet. Un MIDlet es parte de un grupo de MIDlets llamado una “suite” de MIDlet. Las suites de MIDlet pueden compartir recursos, tales como datos persistentes en una base de datos del Record Management System (RMS) en el dispositivo. Una aplicación de MIDP debe extender la clase MIDlet e implementar tres de sus métodos definidos como abstractos: startApp, pauseApp, y destroyApp. Estos métodos son llamados por el sistema cuando se requiere que el MIDlet cambie de estado. Un MIDlet tiene los estados siguientes: – – – Pausado. Cuando el sistema requiere que el MIDlet entre en estado pausado, llama el método pauseApp para permitir liberar los recursos compartidos. Activo. Se llama el método startApp después de que se cree una instancia del MIDlet, y cada vez que se abandona el estado pausado. Destruido. Cuando se invoca destroyApp el MIDlet que debe almacenar su estado y liberar cualquier recurso que tuviera asignado. • El desarrollador puede también hacer que el MIDlet entre en estos estados, usando los métodos notifyPaused, notifyDestroyed, y resumeRequest. • MIDP 2.0 se construye sobre MIDP 1.0, es compatible hacia atrás, esto garantiza que las aplicaciones desarrolladas para MIDP 1.0 también funcionen en MIDP 2.0. Definido en JSR118, la especificación final fue lanzada en noviembre de 2002. Asume funcionalidad de CLDC 1.0, aunque también trabajará con CLDC 1,1. MIDP 2.0 agrega algunos nuevos paquetes: • – – – • javax.microedition.lcdui.game. Este paquete incluye las clases para crear una infraestructura para juego. Incluye clases GameCanvas y Sprites. javax.microedition.media y javax.microedition.media.control. MIDP 2.0 incluye un subconjunto de Movile Media API (JSR135) y generación de tonos y reproducción de sonido. javax.microedition.pki. Certificados para las conexiones de red seguras. Se puede obtener una copia de la especificación de MIDP 2.0, en http://www.jcp.org/jsr/detail/118.jsp . Pàg: 16 Estius Universitaris 06/07 Java Móvil J2ME CLDC: Paquetes Opcionales • • • De igual modo que el profile MIDP, para explotar las características de estos dispositivos se dispone de paquetes que ofrecen una API Java para acceder a estos recursos. En el JSR075 se especifican los paquetes opcionales que se pueden construir sobre CLDC 1.0 o superiores. Estos son el PIM y FileConnection. Aunque fueron definidos por el mismo JSR pueden implementarse de forma independiente. Paquete Opcional de PIM (Personal Information Management) – • El paquete opcional PIM añade el paquete javax.microedition.pim a CLDC. El propósito de este paquete es proveer al desarrollador el acceso y gestión de la libreta de direcciones, la lista de tareas y el calendario del PDA. Paquete Opcional FileConnection – El paquete opcional de FileConnection agrega a CLDC 1.0 o superior el paquete javax.microedition.io.file. Este paquete añade otro tipo de conexión al framework genérico de conexiones (GCF), y proporciona el acceso al sistema de ficheros del PDA. El sistema de ficheros puede estar en el propio dispositivo, en tarjetas de memoria tales como CompactFlash (CF), Secure Digital (SD), Multimedia Card (MMC), SmartMedia (SM), o en otros sistemas de almacenamiento. Pàg: 17 Estius Universitaris 06/07 Java Móvil J2ME CDC Profiles (I) • • • • • • • Los dispositivos PoketPC acostumbran a incluir distribuciones de PersonalJava, formalmente Personal Java es parte de J2SE, se apuntaran las diferencias entre las implementaciones de PersonalJava y J2ME. Foundation Profile El foundation profile fue desarrollado por el JCP como JSR46 http://www.jcp.org/jsr/detail/46.jsp. Puede ser descargado de http://java.sun.com/j2me/index.jsp. Una implementación del foundation profile debe soportar los protocolos especificados por la CDC, y además debe apoyar los sockets y HTTP. Personal Basis Profile Este profile proporciona la capacidad para una presentación básica de interfaz de usuario, pero no tiene soporte para GUI’s de alta funcionalidad. El Personal Basis Profile proporciona únicamente soporte para componentes ligeros de AWT. Las principales diferencias entre este profile y las funcionalidades de PersonalJava son: – – – • PersonalJava implementa el JDK 1.1.8, mientras que el Personal Basis Profile implementa JDK 1,3. Era opcional incluir Remote Method Invocation (RMI) en PersonalJava. En el Personal Basis Profile, el RMI es soportado por un paquete opcional. Un volumen importante de APIs deprecadas no se incluye en el Personal Basis Profile. El Personal Basis Profile fue desarrollado por el JCP como JSR129 http://www.jcp.org/jsr/detail/129.jsp. Pàg: 18 Estius Universitaris 06/07 Java Móvil J2ME CDC Profiles (II) • • • Personal Profile El personal profile es el camino para la migración hacia J2ME de las aplicaciones de PersonalJava, y fue desarrollado por el JCP como JSR62. Ester Profile añade al Personal Basis Profile soporte para Web y entorno para la ejecución de aplicaciones heredadas de PersonalJava. El Personal Profile es el perfil de la CDC ideado para PDAs. Las aplicaciones escritas para las APIs del Personal Profile son compatibles hacia arriba con JDK 1.3 de J2SE. El perfil personal se piensa para aplicaciones que requieren soporte completo de JDK 1.1 AWT (es decir, componentes GUI complejos). Especifica tres modelos de aplicaciones: – – – • Applet. Applet estándares del JDK 1.1. Xlets. Un Xlet es un interfaz de la gestión del ciclo de vida, similar al MIDlet. Un Xlet define tres métodos. El sistema hace que el Xlet cambie su estado. Los estados definidos son Destroyed, Paused, y Active. Aplicaciones. Aplicaciones estándar de Java, definido como clase con un método public static void main(String[]). El Personal Profile agrega al Foundation Profile estos paquetes: – – – – – – – – – – – – java.applet java.awt java.awt.color java.awt.datatransfer java.awt.event java.awt.image java.beans java.math java.rmi java.rmi.registry javax.microedition.xlet javax.microedition.xlet.ixc Pàg: 19 Estius Universitaris 06/07 Java Móvil J2ME CDC Profiles (III) • • • Diferencias entre el perfil personal y JDK 1.3 Los paquetes y las clases del Personal Profile son típicamente subconjuntos de los paquetes y de las clases del JDK 1.3. Hay un conjunto pequeño de APIs en el Personal Profile que tiene restricciones en su uso. Son: – – – – – – • java.awt.AlphaComposite. Aproximación de la regla de SRC_OVER. java.awt.Component. La implementación puede ignorar las llamadas para fijar el cursor visible. java.awt.Dialog. La implementación puede limitar el tamaño, puede impedir redimensionar, puede limitar la localización en la pantalla, y puede no soportar un título visible. java.awt.Frame. Las mismas restricciones que a Dialog pueden aplicarse a Frame. java.awt.Graphics2D. Solamente instancias de AlphaComposite se pueden utilizar con setComposite() . java.awt.TextField. Alguna implementación puede no permitir fijar el carácter de echo. En cada caso, una propiedad del sistema deberá ser puesta a true si la implementación del Personal Profile tiene alguna de las restricciones anteriores. Estas propiedades del sistema tienen las siguientes claves: – – – – – – – – – – – – java.awt.AlphaComposite.SRC_OVER.isRestricted java.awt.Component.setCursor.isRestricted java.awt.Dialog.setSize.isRestricted java.awt.Dialog.setResizable.isRestricted java.awt.Dialog.setLocation.isRestricted java.awt.Dialog.setTitle.isRestricted java.awt.Frame.setSize.isRestricted java.awt.Frame.setResizable.isRestricted java.awt.Frame.setLocation.isRestricted java.awt.Frame.setState.isRestricted java.awt.Frame.setTitle.isRestricted java.awt.TextField.setEchoChar.isRestricted Pàg: 20 Estius Universitaris 06/07 Java Móvil J2ME CDC Profiles (IIII) • • • • • Diferencias entre el Personal Profile y PersonalJava PersonalJava era el Java original para los dispositivos de gama alta y apliances, pero será reemplazado por el Personal Profile. El Personal Profile es una nueva definición, basada en J2ME. Cuando los diseñadores del perfil personal comenzaron a definirlo, lo hicieron con JDK 1.3, quitado todos los APIs deprecados y que consideraron innecesarios para los dispositivos móviles modernos. PersonalJava se basa en las APIs de JDK 1.1. Diferencias entre PersonalJava y JDK 1.1.8 PersonalJava 1.2 hereda las APIs de JDK 1.1.8, modifica ligeramente a muchos de ellos, convirtiendo alguno en opcional, y agrega algunos específicos a PersonalJava. También hereda algún APIs de Java 1.2 para apoyar seguridad en control de acceso y firmas de código. La portabilidad del código sin modificación de JDK 1.1.8 a PersonalJava es por lo tanto posible pero dependerá de la aplicación. La mayoría de las ocasiones en que una aplicación no funciona con PersonalJava son ocasionados por diferencias en las APIs de seguridad. Tal y como se ha comentado anteriormente PersonalJava utiliza las APIs de seguridad de Java 1.2 en vez de JDK 1.1.8. Sin embargo, existe un gran parecido entre JDK 1.1.8 y PersonalJava 1.2, de modo que el código fuente será bastante portable entre las dos plataformas. javax.microedition.* Pàg: 21 Estius Universitaris 06/07 Java Móvil J2ME Dispositivos • • • • • • Por que utilizando Java nos hemos de preocupar de la plataforma? Tal i como se ha discutido en la presentación anterior J2ME no es totalmente portable, hemos de considerar aspectos como la JVM donde se ejecutara nuestra aplicación (PersonalJava y MIDP), así como los paquetes opcionales de los que disponga el dispositivo destino. Por norma general se recomienda estructurar la aplicación en el código funcional común que se pueda ejecutar independiente de la plataforma, y separarlo de la presentación de usuario, la persistencia y conectividad, esto puede ser una tarea compleja. Dado que el punto anterior es de difícil cumplimiento, normalmente se escoge la plataforma destino antes de diseñar la aplicación, dado que muchas aplicaciones para dispositivos móviles son orientadas a cliente servidor, esto afectara significativamente a diseño y realización de la aplicación. A continuación vamos a enumerar algunos de los dispositivos móviles más comunes y sus características más significativas. Al seleccionar una plataforma PDA para el desarrollo de Java, hay un gran número de factores a considerar. En la consideración de estos factores, es importante recordar los dos subconjuntos principales de dispositivos, dependiendo del SO: Palm OS y PocketPCs. Estos tienen filosofías totalmente diferentes, a continuación se enumeran algunas de ellas. Es importante considerar siempre que aunque Java funcionará en ambos dispositivos, la riqueza de la plataforma varía, según las capacidades del dispositivo, y, por consiguiente, la configuración. Esto es principalmente debido a las diferencias en filosofía de diseño de las configuraciones de J2ME según el tipo de dispositivo. Pàg: 22 Estius Universitaris 06/07 Java Móvil J2ME Palm OS vs PocketPCs Dispositivos Palm OS PocketPCs Herencia de los PIM. Los dispositivos originales de PALM OS eran PIMs de gama alta con pantallas grandes y la capacidad de escribir en vez de mecanografiar. Herencia del PC. El PocketPCs es básicamente un PC en miniatura. Funcionalidad simple. PALM se caracteriza por realizar tareas simples de forma elegante. Rica funcionalidad. Un PocketPC es básicamente un PC con Windows o con Linux (Sharp Zaurus) con funcionalidades limitadas, esto deja una “look and feel” de PC al dispositivo. Como ejemplo el menú de inicio y el sistema de ficheros siguen siendo igual. Energía de proceso baja y larga duración de la batería. Los dispositivos PALM OS funcionan a con CPUs de 20 MHz o 33 MHz, y típicamente 8 M de la memoria. Los nuevos dispositivos PALM OS basados en procesadores ARM y XScale aparecidos en el 2003 aumentan las capacidades de proceso y de memoria asemejándose a los PocketPC. Alta energía de proceso y una vida más corta de las baterías. Los PocketPCs disponen actualmente de CPUs de 200 MHz a 400 MHz, y sobre 32Mb a 64Mb de RAM. Pàg: 23 Estius Universitaris 06/07 Java Móvil J2ME Comparativa de precios en USD Diciembre 2002 PocketPC Men or Mayo Palm OS r Men or Mayor Casio E-200 $600 $650 Handspring Treo 270 $500 $700 HP iPaq 3970 $715 $780 Palm m515 $300 $400 Compaq iPaq 3870 $537 $680 Palm i705 $298 $450 Toshiba e740 $550 $600 Sony CLIE PEGNR70V $510 $600 Media $601 $678 Media $402 $538 En esta selección de dispositivos high-end PocketPC y Palm, podemos observar que los PocketPC son entre un 25% y un 50% más caros que los dispositivos high-end Palm OS. Pàg: 24 Estius Universitaris 06/07 Java Móvil J2ME Factores a considerar en la decisión de la plataforma (I) • Coste – • PocketPCs es generalmente más costoso que los dispositivos Palm OS. Tal i como se puede observar en la tabla anterior. Estándar Corporativo – • Si hablamos de desarrollos para usuarios corporativos, o para la propia organización, los estándares corporativos para PDAs afectan claramente a la eleción de la plataforma. Según el grupo tecnológico Winn (en fecha diciembre de 2002), Palm OS ha sido elegido por el 85% de las compañías que comprende Fortune 1000. Fuente: Diez razones de elegir un Handheld Palm, 2002, http://www.palmsource.com/includes/top_ten_reasons_to_choose_palm_powered.pdf . Riqueza de funcionalidad – • Desde la perspectiva de un desarrollador de Java, la riqueza funcional de la plataforma depende de si se tiene acceso a él desde Java. Todos los PDAs tienen funciones estándares de PIM (es decir, libros de direcciones, notas, listas de la tarea, y calendarios). El paquete opcional de PIM se diseña para permitir el acceso fácil a las funciones de PIM de un PDA desde Java. PersonalJava no tiene específicamente una API PIM, sino que proporciona el acceso a la funcionalidad del sistema operativo y las aplicaciones con JNI. Sin embargo, el grado de accesibilidad con JNI depende de la disponibilidad de una biblioteca del API para tener acceso a la funcionalidad. Riqueza del soporte Java – El soporte Java es importante si se es desarrollador Java que desea escribir aplicaciones para PDAs. Aunque PersonalJava es más rico en APIs de Java y más cercano a J2SE que MIDP y los paquetes opcionales de CLDC, PersonalJava carece el APIs para tener acceso a las características especificas de un PDA. Pàg: 25 Estius Universitaris 06/07 Java Móvil J2ME Factores a considerar en la decisión de la plataforma (II) • Soporte Wireless – • Market Share - Actual y tendencia – • Aunque ambos dispositivos son capaces de operar wireless, tanto con soporte WiFi y Bluetooth, la disponibilidad de estas características para aplicaciones Java es limitado. Tomará un cierto tiempo hasta que las APIs Java maduren y para que los vendedores agreguen estas APIs a sus máquinas virtuales de Java (VMs) en los PDAs. En los años 90, el Palm OS era el sistema operativo dominante para PDA en el mercado. Desde entonces, Microsoft ha desafiado esa hegemonía con cierto éxito. En 2002, los PocketPCs eran una alternativa fuerte con crecimiento en cuota de mercado. La tendencia desde entonces es un crecimiento de PocketPC en detrimento de Palm OS. Donde estará el vendedor / fabricante del dispositivo en dos años? – La mayoría de los fabricantes de PDAs tendrán a corto plazo nuevos modelos basados en la CPU de Intel XScale. Esto provocara una clara disminución de las diferencias Hardware entre dispositivos Palm OS y PocketPC, como ejemplo destacar que Palm OS v5 es funcionalmente idéntico a las versiones anteriores, pero sin las limitaciones que tenían sus predecesores. Pàg: 26 Estius Universitaris 06/07 Java Móvil J2ME Comparativa PDAs • Clasificación Java vs PDA – PersonalJava está disponible en los dispositivos de PocketPC, mientras que MIDP está disponible en los dispositivos Palm OS. A continuación se enumeran las implementaciones J2ME actualmente disponibles. PersonalJava se incluye en la tabla aunque no es estrictamente una implementación J2ME, por el contrario está disponible para casi cada dispositivo PocketPC. • Comparación de dispositivos Palm OS – Los dispositivos Palm estan evolucionando rápidamente, tanto a nivel Hardware como SO. También existen nuevos fabricantes que crean dispositivos que ejecutan Palm OS, a continuación se muestra una tabla con una selección de los dispositivos producidos por Palm Inc. y con licencias de Palm OS. Pàg: 27 Estius Universitaris 06/07 Java Móvil J2ME Clasificación Java vs PDA Operating System CPU Device Java Product PocketPC 2002 StrongARM HP iPaq 3800 series PersonalJava 1.2 Insignia Jeode PDA Edition PocketPC 2002 Intel XScale Toshiba GENIO e550G PersonalJava 1.2 Insignia Jeode PDA Edition Lineo's Embedix Linux StrongARM Sharp Zaurus SL-5500 PersonalJava 1.2 Insignia Jeode PDA Edition Windows CE 3.0 StrongARM HHP Dolphin 7400 PersonalJava 1.2 Insignia Jeode PDA Edition PocketPC 2002 StrongARM NEC PocketGear PersonalJava 1.2 Insignia Jeode PDA Edition Windows CE 3.0 StrongARM Samsung NEXiO S150 PersonalJava 1.2 Insignia Jeode PDA Edition PocketPC 2002 Intel XScale Fujitsu Pocket LOOX PersonalJava 1.2 Insignia Jeode PDA Edition PocketPC 2002 StrongARM Compaq iPaq as a reference platform CDC/Foundation 1.0 IBM WebSphere Micro Environment PocketPC 2002 StrongARM Compaq iPaq as a reference platform CLDC/MIDP 1.0 IBM WebSphere Micro Environment Palm OS 68K Palm III, Palm V, Palm Vx as a reference platform CLDC/MIDP 1.0 IBM WebSphere Micro Environment Palm OS 68K Various CLDC/MIDP 1.0 Esmertec Micro Edition CLDC Palm OS 3.5.x 68 K Various; capable of running 3.5.x CLDC/MIDP 1.0 MIDP for Palm OS 1.0 Windows CE 2.11 MIPS or SH3 IBM Workpad Z50, Compaq Aero 2100, HP Jornada 430 SE, and Oth. PersonalJava 1.1.3 Sun PersonalJava Runtime Environment for Windows CE 2.11 Version 1.0 Pàg: 28 Estius Universitaris 06/07 Java Móvil J2ME Comparación de dispositivos Palm OS Device Total RAM Dynamic Heap[a] Palm OS[b] CPU Type CPU Speed Palm IIIx 4 MB 128 KB 3.1 Dragonball EZ 16 MHz Palm V 2 MB 128 KB 3.1 Dragonball EZ 16 MHz Palm VII 2 MB 128 KB 3.2.0/3.2. 5 Dragonball/Dragonball EZ 16 MHz Palm VIIx 8 MB 256 KB 3.5 Dragonball EZ 20 MHz Palm i705 8 MB Handspring Visor 2 MB 128 KB 3.1 Dragonball EZ 16 MHz Handspring Visor Edge 8 MB 256 KB 3.5.2 Dragonball VZ 33 MHz IBM WorkPad (Original) 4 MB 96 KB 3.0 Dragonball EZ 16 MHz Qualcomm pdQ 1900 2 MB 128 KB 3.02 Dragonball EZ 16 MHz Sony CLIE PEG-S500c 8 MB 256 KB 3.5 Dragonball EZ 20 MHz Supra eKey 2 MB 128 KB 3.1 Dragonball EZ 16 MHz Symbol SPT1740 2/4/8 MB 128 KB 3.2 Dragonball 16 MHz TRG TRGpro 8 MB 128 KB/256 KB 3.3/3.5.1 Dragonball EZ 16 MHz • • • 4.1 Fuente: http://www.palmos.com/dev/tech/hardware/compare.html. [a]: Dependiendo de la versión de Palm OS instalada [b]: Esta versión es la de referencia, en algunos dispositivos puede haberse upgradeado. Pàg: 29 Estius Universitaris 06/07 Java Móvil J2ME Preparando el entorno de desarrollo • A continuación se enumerara el software necesario para el desarrollo de las aplicaciones de ejemplo de este curso. Las herramientas utilizadas están disponibles de forma libre o con mínimo coste, se han evitado los IDEs comerciales por las siguientes razones: – Aprender a programar en una nueva plataforma es más eficiente contra más elemental es el entorno de desarrollo, la utilización de un IDE a menudo oculta aspectos fundamentales de la programación y el deployment de la aplicación. Siempre se esta a tiempo de utilizar un IDE, cuando se entiendan los mecanismos de construcción de aplicaciones en la plataforma. – Se dispone de mayor libertad de programación, se pueden realizar cosas que a menudo no son posibles con un IDE. – El objetivo de este curso es demostrar que cualquiera puede desarrollar aplicaciones Java para PDAs. Las herramientas costosas no son de momento necesarias. Pàg: 30 Estius Universitaris 06/07 Java Móvil J2ME Las herramientas que utilizaremos son: • Un editor de textos, como TextPad ( http://www.textpad.com/ ) o UltraEdit ( http://www.ultraedit.com/ ). El editor de textos debería poder destacar la sintaxis Java y XML de modo que el código fuente sea fácil de leer. • Java SDK ( http://java.sun.com/j2se/downloads.html ). Utilizaremos 1.1.8 (para compilar código fuente de PersonalJava) y 1.4 (para el resto). • Emulador de Palm ( http://www.palmos.com/dev/tools/emulator/ ). • Sun's J2ME Wireless Toolkit ( http://java.sun.com/products/j2mewtoolkit/download.html ). • MIDP de Sun para Palm ( http://java.sun.com/products/midp4palm/index.html ). Aunque es libre descargar para propósitos de desarrollo personal, se debe observar que MIDP para Palm no es libre para distribuir comercialmente. Pàg: 31 Estius Universitaris 06/07 Java Móvil J2ME Configurando el emulador de Palm OS (I) • • • El emulador de Palm OS (POSE) es una parte esencial en un toolkit de desarrollo PDA Java. Antes de descargar una aplicación en el PDA es recomendable realizar un test en el entorno POSE. Esto implica un bucle de programación - prueba - corrección mucho más rápido. POSE está disponible para Windows, MacOS, y Unix. También es necesaria una ROM de Palm OS para cargar en el emulador. Se incluyen dos ROMs una correspondiente a una PDA Ibm C3, y otra a una PDA Palm m505, si se dispone de un dispositivo Palm OS puede descargarse la ROM del dispositivo al PC con el software incluido. Cuando se ejecuta el emulador de Palm OS, aparece una pantalla similar a esta. Seleccionamos New para crear una nueva sesión del emulador tal y como se observa en el siguiente grafico. Pàg: 32 Estius Universitaris 06/07 Java Móvil J2ME Configurando el emulador de Palm OS (II) • En este momento ya dispondremos de un entorno de emulación totalmente funcional. Pàg: 33 Estius Universitaris 06/07 Java Móvil J2ME J2ME Wireless Toolkit • J2ME Wireless Toolkit de Sun (J2MEWTK) es un conjunto de herramientas para desarrollar aplicaciones para la plataforma CLDC/MIDP. Funciona en Windows, Solaris, y Linux, y proporciona un entorno de emulación para diversos dispositivos. También es capaz de utilizar POSE para emular dispositivos Palm. El J2MEWTK permite cualquier editor de textos para corregir los archivos fuente. • La JVM proporcionada por J2MEWTK es KVM, una máquina virtual compacta que comprende los dispositivos con menos de un mega de memoria. Dirigirse a http://java.sun.com/products/cldc/wp/KVMwp.pdf para más información sobre KVM. • Se debe instalar J2ME Wireless Toolkit en el directorio por defecto. Pàg: 34 Estius Universitaris 06/07 Java Móvil J2ME MIDP para Palm OS • Si se escoge un entorno genérico de desarrollo MIDP para Palm será necesaria una utilidad para convertir la aplicación MIDP (JAR/JAD) en un PRC (ejecutable para Palm), esto es realizado por la suite MIDP de Sun. – • Incluido en el MIDP para Palm: – – – • Destacar que J2MEWTK también incluye esta funcionalidad, pero no incluye MIDP para Palm. J2MEWTK produce el archivo JAD y lo convierte a PRC solamente cuando se utiliza conjuntamente con el emulador de Palm. Un JAD es un archivo de parámetros para definir valores predefinidos de un MIDlet, y valores definidos por el usuario. El conversor de MIDP para Palm permite que el desarrollador convierta cualquier conjunto JAD/JAR en un PRC. Una utilidad para convertir un MIDP estándar JAD/JAR en un PRC para descargar en el dispositivo. Una implementación de KVM y de las bibliotecas de CLDC/MIDP para Palm. Algunos aplicaciones java de ejemplo. MIDP para Palm ocupa unos 590 KB de memoria y funciona en los dispositivos siguientes: – – Palm OS 3.5.x. Disponer por lo menos de 4 MB de memoria total. • MIDP para Palm también incluye la capacidad de capturar los streams System.out y System.err. • Para instalar el entorno MIDP para Palm tan sólo es necesario sincronizar el archivo MIDP.prc en el dispositivo. Pàg: 35 Estius Universitaris 06/07 Java Móvil J2ME Ejecutar aplicaciones java en Palm (I) • • Como norma general para la creación de cualquier aplicación para Palm deberemos seguir los siguientes pasos: Compilación de la aplicación: – – – – • El compilador utilizado será versión 1.1, se ha de tener en cuenta que tanto MIDP como CLDC están basado en el bytecode de Java 1.1. Los parámetros para una compilación básica: <directorio de jdk 1.1>\bin\javac.exe -d <directorio de salida del class> -classpath <path de midp>\midpapi.zip;<cualquier otro necesario> <fichero a compilar> Ex: c:\jdk1.1.8\bin\javac.exe -d .\tmp -classpath C:\WTK104\lib\midpapi.zip Clase.java En este punto disponemos del código fuente compilado, pero para poder ejecutar este código en una KVM se debe realizar un proceso de preverificación, este proceso se realiza de la siguiente forma: – – – Cuando se trabaja con J2SE la máquina virtual Java (JVM) lleva a cabo un proceso de verificación en tiempo de ejecución. Esto ocupa ciertos recursos que en dispositivos inalámbricos son relativamente escasos. Debido a las restricciones de estos dispositivos se ha creado en J2ME un proceso denominado preverification consistente en llevar a cabo parte de la verificación de la KVM off-line, el resto será llevado a cabo como una verificación normal. <directorio de JME Wireless Toolkit>\bin\preverify.exe -d <directorio de salida del class> -classpath <path de midp>\midpapi.zip;<cualquier otro necesario> <path de las clases> Ex: c:\WTK104\bin\preverify.exe -d .\class -classpath c:\WTK104\lib\midpapi.zip;.\tmp .\tmp Pàg: 36 Estius Universitaris 06/07 Java Móvil J2ME Ejecutar aplicaciones java en Palm (II) • Como hemos indicado, para construir un "ejecutable" Palm (PRC) se ha de disponer de una dupla (JAR/JAD). para crear el JAR que nos sirva de base al PRC a partir de .class, necesitaremos un archivo especial (manifest) que describirá la aplicación midlet. Concretamente: – – – – • El nombre de la aplicación, el icono a utilizar, y el nombre de la clase de la aplicación. Vendedor e información de la versión. Versión de J2ME requerida. Ej: MIDlet-1: TestSimple, , com.f2i.jmd.SimplestMIDlet MIDlet-Name: TestSimple MIDlet-Vendor: Antoni Ros MIDlet-Version: 1.0 MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0 Atributos requeridos para el archivo manifest: Pàg: 37 Estius Universitaris 06/07 Java Móvil J2ME Ejecutar aplicaciones java en Palm (III) • Atributos opcionales del archivo manifest: • Con el archivo manifest anterior, debemos ejecutar – – • <directorio de jdk 1.1>\bin\jar.exe cvfm <archivo de salida.jar> <archivo manifest a utilizar> <clases y recursos a incluir en el jar> Ex: c:\jdk1.1.8\bin\jar.exe cvfm .\jar\Simple.jar .\resources\SimplestMIDlet.mft .\class En este punto ya disponemos de el fichero JAR, solo falta crear el JAD correspondiente, un archivo JAD describe el paquete JAR, entre otros campos puede incluir los siguientes: MIDlet-Version: 1.0 MIDlet-Vendor: Antoni Ros MIDlet-Jar-URL: ../jar/Simple.jar MIDlet-Jar-Size: 2056 MIDlet-Name: TestSimple – Se debe tener en cuanta que generalmente entre diferentes minor versions de nuestros midlets el único dato que variara en el archivo jad será el tamaño del archivo jar. Pàg: 38 Estius Universitaris 06/07 Java Móvil J2ME Ejecutar aplicaciones java en Palm (IV) • Atributos requeridos para el archivo jad: • Atributos opcionales para el archivo jad: • En este instante es posible crear el archivo PRC correspondiente. – – <directorio de jdk 1.1>\jre\bin\java.exe" -classpath “<directorio donde se ha instalado el midp4palm>\midp4palm1.0\Converter\Converter.jar" com.sun.midp.palm.database.MakeMIDPApp -jad <archivo jad a utilizar> type Data -o <archivoprc a construir> <archivo jar> Ex: "C:\Program Files\j2sdk_nb\j2sdk1.4.2\jre\bin\java.exe" -classpath "C:\Documents and Settings\toni\Mis documentos\Curso Java\Software a llevar\midp4palm-1_0\midp4palm1.0\Converter\Converter.jar" com.sun.midp.palm.database.MakeMIDPApp -jad .\resources\Simple.jad -type Data -o .\prc\Simple.prc .\jar\Simple.jar Pàg: 39 Estius Universitaris 06/07 Java Móvil J2ME Ejecutar aplicaciones java en Palm (V) • En el punto anterior se utiliza la aplicación MakeMIDPApp que acompaña al paquete MIDP de Sun para Palm, esta aplicación esta sita en Converter.jar. Las opciones para MakeMIDPApp es: Uso: Java com.sun.midp.palm.database.MakeMIDPApp [ - opciones ] < archivo JAR > donde las opciones incluyen: -v -verbose -icon <file> Verbose output (-v -v gives even more information) Same as –v File containing icon for application. Must be in bmp, pbm, or bin (Palm Resource) format. -smallicon <file> Same as –smallicon -name <name> Short name of application, seen in the launcher -longname <name> Long name for the application, seen in beaming, etc. -creator <crid> Creator ID for the application -type <type> File type for application (default is appl) -outfile <outfile> Name of file to create on local disk; this is the file that is downloaded to the Palm -o <outfile> Same as –outfile -version <string> Change version -help Print this message -jad <file> Specify a file for JAD, MIDlet Suite Packaging • Palm recomienda que los desarrolladores para Palm utilicen un identificador único "Creator ID". Este campo es un identificador de 4 caracteres y se puede obtener en http://dev.palmos.com/creatorid/ – – Si no se especifica ningún identificador de creador el software asigna uno arbitrario. En este punto ya se dispone de un archivo PRC que puede ser transferido al dispositivo y ejecutado. Pàg: 40 Estius Universitaris 06/07 Java Móvil J2ME Ejecutar aplicaciones java en PocketPC • Al no disponer de ningún emulador de PocketPC con un soporte Java adecuado para PC en el momento del curso no podremos llevar a la practica los pasos aquí detallados. El deploy de una aplicación de PocketPC es más simple que en Palm, principalmente por que todos estos dispositivos utilizan PersonalJava 1.2, que es equivalente a JDK 1.1.8. • Para instalar una aplicación en un PocketPC basta con crear el jar correspondiente, sincronizarlo con la carpeta seleccionada del dispositivo, y crear el acceso directo. • Dado que la gran mayoría de PocketPC actuales utilizan Jeode JVM como implementación de PersonalJava, se enumeran los pasos para crear una aplicación Java en un PocketPC – Compilación de la aplicación: • <directorio de jdk 1.1>\bin\javac.exe -d <directorio de salida del class> -classpath < directorio de jdk 1.1 >\lib\classes.zip;<cualquier otro necesario> <fichero a compilar> – Creación del jar contenedor, en este caso el fichero manifest no cumple ningún objetivo, por tanto prescindimos de el: • <directorio de jdk 1.1>\bin\jar.exe cvf <archivo de salida.jar> <clases y recursos a incluir en el jar> – Creación de un fichero de texto que también se sincronizara con el PocketPC y hará la función de acceso directo. • 18#"\Windows\evm.exe" <command line options> <class name> • Donde evm es el ejecutable Jeode JVM, las opciones son equivalentes a las de la ejecución de una jvm en un PC. Pàg: 41 Estius Universitaris 06/07 Java Móvil J2ME Constricciones al desarrollar para dispositivos móviles • • • • Aunque Palm IIIx tiene una capacidad computacional y casi 4 veces la memoria que el primer Mac de Apple y superior al primer PC, debemos considerar estos dispositivos como "limitados" en comparación con la vastedad de recursos de una computadora de sobremesa actual. Por tanto no debemos aplicar las premisas estándares de diseño de software cuando diseñemos aplicaciones para estos dispositivos. Aunque enumeraremos las limitaciones de Palm, las premisas que se expongan son también validas para los PocketPC, todo y que la capacidad de estos es superior a las tradicionales Palm. A medida de que las computadoras son más potentes, el software realiza más trabajo, los recursos hardware han experimentado un crecimiento sorprendente, y para las aplicaciones estos pueden ser virtualizados de forma que no existan constricciones. Esta potencia permite realizar software más elegante, fácil de mantener y que permiten cambios de diseño en tiempo de desarrollo. Este soporte a cambios aislados significa que otras partes de la aplicación no están afectadas; esto, a su vez, significa que los componentes que apoyan la funcionalidad existente no necesitan modificarse. Esto permite a la aplicación soportar los cambios de una forma más fiable y más ordenada, a pesar de la naturaleza imprevisible de los cambios futuros. En un dispositivo móvil, sin embargo, estos principios de diseño pueden no ser aplicables en un entorno limitado. En un dispositivo móvil, las prioridades del diseño cambian. Los recursos limitados se deben asignar de forma que se consiga la máxima funcionalidad. La velocidad de ejecución, del uso de memoria, y tamaño de la pantalla es más importante que un diseño elegante propio de una perspectiva orientada a objetos y que permita que los cambios sean aislados. Pàg: 42 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en capacidad de proceso • • • • Un PC de escritorio dispone de una fuente de alimentación ilimitada, que le permite funcionar a máxima velocidad y disipar cantidades grandes de calor. Un dispositivo Palm, por otra parte, es un dispositivo portable con la electricidad provista por baterías de 1,5 V. Los diseñadores de Palm eligieron una CPU de bajo consumo para funcionar de forma que se maximizará la vida de la batería. Aunque ésta era la decisión adecuada para un dispositivo portable pequeño, significa que el software para Palm se debe desarrollar con una visión bien clara de la cantidad de proceso que necesitara. Otro factor importante es que las tareas realizadas en PDAs se deben hacer muy rápidamente. El usuario de PDA desea realizar tareas simples que terminen rápidamente; el usuario no desea esperar al dispositivo para acabar tareas muy largas de cómputo. Los aplicaciones de Palm son (y deben ser) muy usables (en tiempo de respuesta) como mínimo tanto como un PC de escritorio que realice una tarea media. Si partimos de la premisa que un PC de escritorio es por lo menos 10 veces más potente que un PDA, podemos afirmar que para mantener el mismo nivel de usabilidad, las aplicaciones de una PDA necesita limitarse a las tareas que son 10 veces más simples. Dado que estamos utilizando el mismo lenguaje que utilizamos con éxito en aplicaciones de PC, se acostumbra a caer en el error de desarrollar aplicaciones de la misma forma. En nuestras aplicaciones de escritorio nos aprovechamos de la potencia barata y hemos empleado bibliotecas extensas y ricas de clases para producir aplicaciones simples y elegantes. Utilizamos parsers XML para los archivos de configuración y para detokenizar mensajes pasados como documentos XML; esto proporciona una compresión superior de los mensajes, pero no somos conscientes de la cantidad de proceso necesaria para realizar estas funciones. En el desarrollo de aplicaciones para PDA hemos de recordar que la aproximación de desarrollo para PC no se puede aplicar sin considerar las diferencias de plataforma, y particularmente la disponibilidad de recursos. Una meta del diseño para cualquier aplicación en PDAs es sacar tanto trabajo como sea posible a otra computadora, que puede ser un PC de escritorio o un servidor. Pàg: 43 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en el tamaño De Pantalla • Diseñar para la simplicidad y la facilidad de uso es un aspecto importante del diseño de una aplicación, sin importar la tecnología o el medio. Una pantalla con una gran cantidad de controles o de información exhibida implica que el usuario tardara más en absorber esta información, destacar que el numero de botones en una pantalla implica más tiempo de aprendizaje de la aplicación. • Para más pautas de cómo diseñar aplicaciones para Palm y conformes con otras aplicaciones, se recomienda la lectura de "Palm OS Programmer's Companion" documento número 3004-003. Este documento es parte del kit del desarrollo de software para Palm OS., • En MIDP de Palm, un Form no se limita a un tamaño particular al añadir Items. Por ejemplo, se desean agregar 20 StringItems en un Form, nada impedirá hacerlo, pero en pantalla solo se mostraran los 11 primeros, será necesario realizar scroll para visualizar el resto. • Aunque es posible agregar más artículos de los que pueden ser vistos en un Form, no se recomienda. Se realiza una aplicación mas intuitiva si se evita el scrolling. Para el ejemplo anterior una lista seria una buena aproximación. Pàg: 44 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en la capacidad de memoria (I) • Para argumentar por que Palm es un dispositivo limitado en memoria veremos como se organiza la memoria en este dispositivo. • Para entender la organización de la memoria en MIDP de Palm OS, debemos ver como esta organizada esta, para realizar este paso se debe ejecutar la aplicación developer incluido en el suite, y seleccionar show en developer preferences • Esto nos mostrara una pantalla similar a la presentada • Las descripciones que se muestran corresponden a MIDP de Sun para Palm y no a la organización de memoria para aplicaciones no Java. Pàg: 45 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en la capacidad de memoria (II) Tipo Descripción ROM El tamaño de la imagen ROM en este dispositivo. RAM El tamaño combinado de RAM en este dispositivo. Palm OS divide la RAM en dos áreas lógicas: dinámica y almacenaje. Ambas áreas siguen idénticas después de apagar el dispositivo, pero un reset libera el área dinámica. freeram El tamaño combinado del heap de almacenaje y dinámico del dispositivo: El “heap dinámico" se refiere a la RAM para alocatación dinámica como stack, alocataciones dinamicas de la aplicación y del sistema. En Palm OS 3.5 con MB 4 o más, el espacio dinámico es de 256 KB. Este espacio se libera si no está utilizada actualmente para las asignaciones dinámicas. el “heap almacenamiento" es el resto de la RAM. Puede haber mas de un heap de almacenamiento, estos se utilizan para almacenar datos permanentes, tales como bases de datos. En todas las versiones de Palm OS hasta la 4.0, el chunk máximo de RAM de almacenamiento que se puede obtener por las aplicaciones es un poco menor de 64 o 128 KB (Depende de la versión). Este tamaño se incrementa en la versión 5.0 freeheap El tamaño de la memoria disponible en el heap de almacenamiento. maxheapchunk El tamaño del chunk mayor de almacenamiento. javafreeheap La cantidad de memoria disponible en el heap de Java. Esta es el área del heap dinámico que utiliza Java al asignar nuevos objetos y stack de aplicación, el valor máximo es poco menor de 64 KB permanent La cantidad de memoria asignada internamente por el KVM. Pàg: 46 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en la capacidad de memoria (III) • Para ver cuanta memoria está disponible para el desarrollador, podemos escribir una sencilla aplicación. Hay dos métodos en la clase runtime que son útiles para trabajar con la memoria disponible. Son totalMemory y freeMemory. El fragmento siguiente del código demuestra cómo determinar la memoria disponible dentro de un MIDlet: Runtime runtime = Runtime.getRuntime(); runtime.gc(); System.out.println("Total: " + runtime.totalMemory() + " Free: " + runtime.freeMemory()); • • • Destacar que se utiliza el método gc de runtime antes de llamar el método freeMemory. El propósito de esta llamada es obligar a la JVM a limpiar los objetos no utilizados y no liberador por el garbage collector porque la cantidad de memoria no es suficientemente baja para dispararlo. La cantidad de memoria devuelta por freeMemory puede ser diferente de la cantidad de memoria reportada por javafreeheap. Esto es porque el javafreeheap corresponde con el heap dinámico interno de Java para stack y nuevos objetos, mientras que freeMemory retorna una aproximación de la cantidad de memoria disponible para la futura asignación de objetos. El MIDlet MemoryMIDlet, StaticMemoryMIDlet, y MultipleClassMIDlet cada uno realiza una alocatación de memoria diferente. MemoryMIDlet asigna un nuevo array de 1000 bytes. Runtime runtime = Runtime.getRuntime(); runtime.gc(); beforeFree = runtime.freeMemory(); largeArray = new byte[1000]; runtime.gc(); afterFree = runtime.freeMemory(); System.out.println("Total: " + runtime.totalMemory() + " Free (before): " + beforeFree + " Free (after): " + afterFree); Pàg: 47 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en la capacidad de memoria (IV) • StaticMemoryMIDlet hace lo mismo, pero también tiene un array estático de 2000 bytes: • Finalmente, MultipleClassMIDlet crea una instancia de LargeClass , una clase con un atributo que referencia a un array de 1000 bytes: static byte[] largeStaticArray = new byte[2000]; LargeClass largeClass = new LargeClass(); donde LargeClass se define como: package com.javamovil.small; public class LargeClass { private byte[] byteArray = new byte[1000]; public String method1(String s1, String s2) { return s1+s2; } public String method2(String s1, String s2) { return s1+s2; } } • El número de bytes devueltos por freeMemory() se ha registrado antes y después la asignación dinámica. Pàg: 48 Estius Universitaris 06/07 Java Móvil J2ME Limitaciones en la capacidad de memoria (V) MIDlet Bytes Consumidos en cargar el Midlet Bytes que se consumirán en el proceso del comando "Allocate" Alocatación hecha MemoryMIDlet 4396 1016 Allocatar un array de 1000 bytes StaticMemoryMIDlet 6412 1016 Allocatar un array de 1000 bytes MultipleClassMIDlet 4392 1032 Allocatar una nueva instancia de LargeClass • De la tabla, se observa que un objeto array estático toma el espacio del mismo heap de Java que se utiliza para asignar objetos dinámicos. Es decir, los objetos estáticamente y dinámicamente asignados utilizan el mismo espacio del heap. Según lo observado previamente, el espacio de heap se restringe a 64 KB en Palm OS 3.X y 4.X. Pàg: 49 Estius Universitaris 06/07 • Estructura básica de un Midlet (I) El Gestor de Aplicaciones – El gestor de aplicaciones o AMS (Application Management System) es el software encargado de gestionar los MIDlets. Este software reside en el dispositivo y es el que nos permite ejecutar, pausar o destruir nuestras aplicaciones J2ME. A partir de ahora nos referiremos a él con las siglas de sus iniciales en inglés AMS, El AMS realiza dos grandes funciones: • • • Java Móvil J2ME Por un lado gestiona el ciclo de vida de los MIDlets. Por otro, es el encargado de controlar los estados por los que pasa el MIDlet mientras está en la memoria del dispositivo, es decir, en ejecución. Ciclo de vida de un MIDlet – – – – – – – El ciclo de vida de un MIDlet pasa por 5 fases: descubrimiento, instalación, ejecución, actualización y borrado. Estas fases son aplicables principalmente a las aplicaciones para teléfonos móviles, con servicios asociados y generalmente de pago para la instalación de aplicaciones en el dispositivo. Descubrimiento: Etapa que permite descargar aplicaciones de diversas formas, servicios de pago, conexión directa, etc. Instalación: Etapa que se encarga del deploy de la aplicación dejándola dispuesta para su uso. Ejecución: A continuación analizaremos con más detalle esta fase. Actualización: Ciclo de vida del MIDlet, detectando si es una nueva instalación o la actualización de un MIDlet existente. Borrado: Deben de controlarse los errores y garantizar el correcto borrado del o de los MIDlets Pàg: 50 Estius Universitaris 06/07 Java Móvil J2ME Estructura básica de un Midlet (II) • Estados de un MIDlet – Un MIDlet durante su ejecución pasa por 3 estados diferentes, estos tres estados son: • • • – Activo: El MIDlet está actualmente en ejecución. Pausa: El MIDlet no está actualmente en ejecución. En este estado el MIDlet no debe usar ningún recurso compartido. Para volver a pasar a ejecución tiene que cambiar su estado a Activo. A este estado se llegaría por ejemplo si mientas se esta ejecutando la aplicación se recibe un mensaje, una llamada, una alarma, etc. Destruido: El MIDlet no está en ejecución ni puede transitar a otro estado. Además se liberan todos los recursos ocupados por el MIDlet. Como vemos en el diagrama, un MIDlet puede cambiar de estado mediante una llamada a los métodos MIDlet.startApp(), MIDlet.pauseApp() o MIDlet.destroyApp(). El gestor de aplicaciones cambia el estado de los MIDlets haciendo una llamada a cualquiera de los métodos anteriores. Un MIDlet también puede cambiar de estado por sí mismo. Pàg: 51 Estius Universitaris 06/07 Java Móvil J2ME Estructura básica de un Midlet (III) – Ahora vamos a ver por los estados que pasa un MIDlet durante una ejecución típica y cuáles son las acciones que realiza tanto el AMS como el MIDlet. En primer lugar, se realiza la llamada al constructor del MIDlet pasando éste al estado de “Pausa” durante un corto período de tiempo. El AMS por su parte crea una nueva instancia del MIDlet. Cuándo el dispositivo está preparado para ejecutar el MIDlet, el AMS invoca al método MIDlet.startApp() para entrar en el estado de “Activo”. El MIDlet entonces, ocupa todos los recursos que necesita para su ejecución. Durante este estado, el MIDlet puede pasar al estado de “Pausa” por una acción del usuario, o bien, por el AMS que reduciría en todo lo posible el uso de los recursos del dispositivo por parte del MIDlet. – Tanto en el estado “Activo” como en el de “Pausa”, el MIDlet puede pasar al estado “Destruido” realizando una llamada al método MIDlet.destroyApp(). Esto puede ocurrir porque el MIDlet haya finalizado su ejecución o porque una aplicación prioritaria necesite ser ejecutada en memoria en lugar del MIDlet. Una vez destruido el MIDlet, éste libera todos los recursos ocupados. Pàg: 52 Estius Universitaris 06/07 Java Móvil J2ME Estructura de un MIDlet import javax.microedition.midlet.* public class MiMidlet extends MIDlet { public MiMidlet() { /* Éste es el constructor de clase. Aquí debemos inicializar nuestras variables. */ } public startApp(){ /* Aquí incluiremos el código que queremos que el MIDlet ejecute cuándo se active. */ } public pauseApp(){ /* Aquí incluiremos el código que queremos que el MIDlet ejecute cuándo entre en el estado de pausa (Opcional) */ } public destroyApp(){ /* Aquí incluiremos el código que queremos que el MIDlet ejecute cuándo sea destruido. Normalmente aquí se liberaran los recursos ocupados por el MIDlet como memoria, etc. (Opcional) */ } } Pàg: 53 Estius Universitaris 06/07 Java Móvil J2ME El paquete javax.microedition.midlet (I) • El paquete javax.microedition.midlet define las aplicaciones MIDP y su comportamiento con respecto al entorno de ejecución. Como ya sabemos, una aplicación creada usando MIDP es un MIDlet. • Clase MIDlet – public abstract class MIDlet – Un MIDlet es una aplicación realizada usando el perfil MIDP como ya sabemos. La aplicación debe extender esta clase para que el AMS pueda gestionar sus estados y tener acceso a sus propiedades. El MIDlet puede por sí mismo realizar cambios de estado invocando a los métodos apropiados. Los métodos de los que dispone esta clase son los siguientes: – protected MIDlet() – Constructor de clase sin argumentos. Si la llamada a este constructor falla, se lanzaría la excepción SecurityException. Pàg: 54 Estius Universitaris 06/07 Java Móvil J2ME El paquete javax.microedition.midlet (II) – protected abstract void destroyApp(boolean incondicional) throws – – – – – – – – MIDletstateChangeException Indica la terminación del MIDlet y su paso al estado de “Destruido”. En el estado de “Destruido” el MIDlet debe liberar todos los recursos y salvar cualquier dato en el almacenamiento persistente que deba ser guardado. Este método puede ser llamado desde los estados “Pausa” o “Activo”. Si el parámetro ‘incondicional’ es false, el MIDlet puede lanzar la excepción MIDletstateChangeException para indicar que no puede ser destruido en este momento. Si es true, el MIDlet asume su estado de destruido independientemente de como finalice el método. public final String getAppProperty(String key) Este método proporciona al MIDlet un mecanismo que le permite recuperar el valor de las propiedades desde el AMS. Las propiedades se consiguen por medio de los archivos manifest y JAD. El nombre de la propiedad a recuperar debe ir indicado en el parámetro key. El método nos devuelve un String con el valor de la propiedad o null si no existe ningún valor asociado al parámetro key. Si key es null se lanzará la excepción NullPointerException. public final void notifyDestroyed() Este método es utilizado por un MIDlet para indicar al AMS que ha entrado en el estado de “Destruido”. En este caso, todos los recursos ocupados por el MIDlet deben ser liberados por éste de la misma forma que si se hubiera llamado al método MIDlet.destroyApp(). El AMS considerará que todos los recursos que ocupaba el MIDlet están libres para su uso. public final void notifyPaused() Se notifica al AMS que el MIDlet no quiere estar “Activo” y que ha entrado en el estado de “Pausa”. Este método sólo debe ser invocado cuándo el MIDlet esté en el estado “Activo”. Una vez invocado este método, el MIDlet puede volver al estado “Activo” llamando al método MIDlet.startApp(), o ser destruido llamando al método MIDlet.destroyApp(). Si la aplicación es pausada por sí misma, es necesario llamar al método MIDlet.resumeRequest() para volver al estado “Activo”. Pàg: 55 Estius Universitaris 06/07 Java Móvil J2ME El paquete javax.microedition.midlet (III) – protected abstract void pauseApp() – Indica al MIDlet que entre en el estado de “Pausa”. Este método sólo debe ser llamado cuándo el MIDlet esté en estado “Activo”. Si ocurre una excepción RuntimeException durante la llamada a MIDlet.pauseApp(), el MIDlet será destruido inmediatamente. Se llamará a su método MIDlet.destroyApp() para liberar los recursos ocupados. – public final void resumeRequest() – Este método proporciona un mecanismo a los MIDlets mediante el cual pueden indicar al AMS su interés en pasar al estado de “Activo”. El AMS, en consecuencia, es el encargado de determinar qué aplicaciones han de pasar a este estado llamando al método MIDlet.startApp(). – protected abstract void startApp() throws MIDletstateChangeException – Este método indica al MIDlet que ha entrado en el estado “Activo”. Este método sólo puede ser invocado cuándo el MIDlet está en el estado de “Pausa”. En el caso de que el MIDlet no pueda pasar al estado “Activo” en este momento pero si pueda hacerlo en un momento posterior, se lanzaría la excepción MIDletstateChangeException. – A través de los métodos anteriores se establece una comunicación entre el AMS y el MIDlet. Por un lado tenemos que los métodos startApp(), pauseApp() y destroyApp() los utiliza el AMS para comunicarse con el MIDlet, mientras que los métodos resumeRequest(), notifyPaused() y notifyDestroyed() los utiliza el MIDlet para comunicarse con el AMS. Pàg: 56 Estius Universitaris 06/07 Java Móvil J2ME El paquete javax.microedition.midlet (IV) • Clase MIDletChangeStateException – public class MIDletstateChangeException extends Exception – Esta excepción es lanzada cuando ocurre un fallo en el cambio de estado de un MIDlet. Pàg: 57 Estius Universitaris 06/07 Java Móvil J2ME Mi primer MIDlet import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class HolaMundo extends MIDlet { private Display display; private Form screen; public HolaMundo() { display=Display.getDisplay(this); screen = new Form("HolaJME"); StringItem strItem = new StringItem(" ","Hola mundo"); screen.append(strItem); } public void startApp() throws MIDletStateChangeException{ display.setCurrent(screen); } public void pauseApp(){ } public void destroyApp(boolean unconditional){ display=null; screen=null; notifyDestroyed(); } } Pàg: 58 Estius Universitaris 06/07 La interfaz de usuario (I) Object Ticker CommandListener AlertType Font Graphics ItemStateListener Java Móvil J2ME Command Image Item Display Diplayable Canvas Screen Form Alert List TextBox ChoiceGroup DateField java.lang.* Gauge ImageItem StringItem javax.microedition.lcdui.* Choice TextField javax.microedition.lcdui.* (Interface) Pàg: 59 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Displayable • Displayable es la clase padre de Screen y Canvas, estas proporcionan las funciones básicas del interfaz de usuario de una aplicación. Displayable puede tener un número de comandos, que son objetos visuales usados para iniciar una cierta acción en la aplicación. Un comando se puede implementar de varias formas; boton, item del menú, ... . Un comando tiene una etiqueta, un tipo, y una prioridad. La etiqueta es un string usado para distinguir el comando en la interfaz de usuario. El tipo del comando proporciona la implementación del MIDP para tratar este comando. Los tipos del comando son: BACK, CANCEL, EXIT, HELP, ITEM, OK, SCREEN, y STOP. Dando a un comando un tipo CANCEL, por ejemplo, el desarrollador deja al MIDP el tratamiento de la información que se pudiera haber introducido que será, a priori cancelada. Observe que para los tipos del comando con excepción de SCREEN, la implementación de MIDP puede modificar la etiqueta por una mas apropiada para el dispositivo. A Command se le puede dar una prioridad, que proporciona otra característica de MIDP referente al orden con que este comando se debe exhibir respecto a otros comandos en la misma pantalla. Un número más bajo indica una prioridad más alta. Por ejemplo, para crear un nuevo comando que representa una acción para salir de la aplicación, escribiríamos lo siguiente: Pàg: 60 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Command Command exitCommand = new Command("Exit", Command.EXIT, 10); • Esto indica a la aplicación que el botón de salida debe aparecer al final de los command's del menú dado que le hemos asignado una prioridad baja. • Una vez que una aplicación haya creado sus objetos Command, un objeto que implementa la interfaz CommandListener debe ser asignado para tratar los eventos. Esto se hace con el método setCommandListener, invocado en un objeto derivado de Displayable. El interfaz de CommandListener especifica un método, el commandAction, al que se le pasa el comando que es activado, y el objeto Displayable a el cual pertenece. • La diferencia entre un Screen y Canvas es que el primero se utiliza como base para construir un interfaz de usuario basado en formularios, mientras que el segundo se utiliza para dibujar imágenes, líneas, y círculos. El curso se va a centrar en interfaces de usuario generados a partir de Screen. • Hay cuatro tipos de Screen: Alarm, Form, List, y TextBox. Cualquiera de ellos puede tener agregados objetos Command, tal i como pueden tener un título. Pàg: 61 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (I) • Una Form es un tipo especial de Screen, en el que se pueden colocar Item’s. Un Item es un control simple del interfaz de usuario, En un Form se pueden colocar varios Items. Las subclases de Item son botones de múltiple o simple selección, controles de fecha y de hora, control de barra, control de imagen, control de sting, y control de entrada de texto. Para crear un Form vacio: Form mainForm = new Form("BaseUIMIDlet"); • Recordemos crear el comando exit, para poder abandonar el MIDlet: Command exitCommand = new Command("Salir", Command.EXIT, 10); • Debido a que una aplicación puede tener varios objetos Displayable (es decir, muchas instancias de Form's, Alert's, List's, TextBox'es, y Canvas'es), y debido a que únicamente se puede ocupar el display con un objeto Displayable, necesitamos una forma de especificar qué Displayable debe ser visible. Esto se hace con la clase Display. Con un objeto Display, podemos descubrir que Displayable es actualmente visible, y podemos fijar que Displayable se hará visible. Cada MIDlet tiene un Display. Para obtener una referencia a el, utilizaremos el método estático getDisplay en la clase Display, pasándole una referencia al objeto MIDlet. Así pues, para nuestro ejemplo, necesitaremos una referencia al objeto Display: Display display = null; Pàg: 62 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (II) • En el constructor del MIDlet, agregamos el comando exit y fijamos el MIDlet para ser el listener de este comando: mainForm.addCommand(exitCommand); mainForm.setCommandListener(this); • En el método startApp, obtenemos una referencia al Display del MIDlet, y fijamos el Display actual a nuestro Form recién creado: display = Display.getDisplay(this); display.setCurrent(mainForm); • Dado que hemos fijado el MIDlet para ser el listener del comando exit, necesitamos implementar el método commandAction para tomar las acciones apropiadas cuando suceda el evento del comando exit. A modo de ejemplo: public void commandAction(Command c, Displayable d) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } } Pàg: 63 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (III) • En el código siguiente se observa un ejemplo que agrupa lo visto anteriormente. Dado que vamos a intentar que todos los ejemplos tengan el mismo comportamiento básico, la clase de BaseUIMIDlet también proporcionará la clase base para todos los ejemplos de la interfaz de usuario. package com.f2i.jmd.ui; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class BaseUIMIDlet extends MIDlet implements CommandListener { protected Form mainForm = new Form("BaseUIMIDlet"); protected Command exitCommand = new Command("Salir", Command.EXIT, 10); protected Display display = null; protected static final String[] MOVIES = {"Gladiator", "The Patriot", "A Few Good Men"}; protected Command okCommand = new Command("OK", Command.SCREEN, 1); protected Command backCommand = new Command("Atras", Command.SCREEN, 2); Pàg: 64 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (IV) public BaseUIMIDlet() { mainForm.addCommand(exitCommand); mainForm.setCommandListener(this); } public void startApp() { display = Display.getDisplay(this); display.setCurrent(mainForm); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } public void commandAction(Command c, Displayable d) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } } } Pàg: 65 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (V) • En el ejemplo anterior el comando salir se ha implementado como: • Esto sitúa la acción en el menú Go, si se hubiera definido como Command.SCREEN se hubiera situado en el menú Actions y tendría asociado un botón el la pantalla: protected Command exitCommand = new Command("Salir",Command.EXIT, 10); protected Command exitCommand = new Command("Salir",Command.SCREEN, 10); • Algunas implementaciones de MIDP pueden, sobrescribir la etiqueta definida para un command por la de defecto del dispositivo, esto no es así en la implementación de Palm. Destacar que el tipo de comando obligara a que este aparezca en un determinado submenú de opciones, p.ex. Si se define como Command.HELP, provocaría que se situara en el submenú Options: protected Command exitCommand = new Command("Salir",Command.HELP, 10); Pàg: 66 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (VI) • Como se menciono previamente, la implementación de MIDP determina cómo se dibujan los objetos de comando, dependiendo de las capacidades del dispositivo. En un dispositivo Palm usando el MIDP de Sun, los objetos Command de tipo SCREEN se dibujan como botones en el fondo de la pantalla. Si hay muchos Command's, o sus etiquetas hicieran los botones demasiado grandes para situarlos a lo largo de la pantalla, los Command's restantes se colocan como entradas de menú en el menú de Actions. • En el ejemplo siguiente, se crearan seis Command's, todos ellos del tipo SCREEN, con igual prioridad, y los agregamos al Form anterior. Observar que crearemos una subclase de BaseUIMIDlet, esto lo realizaremos para todos los ejemplos, de modo que obtengamos el mismo comportamiento fundamental (y ahorremos un poco de trabajo). Pàg: 67 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Form (VII) package com.f2i.jmd.ui; import javax.microedition.lcdui.*; public class CommandMIDlet extends BaseUIMIDlet { public Command command1Command = new Command("1", 1); public Command command2Command = new Command("2", 1); public Command command3Command = new Command("3", 1); public Command command4Command = new Command("4", 1); public Command command5Command = new Command("5", 1); public Command command6Command = new Command("6", 1); public CommandMIDlet() { super(); mainForm.setTitle("CommandMIDlet"); mainForm.addCommand(command1Command); mainForm.addCommand(command2Command); mainForm.addCommand(command3Command); mainForm.addCommand(command4Command); mainForm.addCommand(command5Command); mainForm.addCommand(command6Command); } } Pàg: 68 Command.SCREEN, Command.SCREEN, Command.SCREEN, Command.SCREEN, Command.SCREEN, Command.SCREEN, Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Alert (I) • • Un Alert es una pantalla que presenta texto y opcionalmente una imagen. Típicamente, un Alert se utiliza para presentar una información para el usuario o para indicar que una acción urgente se debe tomar. Un Alert puede tener un time-out, o esperar a que el usuario la reconozca. Para crear un Alert y para fijar su temporización (a cinco segundos, por ejemplo), el código seria: Alert alert = new Alert("Alerta"); alert.setTimeout(5000); alert.setString("Esta es una alerta que se mostrara por 5 segundos"); • Para mostrar el Alert, e ir de nuevo al Form principal cuando pase el tiempo, podemos utilizar el método setCurrent que toma un Alert y un Displayable como parámetros. display.setCurrent(alert, mainForm); • • Los números exhibidos en el círculo en la esquina izquierda inferior de la alerta indican el número de segundos restantes hasta el cierre de la alerta. Hay dos formas que la alerta no será reconocida automáticamente. La primera es si el texto de la alarma es demasiado grande para ser mostrado en una pantalla. En este caso, sin importar el valor del temporizador de la alerta, esta permanecerá en pantalla hasta que el usuario la cierre. Pàg: 69 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Alert (II) • • • • Para forzar una alarma a ser reconocida, se debe usar el valor de temporizador FOREVER, como en el siguiente ejemplo: Alert alert = new Alert("AlertaSiempre"); alert.setTimeout(Alert.FOREVER); alert.setString("Texto de la alerta"); display.setCurrent(alert, mainForm); En esta alerta queda en manos de MIDP dibujar el botón "Done". Una alerta puede también tener un tipo, que indica la naturaleza de la alerta. Las opciones son CONFIRMATION, WARNING, INFO, ERROR, y ALARM. El tipo de la alerta afecta al icono exhibido en la misma. El AlertType también se puede utilizar para reproducir un sonido que acompañe la alerta. Este esta limitado a las capacidades del dispositivo. AlertType.WARNING.playSound(display); Pàg: 70 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Alert (II) • • Una alerta es una buena herramienta para mostrar una pequeña cantidad de información, las usaremos en los ejemplos siguientes para mejorar los conocimientos de los Form's. Para crear interfaces de usuario más sofisticadas, tenemos la posibilidad de añadir objetos derivados de Item en los formularios. Destacar que los derivados de Item sólo pueden aparecer en formularios. Pàg: 71 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: ChoiceGroup (I) • Un ChoiceGroup se utiliza para obtener una sola selección o selecciones múltiples de un grupo de opciones. La implementación de MIDP determina como se dibuja el objeto. En dispositivos Palm, los grupos de una única selección se dibujan como listas de una sola selección, mientras que los grupos de selección múltiple se dibujan como cajas de selección. Los grupos de única selección se crean: protected static final String[] MEDIA = {"DVD", "VHS"}; ChoiceGroup singleChoice = new ChoiceGroup("Media",ChoiceGroup.EXCLUSIVE, MEDIA, null); • • Para este ejemplo, se ha escogido un constructor que permite que las etiquetas sean especificadas como un array de strings. Se escoge no acompañar las opciones de imágenes, indicando el ultimo parámetro del constructor como null. Observar que también existe el tipo IMPLICIT. La única diferencia entre EXCLUSIVE e IMPLICIT es que es posible registrar un objeto de CommandListener para el tipo IMPLICIT, y se notifica cuando la selección cambie. No hay notificación para el tipo EXCLUSIVE. Se puede añadir un ChoiceGroup a un Form: Form choiceForm = new Form("Selección de películas"); choiceForm.append(singleChoice); Pàg: 72 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: ChoiceGroup (II) • Para obtener la selección del usuario se debe añadir al command listener del formulario un código como el siguiente: int i = singleChoice.getSelectedIndex(); String mediaSelected = singleChoice.getString(i); • Para selecciones múltiples se debe utilizar MULTIPLE como tipo: ChoiceGroup multipleChoice = new ChoiceGroup("Películas", ChoiceGroup.MULTIPLE, MOVIES, null); • Para obtener las selecciones, un array de flags boleanos es utilizado por el método getSelectedFlags: boolean[] selections = new boolean[multipleChoice.size()]; multipleChoice.getSelectedFlags(selections); • El flag boleano correspondiente a la selección es puesto true si el usuario selecciono la opción, un código que haría lo descrito seria: String movieSelected = new String(); boolean[] selections = new boolean[multipleChoice.size()]; multipleChoice.getSelectedFlags(selections); for (int j=0; j<selections.length; j++) if (selections[j]) movieSelected += multipleChoice.getString(j) + " on " + mediaSelected + "\n"; • Colocando todo lo anterior en el MIDlet ChoiceGroupMIDlet mostrará un formulario con un grupo de selección simple, cuando el usuario presione el botón OK, se mostrara una alerta con las selecciones del usuario de ambos grupos. Pàg: 73 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: ChoiceGroup (III) package com.f2i.jmd.ui; import javax.microedition.lcdui.*; public class ChoiceGroupMIDlet extends BaseUIMIDlet { protected static final String[] MEDIA = {"DVD", "VHS"}; protected Command choiceCommand = new Command("Choice", Command.SCREEN, 1); public ChoiceGroupMIDlet() { super(); mainForm.setTitle("ChoiceGroupMIDlet"); mainForm.addCommand(choiceCommand); } public void commandAction(Command c, Displayable d) { if (c == choiceCommand) { Form choiceForm = new Form("Selección de películas"); ChoiceGroup singleChoice = new ChoiceGroup("Media", ChoiceGroup.EXCLUSIVE, MEDIA, null); ChoiceGroup multipleChoice = new ChoiceGroup("Películas", ChoiceGroup.MULTIPLE, MOVIES, null); choiceForm.append(singleChoice); choiceForm.append(multipleChoice); Pàg: 74 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: ChoiceGroup (IV) choiceForm.addCommand(okCommand); choiceForm.addCommand(backCommand); choiceForm.addCommand(exitCommand); choiceForm.setCommandListener(this); display.setCurrent(choiceForm); } else if (c == okCommand) { Form choiceForm = (Form)d; ChoiceGroup singleChoice = (ChoiceGroup)(choiceForm.get(0)); ChoiceGroup multipleChoice = (ChoiceGroup)(choiceForm.get(1)); // Obtener la selección int i = singleChoice.getSelectedIndex(); String mediaSelected = singleChoice.getString(i); // get the movie selection String movieSelected = new String(); boolean[] selections = new boolean[multipleChoice.size()]; multipleChoice.getSelectedFlags(selections); for (int j=0; j<selections.length; j++) if (selections[j]) movieSelected += multipleChoice.getString(j) + " on " + mediaSelected + "\n"; Pàg: 75 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: ChoiceGroup (V) // Mostrar el resultado Alert alert = new Alert(“Selección"); alert.setString(movieSelected); alert.setTimeout(5000); alert.setType(AlertType.INFO); display.setCurrent(alert, mainForm); } else if (c == backCommand) { display.setCurrent(mainForm); } else { super.commandAction(c, d); } } } Pàg: 76 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: DateField (I) • La clase DateField provee una forma de mostrar y entrar fechas y horas, se muestra un código de ejemplo: DateField startDateField = new DateField("Fecha de vencimiento", DateField.DATE_TIME); startDateField.setDate(new Date()); mainForm.append(startDateField); • La fecha y hora que se muestra va fijada en un objeto Date, en el ejemplo anterior se utiliza el los datos actuales del dispositivo, para fijar unos datos se puede utilizar lo siguiente: DateField returnDateField = new DateField("Fecha de vuelta", DateField.DATE_TIME); Calendar calendar = Calendar.getInstance(); calendar.setTime(tomorrow()); calendar.set(Calendar.HOUR, 10); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.AM_PM, Calendar.PM); returnDateField.setDate(calendar.getTime()); mainForm.append(returnDateField); • Dado que MIPD no dispone de tipos para calculo de fechas estos se deberán realizar manualmente: private Date manana() { Date hoy = new Date(); Date manana = new Date(hoy.getTime()+(24*60*60*1000)); return manana; } Pàg: 77 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: DateField (II) package com.f2i.jmd.ui; import javax.microedition.lcdui.*; import java.util.*; public class DateFieldMIDlet extends BaseUIMIDlet { public DateFieldMIDlet() { super(); mainForm.setTitle("DateFieldMIDlet"); DateField startDateField = new DateField("Fecha de vencimiento", DateField.DATE_TIME); startDateField.setDate(new Date()); mainForm.append(startDateField); DateField returnDateField = new DateField("Fecha de vuelta", DateField.DATE_TIME); Calendar calendar = Calendar.getInstance(); calendar.setTime(manana()); calendar.set(Calendar.HOUR, 10); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.AM_PM, Calendar.PM); returnDateField.setDate(calendar.getTime()); mainForm.append(returnDateField); } Pàg: 78 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: DateField (III) private Date manana() { Date hoy = new Date(); Date manana = new Date(hoy.getTime()+(24*60*60*1000)); return manana; } public void commandAction(Command c, Displayable d) { super.commandAction(c, d); } } Pàg: 79 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Gauge (I) • Gauge se utiliza para mostrar y editar un valor en un rango, el código para su creación seria: Gauge gauge = new Gauge("Valor", true, 20, 5); gaugeForm.append(gauge); • • El primer parámetro especifica la etiqueta, el segundo es un boleano que indica si es editable, el tercero el valor final, y el último el inicial. El valor puede ser recuperado con el método getValue del objeto, la forma de dibujo puede variar en función de que el Gauge sea editable. package com.f2i.jmd.ui; import javax.microedition.lcdui.*; import java.lang.Integer; public class GaugeMIDlet extends BaseUIMIDlet { protected Gauge gauge1; protected Gauge gauge2; public GaugeMIDlet() { super(); mainForm.setTitle("GaugeMIDlet"); gauge1 = new Gauge("Valor 1", true, 20, 5); mainForm.append(gauge1); gauge2 = new Gauge("Valor 2", false, 20, 5); mainForm.append(gauge2); Pàg: 80 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Gauge (II) mainForm.addCommand(okCommand); mainForm.setCommandListener(this); } public void commandAction(Command c, Displayable d) { if (c == okCommand) { int valor=gauge1.getValue(); Integer valin = new Integer(valor); Alert alert = new Alert("Valor selecionado"); alert.setString("El Valor es " + valin.toString()); alert.setTimeout(5000); alert.setType(AlertType.INFO); display.setCurrent(alert, mainForm); gauge2.setValue(valor); } else { super.commandAction(c, d); } } } Pàg: 81 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: StringItem (I) • Un StringItem es un Item utilizado para Mostar texto estático en un Form. Esta formado por una etiqueta y el texto en si. Este no se puede editar por el usuario: StringItem addressLine1 = new StringItem("Dirección 1", "Sabadell, 67"); stringItemForm.append(addressLine1); • Ejemplo: package com.f2i.jmd.ui; import javax.microedition.lcdui.*; public class StringItemMIDlet extends BaseUIMIDlet { private Command stringItemCommand = new Command("StringItem", Command.SCREEN, 1); public StringItemMIDlet() { super(); mainForm.setTitle("StringItemMIDlet"); mainForm.addCommand(stringItemCommand); } public void commandAction(Command c, Displayable d) { if (c == stringItemCommand) { Form stringItemForm = new Form("Detalles de dirección"); StringItem addressLine1 = new StringItem("Dirección 1", "Sabadell, 67"); Pàg: 82 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: StringItem (II) StringItem addressLine2 = new StringItem("Dirección 2", "Barcelona"); StringItem postcode = new StringItem("Código Postal", "08003"); stringItemForm.append(addressLine1); stringItemForm.append(addressLine2); stringItemForm.append(postcode); stringItemForm.addCommand(backCommand); stringItemForm.addCommand(exitCommand); stringItemForm.setCommandListener(this); display.setCurrent(stringItemForm); } else if (c == backCommand) { display.setCurrent(mainForm); } else { super.commandAction(c, d); } } } Pàg: 83 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: TextField (I) • Un elemento TextField es similar en aspecto a un StringItem, excepto que un TextField permite al usuario modificar o introducir el texto. Un TextField puede también aplicar filtros al texto que se introduce; el filtro se considera una mascara de entrada. Para crear un TextField con el contenido del texto inicializado, utilizan al constructor siguiente: TextField addressLine1 = new TextField("Dirección 1", "Sabadell, 67", 20, TextField.ANY); • El último parámetro pasado al constructor es donde las mascaras de entrada pueden ser especificados. Las mascaras disponibles son ANY, EMAILADDR, NUMERIC, PASSWORD, PHONENUMBER, y URL. En cada caso, únicamente la entrada indicada por la mascara será aceptada por el campo. Cuando el usuario ha acabado de modificar o incorporar del texto, el texto del campo puede ser recuperado llamando el método getString. El código siguiente muestra cómo un TextField se podría utilizar en una aplicación: package com.f2i.jmd.ui; import javax.microedition.lcdui.*; public class TextFieldMIDlet extends BaseUIMIDlet { private Command textFieldCommand = new Command("TextField", Command.SCREEN, 1); Pàg: 84 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: TextField (II) public TextFieldMIDlet() { super(); mainForm.setTitle("TextFieldMIDlet"); mainForm.addCommand(textFieldCommand); } public void commandAction(Command c, Displayable d) { if (c == textFieldCommand) { Form textFieldForm = new Form("Confirme su dirección"); TextField addressLine1 = new TextField("Dirección 1", "Sabadell, 67", 20, TextField.ANY); TextField addressLine2 = new TextField("Dirección 2", "Barcelona", 20, TextField.ANY); TextField postcode = new TextField("Código Postal", "08003", 5, TextField.NUMERIC); textFieldForm.append(addressLine1); textFieldForm.append(addressLine2); textFieldForm.append(postcode); textFieldForm.addCommand(okCommand); textFieldForm.addCommand(backCommand); textFieldForm.addCommand(exitCommand); textFieldForm.setCommandListener(this); display.setCurrent(textFieldForm); } Pàg: 85 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: TextField (III) else if (c == okCommand) { Form textFieldForm = (Form)d; TextField addressLine1 = (TextField)(textFieldForm.get(0)); TextField addressLine2 = (TextField)(textFieldForm.get(1)); TextField postcode = (TextField)(textFieldForm.get(2)); // display the result Alert alert = new Alert("Dirección entrada"); alert.setString("La dirección es:\n" + addressLine1.getString() + "\n" + addressLine2.getString() + "\n" + postcode.getString()); alert.setTimeout(5000); alert.setType(AlertType.INFO); display.setCurrent(alert, mainForm); } else if (c == backCommand) { display.setCurrent(mainForm); } else { super.commandAction(c, d); } } } • Hasta ahora hemos utilizado dos subclases de Screen, que son Alert y Form, a continuación vamos a estudiar los otros dos tipos: List y TextBox Pàg: 86 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: List (I) • • La lista es un tipo de Screen que permite al usuario seleccionar elementos. Tanto List como ChoiceGroup se basan en el mismo interfaz. La principal diferencia es el ámbito de utilización, un ChoiceGroup siempre se deberá utilizar dentro de un formulario. List soporta los mismos tipos, todo y que la implementación no tiene por que ser la misma que en ChoiceGroup, recordémoslos: IMPLICIT, EXCLUSIVE, y MULTIPLE. La creación se realizaría del siguiente modo: List list = new List("Películas", List.EXCLUSIVE, MOVIES, null); • Como en ChoiceGroup, la selección se recupera de la lista usando los métodos getSelectedIndex y getString: int i = list.getSelectedIndex(); String movieSelected = list.getString(i); • Una lista MULTIPLE se crea de forma similar, y las selecciones se recuperan de la misma manera que las selecciones múltiples para un ChoiceGroup. List list = new List("Películas", List.MULTIPLE, MOVIES, null); String movieSelected = new String(); boolean[] selections = new boolean[list.size()]; list.getSelectedFlags(selections); for (int i=0; i<selections.length; i++) if (selections[i]) movieSelected += list.getString(i) + "\n"; Pàg: 87 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: List (II) • Seria interesante construir un código que pusiera en practica los dos tipos de lista, utilizando la lista de películas de BaseUIMIDlet, de forma similar a como se ha ido realizando en los apartados anteriores, el resultado debería ser algo similar a: Pàg: 88 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: TextBox • El TextBox es un tipo de pantalla que permite la entrada de texto en formato libre. En un dispositivo Palm se visualiza como una pantalla de Memo. El TextBox utiliza el mismo concepto de mascaras de entrada que TextField. El modo de creación seria: TextBox textBox = new TextBox("Películas", "", 20, TextField.ANY); • Para recuperar el contenido: String movieSelected = textBox.getString(); Pàg: 89 Estius Universitaris 06/07 Java Móvil J2ME La interfaz de usuario: Ticker • Por último vamos a analizar la clase Ticker, los objetos Ticker son como letreros con información que se desplaza. Un objeto Ticker se crea del siguiente modo: Ticker ticker = new Ticker("Información: Llevese 2 películas al precio de 1..."); • El Ticker se muestra en cualquier objeto derivado de Screen, usando el método del setTicker. El MIDlet siguiente es igual que el ChoiceGroupMIDlet, excepto que se ha añadido un Ticker en cada pantalla de la aplicación. Ticker en el formulario principal, en la demostración de ChoiceGroup y en un Alert Pàg: 90 Estius Universitaris 06/07 Java Móvil J2ME Almacenamiento de información (I) • Dado que un PDA no se puede conectar siempre con un servidor de el cual recuperar la información, almacenar la información en el dispositivo local es muy importante. A continuación exploraremos los métodos disponibles para almacenar información. • MIDP proporciona unas APIs simples de base de datos de sistema para almacenar la información en el dispositivo. El sistema de APIs se llama "Record Management System" (RMS). Estas APIs incluye métodos para crear, para actualizar, para buscar, y para suprimir bases de datos. • La implementación de la base de datos se deja en manos de la correspondiente implementación de MIDP en el dispositivo. En los dispositivos Palm, la base de datos del RMS se implementa como una DB de Palm OS. • A continuación estudiaremos la API RMS para almacenar información. Pàg: 91 Estius Universitaris 06/07 Java Móvil J2ME Almacenamiento de información (II) Las propiedades de estos almacenes de registros son: • 1. 2. 3. 4. 5. • Cada Record Store está compuesto por cero o más registros. Un nombre de Record Store es sensible a mayúsculas y minúsculas y está formado por un máximo de 32 caracteres UNICODE. Dentro de una suite no pueden coexistir dos Record Stores con el mismo nombre. Si una suite de MIDlets es borrada del dispositivo MID, todos los RecordStores pertenecientes a esa suite se borrarán. Es posible que un MIDlet acceda a un Record Además de un nombre, cada Record Store también posee otros dos atributos: – – Número de versión: Es un valor entero que se actualiza conforme vayamos insertando, modificando o borrando registros en el Record Store. Podemos consultar este valor invocando al método RecordStore.getVersion(). Marca temporal: Es un entero de tipo long que representa el número de milisegundos desde el 1 de enero de 1970 hasta el momento de realizar la última modificación en el Record Store. Este valor lo podemos obtener invocando al método RecordStore.getLastModified(). Pàg: 92 Estius Universitaris 06/07 Java Móvil J2ME Métodos generales de RecordStore Pàg: 93 Estius Universitaris 06/07 Java Móvil J2ME Manipulación de registros Pàg: 94 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore (I) • La API RMS se encuentra en el paquete javax.microedition.rms del MIDP. La clase central del paquete es RecordStore, que representa un almacén RMS. La clase de RecordStore se utiliza para realizar todas las operaciones en los registros. Las operaciones disponibles para el desarrollador son: – – – – Crear, Abrir, Cerrar o Suprimir un RecordStore. Agregue un nuevo registro, suprima un registro, iterar sobre los registros. Filtros y comparadores pueden desarrollarse para clasificar y filtrar los registros según lo deseado. Obtenga la información sobre un RecordStore, número de registros, tamaño, la cantidad de memoria restante para el RecordStore, su nombre, el tiempo que la ultima modificación, y el número de veces que se ha modificado (es decir, la versión). Vincular un "listener" para recibir una notificación cuando se modifica un registro. • Para crear y para abrir un RecordStore nuevo, utilizamos el método estático openRecordStore sobre un objeto RecordStore: • El segundo parámetro del openRecordStore es un valor boleano para indicar si deseamos generar una excepción si no existe el RecordStore. Si el valor es true, openRecordStore creará un nuevo RecordStore si no puede encontrar uno existente con el nombre facilitado, abriéndolo, y retornando una referencia al objeto. Se retorna una referencia al objeto, por lo que mas de un MIDlet de la misma suite puede acceder al RecordStore. store = RecordStore.openRecordStore(recordStoreName, true); Pàg: 95 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore (II) • • Si únicamente se desea abrir un RecordStore se puede utilizar false en este parámetro. En este caso, una excepción de tipo RecordStoreNotFoundException se lanzaría si no existiese el RecordStore. Para obtener información sobre el RecordStore, los siguientes métodos de la clase de RecordStore se pueden utilizar: StringBuffer result = new StringBuffer(); result.append("Nombre: " + store.getName() + "\n"); result.append("Registros: " + store.getNumRecords() + '\n'); result.append("Tamaño: " + store.getSize() + " bytes\n"); result.append("Bytes disponibles: " + store.getSizeAvailable() + " bytes\n"); result.append("Versión: " + store.getVersion() + "\n"); • Para cerrar un RecordStore, llamamos simplemente el método closeRecordStore del objeto RecordStore: store.closeRecordStore(); • Observar que cada llamada del método del openRecordStore necesita el correspondiente closeRecordStore. Se debe tener en cuenta que en cada ocasión que se llama a openRecordStore se incrementa un contador de referencia, por tanto es necesario realizar closeRecordStore para decrementar este contador. El RecordStore no se cierra realmente hasta que el contador es cero. Pàg: 96 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore (III) • Para eliminar totalmente un RecordStore, utilizamos el método deleteRecordStore: RecordStore.deleteRecordStore(recordStoreName); • Dado que un RecordStore se puede compartir por los MIDlets de una suite, puede ser posible que otro MIDlet está teniendo acceso al RecordStore que estamos intentando suprimir. En ese caso, el método deleteRecordStore lanzará una RecordStoreException. • La información se almacena en el RecordStore en forma de registros, y cada registro es un array de bytes. Los métodos para guardar y recuperar registros de un RecordStore deben realizarlo como un array de bytes. Como primera instancia, tener que almacenar la información como array de bytes puede parecer un mecanismo incómodo. Sin embargo, con el uso de ByteArrayOutputStream, de ByteArrayInputStream, DataOutputStream y DataInputStream, no es tan complicado como podría parecer. Como ejemplo podemos modificar la aplicación para ordenar películas en videos o DVDs. El objeto básico podría ser el siguiente: Pàg: 97 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore: Ejemplo package com.f2i.jmd.persistence.rms; import java.io.*; public class Movie { public String title; public String actors; public long yearReleased; public Movie() { } public Movie(String title, String actors, long yearReleased) { this.title = title; this.actors = actors; this.yearReleased = yearReleased; } public String toString() { StringBuffer result = new StringBuffer(title); result.append(", estrenado "); result.append(yearReleased); result.append(", estrellas "); result.append(actors); return result.toString(); } } Pàg: 98 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore: Serialización (I) • • El perfil MID no define un esquema para serialización. Vamos a definir un esquema simple de serialización para almacenar objetos en RMS que después también podría ser utilizado para enviar estos objetos sobre una red. Para el esquema simple de serialización, definimos un interfaz que tenga dos métodos: package com.f2i.jmd.persistence.rms; import java.io.*; public abstract interface Serializable { public void writeObject(DataOutputStream dos) throws IOException; public void readObject(DataInputStream dis) throws IOException; } • Los objetos que implementen este interfaz deben definir una forma especifica de guardar el estado del objeto hacia un DataOutputStream, y de recuperar de (implementar serializable a la definición de la clase) un DataInputStream. Así pues, necesitamos agregar dos métodos a nuestra clase Movie: Pàg: 99 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore: Serialización (II) public void writeObject(DataOutputStream dos) throws IOException { dos.writeUTF(title); dos.writeUTF(actors); dos.writeLong(yearReleased); } public void readObject(DataInputStream dis) throws IOException { title = dis.readUTF(); actors = dis.readUTF(); yearReleased = dis.readLong(); } • • Utilizaremos un DataOutputStream con un ByteArrayOutputStream por debajo para escribir el objeto a un registro RecordStore. La ventaja de este esquema simple para la serialización es que no hay necesidad de cambiar la definición de la clase Movie tanto para almacenar su contenido como mas adelante para enviar este contenido sobre un conexión HTTP. Por tanto en J2SE, la forma de escribir un array de bytes es crear un DataOutputStream con un ByteArrayOutputStream asociado: Pàg: 100 Estius Universitaris 06/07 Java Móvil J2ME Uso de RecordStore: Serialización (III) ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); • Una vez se haya creado el DataOutputStream, podemos enviarlo al objeto Movie para que se guarde a si mismo: movie.writeObject(dos); • //Escribe el objeto en el Stream Dado que DataOutputStream tiene un ByteArrayOutputStream asociado, es fácil obtener el contenido del stream en forma de un array de bytes: byte[] ba = bos.toByteArray(); • Para guardar este array en el RecordStore, utilizamos el método addRecord en el objeto RecordStore: store.addRecord(ba, 0, ba.length); • Para recuperar un objeto del RecordStore, utilizamos un DataInputStream con un ByteArrayInputStream asociado. Llamando el método del readObject en el objeto Movie, se leerá el array de bytes del registro, rellenándose el objeto con la información de la película guardada es ese registro: ByteArrayInputStream bis = new ByteArrayInputStream(store.getRecord(recordId)); DataInputStream dis = new DataInputStream(bis); Movie movie = new Movie(); movie.readObject(dis); Pàg: 101 Estius Universitaris 06/07 Java Móvil J2ME RecordEnumeration • Para recuperar un conjunto de registros del RecordStore, RMS proporciona el interfaz RecordEnumeration. RecordEnumeration proporciona la capacidad de avanzar y retroceder sobre los registros del RecordStore. Para obtener un RecordEnumeration, se debe llamar el método enumerateRecords en el objeto RecordStore: RecordEnumeration re = store.enumerateRecords(this, this, false); Pàg: 102 Estius Universitaris 06/07 Java Móvil J2ME RecordEnumeration: Filtros (I) • El primer parámetro proporciona la capacidad de aplicar un filtro en la enumeración. El filtro es un objeto que implementa el interfaz RecordFilter, esto implica que dispone de un método matches. El método matches retorna true si el registro se incluirá en la enumeración. Como ejemplo, si se desearan todas las películas con el título que comenzara con "The" se desarrollaría un método matches como sigue: public boolean matches(byte[] candidate) { boolean result = true; Movie movie = null; try { ByteArrayInputStream bis = new ByteArrayInputStream( candidate); DataInputStream dis = new DataInputStream(bis); movie = new Movie(); movie.readObject(dis); } catch (Exception e) { System.out.println(e); e.printStackTrace(); } result = movie.title.startsWith("The"); return result; } Pàg: 103 Estius Universitaris 06/07 Java Móvil J2ME RecordEnumeration: Filtros (II) • • • El método matches se llama para cada registro en el RecordStore, proporcionando un array de bytes al método para que pueda validar la condición del filtro. En el ejemplo anterior, se lee el objeto Movie del DataInputStream (con el ByteArrayInputStream asociado) y se prueba si su título comienza con los caracteres "The". Si es así se retorna true y el registro se incluye en la enumeración. Si no se provee ningún objeto para el filtro todos los registros del RecordStore se incluyen en la enumeración. El segundo parámetro del método enumerateRecords proporciona la capacidad de especificar un orden en la enumeración. Si un objeto implementa la interfaz RecordComparator se especifica como el segundo parámetro, el método compare del interfaz se llamara para cada par de registros en el RecordStore. Por ejemplo, si se deseara clasificar los registros por orden alfabético del títulos de la película, se debería desarrollar un método compare similar al siguiente: Pàg: 104 Estius Universitaris 06/07 Java Móvil J2ME RecordEnumeration: Ordenación (I) public int compare(byte[] rec1, byte[] rec2) { Movie movie1 = null; Movie movie2 = null; try { ByteArrayInputStream bis1 = new ByteArrayInputStream(rec1); DataInputStream dis1 = new DataInputStream(bis1); movie1 = new Movie(); movie1.readObject(dis1); ByteArrayInputStream bis2 = new ByteArrayInputStream(rec2); DataInputStream dis2 = new DataInputStream(bis2); movie2 = new Movie(); movie2.readObject(dis2); } catch (Exception e) { System.out.println(e); e.printStackTrace(); } // ordenar por titulo int result = movie1.title.compareTo(movie2.title); Pàg: 105 Estius Universitaris 06/07 Java Móvil J2ME RecordEnumeration: Ordenación (II) if (result < 0) { return RecordComparator.PRECEDES; } else if (result > 0) { return RecordComparator.FOLLOWS; } else { return RecordComparator.EQUIVALENT; } } • • Para cada par de registros en el RecordStore (después de que se ha aplicado el filtro), el correspondiente par de array de bytes se envía al método compare. Como antes, es posible convertir los byte arrays en objetos Movie. Si el título del primer objeto de la película precede léxicograficamente al título del segundo, el método compare retorna RecordComparator.PRECEDES una constante predefinida. Si el título de la primera película sigue al título de la segunda, el método compare retorna RecordComparator.FOLLOWS. Si son iguales, el método retorna RecordComparator.EQUIVALENT. Si no se provee ningún comparador al método enumerateRecords, los registros se clasifican en un orden indefinido. Pàg: 106 Estius Universitaris 06/07 Java Móvil J2ME RecordStore: Ejemplo • • Se adjunta el código de las clases Movie, Serializable y RmsMIDlet, que sirven de demostración de lo expuesto anteriormente. A continuación se exponen una pantallas de ejemplo del el código anterior: Pàg: 107 Estius Universitaris 06/07 Java Móvil J2ME RecordListener (I) • La API RMS incluye la capacidad de definir un objeto record listener, que seguirá la actividad del RecordStore. Un objeto que implementa la interfaz RecordListener se puede agregar como listener a un RecordStore, y los métodos de notificación provistos por el interfaz serán llamados cuando un registro del RecordStore se añada, se actualice, o se suprima. Para registrar un listener se debe usar el método addRecordListener en el objeto RecordStore: store.addRecordListener(this); • A partir de ese momento y hasta que se cierre el RecordStore, el objeto referido por this será notificado cuando el RecordStore cambie. Tres métodos separados se definen en el interfaz de RecordListener: public void recordAdded(RecordStore store, int recordId); public void recordChanged(RecordStore store, int recordId); public void recordDeleted(RecordStore store, int recordId); • • Para demostrar cómo trabaja un record listener, podemos ampliar el ejemplo anterior RmsMIDlet para agregar registros de películas en un thread diferente ejecutado en background. El objeto de MIDlet se registra como RecordListener, y el correspondiente método es invocado cada vez el thread agrega un nuevo registro a Movie. [NOTA] Palm OS no soporta de forma nativa los threads en background. Sin embargo, la definición de CLDC impone el soporte a threads, por tanto la KVM implementa este soporte. Pàg: 108 Estius Universitaris 06/07 Java Móvil J2ME RecordListener (II) • En primer lugar se creara el thread referenciado: package com.f2i.jmd.persistence.rms; import java.io.*; import javax.microedition.rms.*; public class RmsThread extends Thread { int count = 0; Movie[] movies = null; RecordStore store = null; public RmsThread(int count, Movie[] movies, RecordStore store) { this.count = count; this.movies = movies; this.store = store; } Pàg: 109 Estius Universitaris 06/07 Java Móvil J2ME RecordListener (III) public void run() { try { // añadir el numero especificado de películas en el RecordStore, // pausa entre cada registro añadido for (int i=0; i<count; i++) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); Movie movie = movies[i % movies.length]; // escribir el objeto en el stream movie.writeObject(dos); byte[] ba = bos.toByteArray(); store.addRecord(ba, 0, ba.length); // esperamos sobre 1 segundo sleep(1000); } store.closeRecordStore(); } catch (Exception e) { e.printStackTrace (); } } } Pàg: 110 Estius Universitaris 06/07 Java Móvil J2ME RecordListener (IV) • • Esta clase derivada de thread inserta un nuevo registro y queda en pausa por un segundo, repitiendo este proceso un determinado numero de veces. A continuación se debe definir un nuevo Command Inicio que ponga en ejecución el thread. Command startCommand = new Command("Inicio", Command.SCREEN, 1); ... mainForm.addCommand(startCommand); ... if (c == startCommand) { store = RecordStore.openRecordStore(recordStoreName, true); store.addRecordListener(this); RmsThread thread = new RmsThread(5, movies, store); thread.start(); } • Por último, es necesario implementar los métodos del RecordListener. En este ejemplo, recuperaremos el registro de la película y mostraremos el título del registros agregado o actualizado. Observar que al intentar recuperar el registro afectado en el método recordDeleted fallará, y una excepción del tipo InvalidRecordIDException se lanzará: Pàg: 111 Estius Universitaris 06/07 Java Móvil J2ME RecordListener (V) public void recordAdded(RecordStore store, int recordId) { resultItem.setLabel ("Status:"); resultItem.setText("Película añadida: " + getMovieFromRecord(store, recordId).title); } public void recordChanged(RecordStore store, int recordId) { resultItem.setLabel ("Status:"); resultItem.setText("Película actualizada: " + getMovieFromRecord(store, recordId).title); } public void recordDeleted(RecordStore store, int recordId) { resultItem.setLabel ("Status:"); resultItem.setText("Película eliminada: " + recordId); } Pàg: 112 Estius Universitaris 06/07 Java Móvil J2ME RecordListener (VI) • Ahora es necesario implementar el correspondiente getMovieFromRecord como sigue: Movie getMovieFromRecord(RecordStore store, int recordId) { Movie movie = new Movie(); try { ByteArrayInputStream bis = new ByteArrayInputStream(store.getRecord(recordId)); DataInputStream dis = new DataInputStream(bis); movie.readObject(dis); } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return movie; } Pàg: 113 Estius Universitaris 06/07 Java Móvil J2ME RecordStores en Palm OS • La implementación de los RecordStores es dependiente del dispositivo, y puede variar entre plataformas. Esta implementación no esta definida en las especificaciones de MIDP ni en las de CLDC. La implementación de Palm OS utiliza una base de datos del dispositivo para guardar los RecordStores. Se puede acceder a esta DB de forma idéntica a otras DB de Palm, por ejemplo para sincronizar los datos, simplemente seria necesario crear un driver de acceso, pero esto no se recomienda por la siguientes razones: • – – • Los estándares se deben utilizar siempre que sea posible por las siguientes razones: – – – – • El formato de la base de datos no se especifica ni se soporta, y puede cambiar. Hay maneras soportadas de transferir información a y desde un dispositivo. Los estándares simplifican la migración de aplicaciones a otras plataformas soportadas. Los estándares facilitan la lectura del código generado por nosotros. Una aplicación conforme a un estándar es mas fácil que funcione en modelos posteriores. Una aplicación que siga los estándares tendrá más posibilidades de utilizar las nuevas características que dispongan las próximas versiones de la plataforma Si aún así se desea acceder directamente a las DB de Palm OS en este link se podrá encontrar más información: http://archives.java.sun.com/cgi-bin/wa?A2=ind0108&L=kvminterest&D=0&H=0&O=T&T=1&P=49045%20. Pàg: 114 Estius Universitaris 06/07 Java Móvil J2ME Otras Bases de Datos para Java • Si una aplicación necesitara mas de lo aportado por RMS de MIDP se podrían adquirir productos de terceros como los que se exponen a continuación. Ambos productos descritos proveen una aplicación MIDP de bases de datos compatible JDBC. • • PointBase PointBase Micro es una implementación de un subconjunto de la API JDBC que se encuentra en J2SE, preparado pata para trabajar en un entorno MIDP. El lenguaje utilizado es SQL estándar. El archivo JAR ocupa menos de 45 KB. La base de datos puede residir integramente en el dispositivo, o sincronizarse con el producto PointBase UniSync. Para más información sobre PointBase Micro: http://www.pointbase.com/ • • • • ReqwirelessDB ReqwirelessDB proporciona el acceso a cualquier base de datos JDBC estándar desde una aplicación MIDP. Se proporciona la API JDBC para uso de la aplicaciones MIDP, y un servlet para el servidor donde reside la DB a la que se desea acceder. Para más información sobre Reqwireless: http://www.reqwireless.com/ Pàg: 115 Estius Universitaris 06/07 Java Móvil J2ME Comunicaciones (I) • • • • La principal ventaja de los dispositivos móviles es su posibilidad de conectividad, todo y que esta era en un inicio escasa, se están realizando grandes progresos a medida que los dispositivos tienen un grado de integración mayor y los estándares de conectividad van evolucionando. CLDC define un conjunto de APIs de conectividad llamado Generic Connection Framework (GCF). Este conjunto de APIs es suficiente para establecer redes de bajo nivel entre dispositivos móviles y con sistemas de mayor potencia. MIDP utiliza GCF para establecer un conjunto de clases que soportan streams y esto se amplia hasta soportar conexiones HTTP 1.1 en el caso de MIDP 1.0 y HTTPS en el caso de MIDP 2.0. Sin poder compararse con el framework ofrecido por J2SE en java.net, principalmente debido a los problemas inherentes de las restricciones de memoria, y las necesidades del dispositivo. Los diseñadores de CLDC generalizaron las características de establecimiento de una red de J2SE, proporcionando un marco uniforme para soportar los nuevos dispositivos y los nuevos protocolos que estos pueden requerir. Pàg: 116 Estius Universitaris 06/07 Java Móvil J2ME Comunicaciones (II) Connector Connection DatagramConnection InputConnection OutputConnection StreamConnectionNotifier StreamConnection ContentConnection CommConnection HttpConnection HttpsConnection SocketConnection SecureConnection javax.microedition.io.* javax.microedition.io.* (Interface) MIDP 1.0 javax.microedition.io.* (Interface) MIDP 2.0 Pàg: 117 Estius Universitaris 06/07 Java Móvil J2ME Comunicaciones (III) • • • Para el establecimiento básico de una red, J2SE incluye clases tales como socket, HttpURLConnection, DatagramSocket, MulticastSocket, ServerSocket, InetAddress, URL, y URLConnection en el paquete java.net. Generalmente, cada protocolo es manejado por una clase diferente. Por ejemplo, los datagramas son implementados por la clase DatagramSocket, y las conexiones HTTP son manejadas por la clase HttpURLConnection. Sin embargo, en el CLDC de J2ME, las clases para el establecimiento de una red son absolutamente diferentes. Ninguna de las clases básicas referentes a conectividad en J2SE existe en el CLDC de J2ME. De hecho, el paquete de java.net no existe. Las clases del GCF están situadas en un paquete especifico del CLDC, llamado javax.microedition.io. En el GCF, la clase Connector maneja todos los protocolos de establecimiento de una red soportados en el dispositivo. El resultado es que el código de una aplicación es básicamente el mismo independientemente del protocolo que utilice. Se debe tener en cuenta que los protocolos soportados no están especificados en el nivel de configuración. La especificación de los protocolos pertenece a los perfiles. Esto es consistente con la premisa de que los perfiles especifican las características que aprovechan de las capacidades del dispositivo. La clase Connector tiene varios métodos estáticos, que se utilizan para crear conexiones. Estos métodos se resumen a continuación: Pàg: 118 Estius Universitaris 06/07 Java Móvil J2ME Comunicaciones (IV) • La forma genérica de abrir una conexión es utilizar el método estático de Connection tal como sigue Connector.open("<protocolo>:[<destino>][;<parámetros>]"); • Pero también se pueden utilizar las siguientes variantes: static Connection open(String name) Crea y abre una conexión, usando una URL. static Connection open(String name, int mode) Crea y abre una conexión, usando una URL y un modo (leer, escribir, o leer/escribir). static Connection open(String name, int mode, boolean timeouts) Crea y abre una conexión, usando una URL, un modo, y un flag para lanzar excepciones por timeout. static DataInputStream openDataInputStream(String name) Crea y abre un input stream de datos para la conexión. static DataOutputStream openDataOutputStream(String name) Crea y abre un output stream de datos para la conexión. static InputStream openInputStream(String name) Crea y abre un input stream para la conexión. static OutputStream openOutputStream(String name) Crea y abre un output stream para la conexión. Pàg: 119 Estius Universitaris 06/07 Java Móvil J2ME Comunicaciones (V) • El formato de los argumento del método open debe ser conforme con la sintaxis estándar para URIs – • • • • El estándar para URIs se define en RFC2396, que se puede encontrar en http://www.ieft.org/rfc/rfc2396.txt El argumento < protocolo > corresponde al protocolo (http/file/...) que se utilizará para la conexión. El argumento opcional < destino > se interpreta en función del protocolo. Para conexiones orientadas a red, este parámetro se refiere a una dirección, en formato nombre o IP. Para otros protocolos este argumento se interpreta en función del protocolo, si en un futuro se soportan archivos, este argumento contendría el path y el nombre del archivo. Los argumentos opcionales < parámetros > contienen duplas nombre-valor separadas por punto y coma. Por ejemplo, ";nombre1=valor1;nombre2=valor2". Aunque len la especificación de MIDP se define únicamente el soporte HTTP, HTTP y HTTPS se soportan en la especificación MIDP 2.0 de J2ME, así como otros modos (socket, serversocket, comm, datagram) pero esto es de forma experimental. Para dispositivos Palm con la JVM de SUN únicamente se dispone del obligado HTTP, esto tiene la ventaja que cualquier código desarrollado para Palm será totalmente portable, dado que todos los dispositivos que implementen MIDP disponen de este protocolo. Pàg: 120 Estius Universitaris 06/07 Java Móvil J2ME HttpConnection (I) • Para entender el funcionamiento de las APIs de red de MIDP, podemos observar el siguiente ejemplo simple que descarga una página desde una conexión HTTP. private String getPage(String url) throws IOException { HttpConnection c = null; String result = null; try { c = (HttpConnection)Connector.open(url); DataInputStream dis = c.openDataInputStream(); byte[] buffer = new byte[(int)c.getLength()]; dis.readFully(buffer); result = new String(buffer); } catch (Exception e) { Alert alert = new Alert("Error"); alert.setString(e.toString()); alert.setTimeout(Alert.FOREVER); display.setCurrent(alert, mainForm); System.out.println(e.getMessage()); } finally { if(c != null) c.close(); } return result; } Pàg: 121 Estius Universitaris 06/07 Java Móvil J2ME HttpConnection (II) • • En este ejemplo, utilizamos Connector para abrir una HttpConnection, que se utiliza a continuación para abrir un stream de entrada de datos. Para descargar los primeros bytes de la página del URL especificado, se utiliza el método readFully() para leer todo el array de bytes. Notar que se utiliza el método getLength para crear el array de bytes del tamaño necesario. Lo que ocurre en las interioridades de este código es: En primer lugar la conexión HTTP no se realiza cuando se ejecuta el método open de Connector. En este punto se considera que se esta en estado de establecimiento de conexión, la conexión HTTP todavía no se ha realizado con el servidor. Se realiza la conexión y los datos se envían y se reciben cuando uno de los métodos siguientes se llama, causando en HttpConnection una transición del estado "establecimiento" al estado "conectado": •getResponseMessage •openInputStream •getHeaderFieldInt •openOutputStream •getHeaderFieldDate •openDataInputStream •openDataOutputStream •getExpiration •getDate •getLength •getLastModified •getType •getHeaderField •getEncoding •getHeaderFieldKey •getHeaderField •getResponseCode Pàg: 122 Estius Universitaris 06/07 Java Móvil J2ME HttpConnection (III) • Para probar este ejemplo, en el método commandAction de HttpNetworking.java podemos utilizar el código siguiente para establecer la conexión: public void commandAction(Command c, Displayable d) { try { if (c == getCommand) { resultItem.setLabel("Requesting page..."); resultItem.setText(""); String result = getPage( "http://localhost/fichero.html"); resultItem.setLabel("Received..."); resultItem.setText(result); } else if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } } catch (Exception e) { e.printStackTrace(); resultItem.setLabel("Error:"); resultItem.setText(e.toString()); } } Pàg: 123 Estius Universitaris 06/07 Java Móvil J2ME HttpConnection (IV) • • Se puede utilizar NetCat (nc -l -p 80) en el servidor destino para capturar la petición y enviar una respuesta compatible HTTP, p.ex: Petición: " GET /fichero.html HTTP/1.1 Host: localhost:80 Content-Length: 0 " • Respuesta: " HTTP/1.1 200 OK Content-Length: 54 Content-Type: text/html Java en dispositivos móviles Año 2004 F2i Sabadell " Pàg: 124 Estius Universitaris 06/07 Java Móvil J2ME Acceso a Internet desde un dispositivo Palm • • – – – • – – – • Vamos a realizar un inciso en el curso sobre Java, para ver las posibilidades de conexión de los dispositivos móviles, y concretamente de Palm para obtener un acceso a Internet. Opciones: Cradle con conexión serie o Bluetooth Conexión por Inflarojos o USB Disponibilidad de conexiones WireLess Para la primera opción la conexión entre el dispositivo el PC y Internet pasa por establecer un túnel PPP, esto debe realizar mediante software, en el caso de bluetooth utilizando el dispositivo serie virtual, todo y que es posible establecer también una pasarela mediante una red bluetooth y "ICS" las posibilidades son: Instalar el software http://www.mochasoft.dk/home.html Establecer un servicio RAS en Windows 2000, XP, NT que permita al dispositivo acceder a un servicio de pasarela: http://bwinton.latte.ca/Palm/ppp.html Para establecer una red bluetooth y compartir la conexión a Internet mediante ICS: http://www.whizoo.com/bt_setup/ Para establecer una conexión por Infrarrojos o USB se debe realizar lo mismo que en los puntos anteriores, es decir, es necesario un servicio PPP, que puede ser RAS o el software de mochasoft pero con un driver de virtualización a puerto serie del puerto de infrarrojos (http://www.ircomm2k.de/) o del USB Pàg: 125 Estius Universitaris 06/07 Java Móvil J2ME Acceso a Internet desde un dispositivo • • El tercer caso es mucho mas simple, dado que los dispositivos Palm dotados de una interfase wireless incorporan un stack Tcp/Ip y esto facilita enormemente la conectividad, simplemente debemos configurar nuestro dispositivo de acuerdo con la topología de nuestra red. Para dispositivos móviles es mucho más sencillo, y por supuesto mas caro, consiste en establecer una conexión a través del ISP correspondiente, abonando para ello las cuotas de conexión. Los dispositivos Palm también ofrecen la posibilidad de establecer una conexión por infrarrojos, bluetooth, o un cable especifico a un teléfono móvil para crear una conexión PPP con el correspondiente ISP. Pàg: 126