Академический Документы
Профессиональный Документы
Культура Документы
J2ME
Cuando Sun decidió lanzar su nuevo standard Java, llamado Java2, creó tres
diferentes entornos para desarrollo y ejecución de aplicaciones. Estos fueron
J2SE, J2EE y J2ME.
J2SE (Java 2 Standard Edition) es, por decirlo de alguna manera, la base de la
tecnología Java. Permite el desarrollo de applets (aplicaciones que se ejecutan
en un navegador web) y aplicaciones independientes (standalone). J2SE es el
heredero directo del Java inicial (antes de Java 2). J2EE (Java 2 Enterprise
Edition) está basado en J2SE, pero añade una serie de características
necesarias en entornos empresariales, relativos a redes, acceso a datos y
entrada/salida que requieren mayor capacidad de proceso, almacenamiento y
memoria. La decisión de separarlos es debida a que no todas estas
características son necesarias para el desarrollo de aplicaciones standard.
Al igual que J2EE cubre unas necesidades más amplias que J2SE, se hace
patente la necesidad de un subconjunto de J2SE para entornos más limitados.
La respuesta de Sun es J2ME (Java 2 Micro Edition).
J2ME se basa en los conceptos de configuración y perfil. Una configuración
describe las características mínimas en cuanto a la configuración hardware y
software. La configuración que usa J2ME es la CLDC (Connected Limited
Device Configuration).
Vamos a construir paso a paso nuestro primer MIDlet usando esta herramienta.
Tras la instalación del wireless toolkit, tendremos un nuevo submenú en el
menú inicio con un aspecto similar a éste:
Selecciona la aplicación KToolBar e inicializa el entorno. Verás aparecer la
ventana del entorno.
Vamos a crear un nuevo proyecto, así que pulsamos el botón New Project.
Nos solicitará un nombre para el proyecto y otro para la clase principal de la
aplicación.
Tanto el proyecto como la clase principal se llamarán HelloWorld, así que
introducimos este nombre en ambos cuadros de texto y pulsamos el botón
Create Project. En este momento KToolBar crea la estructura de directorios
necesaria para albergar el proyecto.
Cada una de las carpetas creadas tiene una misión concreta. Por ahora nos
bastará saber que nuestros archivos fuente irán emplazados en el directorio src,
y los recursos necesarios como gráficos, sonidos, etc... se alojarán en el
directorio res.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public HelloWorld() {
// Obtenemos el objeto Display del midlet.
display = Display.getDisplay(this);
// Creamos el comando Salir.
exitCommand = new Command("Salir", Command.EXIT,2);
Compilación y depuración
La fase de compilación se deberá efectuar bajo el entorno del : Wireless Toolkit
. Este entorno ofrece una serie de posibilidades de depuración y emulación
que dependen de la versión instalada.
Una vez creados los ficheros fuentes y colocados en el directorio VUF
anteriormente comentado se pulsará el botón Build de la pantalla principal. En
ese momento se realiza la compilación, preverificación de clases y
empaquetamiento de todos los recursos (clases, imágenes, datos, etc..)
necesarios para la ejecución. Los ficheros resultantes son dos: fichero.jar y
fichero.jad.
El primero es propiamente el fichero que contiene la aplicación en sí. El
segundo contiene la definición de los datos existentes en el anterior fichero.
Las siguientes aplicaciones son un ejemplo de las facilidades que permite Java
para dispositivos móviles:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
/*--------------------------------------------------
* Main class definition
*-------------------------------------------------*/
public class pngViewer extends MIDlet implements CommandListener
{
private Display display;
private TextBox tbxMain;
private Form frmViewPng;
private Command cmdExit;
private Command cmdView;
private Command cmdBack;
/*--------------------------------------------------
* Constructor for the class.
*-------------------------------------------------*/
public pngViewer()
{
display = Display.getDisplay(this);
// Create the Main textbox with a maximum of 50 characters
tbxMain = new TextBox("Enter png url",
"http://www.corej2me.com/scratch/spin.png", 50, 0);
// Create commands and add to textbox
cmdView = new Command("View", Command.SCREEN, 1);
cmdExit = new Command("Exit", Command.SCREEN, 1);
tbxMain.addCommand(cmdView );
tbxMain.addCommand(cmdExit);
// Set up a listener to "capture" button presses
tbxMain.setCommandListener(this);
// ---------------------------------------
// Create the form that will hold the png image
frmViewPng = new Form("Png Image");
// Create commands and add to form
cmdBack = new Command("Back", Command.BACK, 1);
frmViewPng.addCommand(cmdBack);
// Set up a listener to "capture" button presses
frmViewPng.setCommandListener(this);
}
/*--------------------------------------------------
* Called by the Application Manager on the device
* to start the MIDlet.
*-------------------------------------------------*/
public void startApp()
{
// Display the Main textbox
display.setCurrent(tbxMain);
}
/*--------------------------------------------------
* A required method.
* Does nothing in this MIDlet
*-------------------------------------------------*/
public void pauseApp()
{}
/*--------------------------------------------------
* A required method.
* Does nothing in this MIDlet
*-------------------------------------------------*/
public void destroyApp(boolean unconditional)
{}
/*--------------------------------------------------
* Process events
*-------------------------------------------------*/
public void commandAction(Command c, Displayable s)
{
// If the Command button pressed was "Exit"
if (c == cmdExit) {
destroyApp(false);
notifyDestroyed();
} else if (c == cmdView) { // If the Command button pressed was "View"
// Remove anything that may be on the form
if (frmViewPng.size() > 0)
for (int i = 0; i < frmViewPng.size(); i++)
frmViewPng.delete(i);
// Get the image from the web and append to the form
Image img;
if ((img = getImage(tbxMain.getString())) != null)
frmViewPng.append(img);
// Display the form with the image
display.setCurrent(frmViewPng);
} else if (c == cmdBack) { // If the Command button pressed was "Back"
display.setCurrent(tbxMain);
}
}
/*--------------------------------------------------
* Open an http connection and download a png file
* into a byte array.
*-------------------------------------------------*/
private Image getImage(String imageStr)
{
try
{
HttpConnection conn = (HttpConnection) Connector.open(imageStr);
// Check to see if we successfully opened the connection
int response = conn.getResponseCode();
if(conn.getResponseCode() == HttpConnection.HTTP_OK )
{
int length = (int) conn.getLength();
if (length > 0)
{
byte imageData[] = new byte[length];
InputStream in = conn.openInputStream();
// Read the png into an array
in.read(imageData);
// Create the image from the byte array
return Image.createImage(imageData, 0, length);
}
}
else
{
frmViewPng.append("Error getting png");
}
}
catch (IOException e)
{
frmViewPng.append("IO Error");
}
return null;
}
}
import java.lang.*;
import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
/**
* A simple class that shows an example of using a Timer and
* a TimerTask.
*
* This MIDlet creates two gauges. One gauge gaugeOne,
* sets elements from low to high. The other, gaugeTwo,
* set elements from high to low. In effect, this has
* gaugeOne "going up", and gaugeTwo "going down."
*
* The two timers fire at different intervals.
*
* There are two commands on our form:
*
* OK: toggles whether the times are active or not.
* EXIT: exits the MIDlet.
*/
public class TimerMIDlet extends MIDlet implements CommandListener {
// number of elements in gauge
final private static int GAUGE_MAX = 10;
private boolean timersRunning; // tracks state of timers
private Display myDisplay; // handle to the display
private Gauge gaugeOne; // "going up" gauge
private Gauge gaugeTwo; // "going down" gauge
private Form myScreen; // form on which to
// place gauges
15
private Command cmdOK; // OK command
private Command cmdExit; // EXIT command
private Timer timer;
private MyTimerTask timerTaskOne;
private MyTimerTask timerTaskTwo;
/**
* Internal class that provides a TimerTask.
*/
private class MyTimerTask extends TimerTask {
private Gauge myGauge; // reference to gauge
private boolean goUp; // if true, go up
private int num; // number of times called
/**
* Public constructor: stores "direction" and a reference to
* a gauge.
*/
public MyTimerTask(Gauge g, boolean up) {
myGauge = g;
goUp = up;
}
/**
* As the timer fires, this method is invoked. Set gauge
* based on goUp
*/
public void run() {
num++;
myGauge.setValue(goUp ?
GAUGE_MAX -(num % GAUGE_MAX) :
num % GAUGE_MAX);
}
}
/**
* Public constructor: gets handle to display,
* creates form, gauges, and commands.
*/
public TimerMIDlet() {
myDisplay = Display.getDisplay(this);
myScreen = new Form("TimerMIDlet");
gaugeOne = new Gauge("Up Gauge",
false,
GAUGE_MAX,
0);
myScreen.append(gaugeOne);
gaugeTwo = new Gauge("Down Gauge",
16
false,
GAUGE_MAX,
GAUGE_MAX);
myScreen.append(gaugeTwo);
cmdOK = new Command("OK", Command.OK, 1);
cmdExit = new Command("Exit", Command.EXIT, 1);
myScreen.addCommand(cmdOK);
myScreen.addCommand(cmdExit);
myScreen.setCommandListener(this);
}
/**
* Changes the state of timers to/from active to/from
* not-active.
*/
private void flipFlop() {
if (timersRunning) {
timerTaskOne.cancel();
timerTaskTwo.cancel();
timer.cancel();
timersRunning = false;
} else {
timer = new Timer();
timerTaskOne = new MyTimerTask(gaugeOne, false);
timerTaskTwo = new MyTimerTask(gaugeTwo, true);
timer.schedule(timerTaskOne, 0, 1000);
timer.schedule(timerTaskTwo, 0, 1500);
timersRunning = true;
}
}
/**
* Called by the system to start our MIDlet.
* @exception MIDletStateChangeException
*/
protected void startApp() throws MIDletStateChangeException {
myDisplay.setCurrent(myScreen);
flipFlop();
}
/**
* Called by the system to pause our MIDlet.
* No actions required by our MIDLet.
*/
protected void pauseApp() {}
/**
* Called by the system to end our MIDlet.
17
* No actions required by our MIDLet.
*/
protected void destroyApp(boolean unconditional) {}
/***
* Respond to command selections. Process two commands:
*
* OK: flip flop the timers to/from active
* EXIT: exit this MIDlet
*
*/
public void commandAction(Command c, Displayable d) {
if (c == cmdOK) {
flipFlop();
} else if (c == cmdExit) {
destroyApp(false);
notifyDestroyed();
}
}
}
Tanto los eventos a alto nivel, como a bajo nivel tienen una cosa en común: la
gestión de eventos debe de realizarse siempre en el mismo thread en el que se
produce el evento.
Para finalizar esta práctica veremos la clase Command y CommandListener
utilizadas en el ejemplo HelloWorld.