Aplicaciones MIDP: Midlets (javax.microedition.midlet) 

F. Javier García Castellano
Web: http://decsai.ugr.es/~fjgc, Mail: fjgc@decsai.ugr.es
IndiceInicioPerl

(C) Decsai
Web: http://decsai.ugr.es

1.- Midlet: Ciclo de vida

En la introducción dijimos que un midlet siempre heredará de la clase javax.microedition.midlet.MIDlet. Los métodos de esta clase permiten a nuestra aplicación crear, empezar, parar y destruir un Midlet, estos métodos son la interfaz del Midlet, que va a permitir a nuestro dispositivo poder manejar múltiples Midlets, sin tener que estar todos ejecutándose en el mismo entorno. El sistema de nuestro dispositivo puede seleccionar que Midlet está activo usando los métodos correspondientes para empezar o pausar.

El ciclo de vida de un midlet se compone de lo siguientes estados: Pausado, Activo o Destruido. Sólo puede estar en un estado a la vez. La figura 1 muestra como se pasa de uno a otro:

Figura 1. Ciclo de vida de un Midlet.

Cuando un midlet ser carga en memoria, inicialmente pasa al estado Pausado, entonces se realiza la inicialización de la clase (método startApp(), que luego veremos). Si el Midlet lanza una excepción durante la ejecución de su constructor, se destruye. El midlet puede pasar de Activo a Pausado, cuando, por ejemplo, recibimos una llamada en nuestro móvil; es el sistema quien pasa nuestro Midlet de Activo a Pausado y viceversa. Un Midlet puede ser lanzado y parado todas las veces que queramos, pero sólo puede ser destruido una vez.

2.- Empaquetamiento de los Midlet

Los Midlet necesitan ser empaquetados antes de ser instalado en el dispositivo de destino. Se utilizará un fichero .JAR(Java ARchive) donde se tendrá el Midlet principal y todas aquellas clases, imágenes u otros ficheros que nos puedan ser necesarios en tiempo de ejecución. También se incluirá en el .JAR información (en el fichero manifest) que le explique al dispositivo el contenido del fichero .JAR. Esta misma información también se incluye en el fichero .JAD (Java Application Descriptor).

Las clases del Midlet que son empaquetadas en el .JAR, deben estar compiladas en .class (obviamente) y verificadas antes de su utilización en un dispositivo, para verificar que no realizan ninguna operación no permitida. De hecho, las únicas operaciones 'no permitidas' que permite el API de MIDP es el método exit() de las clases System o Runtime, y como vimos requieren usar la excepción SecurityException para poder ser utilizado. Esta verificación se debe a hacer, debido a las limitaciones de los dispositivos, donde añadir esta parte de seguridad en la máquina virtual sería muy costoso en memoria. Es por ello, que los usuarios de estos dispositivos tiene que tener mucho cuidado con los .JAR que instalan, ya que si es de una fuente no fiable, podría contener código malicioso no verificado y que escapase al control de la máquina virtual.

Un fichero .jar puede contener varios Midlets, a esto se le denomina Midlet suite y permite compartir recursos, lo cual es aconsejable para minimizar el uso de los recursos del dispositivo y para una mayor reutilización de los componentes.

2.- Tratamiento de ciclos de vida de la clase MIDlet javax.microedition.midlet.MIDlet

Como hemos visto un Midlet siempre tiene que extender la clase javax.microedition.midlet.MIDlet que contiene todos los métodos necesarios para controlar el ciclo de vida del midlet (visto en la Figura 1).

Un Midlet debe tener un constructor público por defecto, es decir, un constructor sin argumentos. Este constructor lo puede implementar el programador si le hace falta inicializar algunos atributos del Midlet o lo puede añadir el compilador Java si no encuentra ninguno.

Para introducir los métodos del Midlet veamos el esquema que sigue todo Midlet:

Esqueleto de un Midlet:

//Usamos la clase MIDlet
import javax.microedition.midlet.*;

//Nuestra clase debe de heredar de la clase MIDlet
public class Ejemplo1 extends MIDlet {

    //Constructor, si no lo ponemos (está vacío) ya lo hará Java por nosotros
    public Ejemplo1(  ) {
    }

    //Método que se llama cuando pasamos de Pausado a Activo
    protected void startApp(  ) {
    }

    //Método que se llama cuando pasamos de Activo a Pausado
    protected void pauseApp(  ) {
    }

    //Método que se llama cuando se destruye el midlet
    protected void destroyApp(boolean incondicional) {
    }
}

El Midlet empieza en estado Pausado, se carga en memoria, se ejecuta el constructor y si no ha habido ningún problema en el constructor pasa a estado activo por lo que se ejecuta el método startApp():

protected abstract void startApp () 

Es un método abstracto de la clase MIDlet, lo que significa que tiene que ser implementado en nuestro Midlet, al ser un método protegido (protected) significa que sólo puede ser utilizado en el paquete javax.microedition.midlet.MIDlet. Aunque suele ser redefinido como público (public) para que pueda ser llamado desde otro sitio. Si no hay ningún problema (excepción o error) comenzará la ejecución del Midlet hasta que pase a estado Pausado o Destruido.

En cualquier momento el entorno de ejecución puede pasar un Midlet a estado Pausado, por ejemplo, debido que se recibe una llamada al móvil, y el dispositivo decide que necesita los recursos (pantalla y teclado) para tratar esa llamada entrante. En ese momento se llama al método pauseApp():

protected abstract void pauseApp ()

Al ser una clase abstracta también la tendremos que redefinir, y lo que se implementa en este método depende, en gran medida, de la aplicación, pero lo que se hace es guardar el estado actual y liberar cualquier recurso que estuviera ocupado, digamos que en este método se pasa nuestra aplicación a un estado seguro, a partir del cual se pueda reanudar la ejecución sin ningún problema. Hay que tener en cuenta que dejamos de tener accesos a la pantalla, las hebras no se terminan automáticamente y que los temporizadores (timers) que pudiéramos tener siguen activos.

Cuando volvemos al estado Activo después del estado Pausado se llama a la función startApp(). Esto hay que tenerlo en cuenta y reanudar la aplicación en el estado que se quedó antes de la pausa. Por lo que en este método tendremos que distinguir entre la primera vez que fue llamado (al iniciase el Midlet) y cuando es llamado después de una pausa.

Cuando el entorno de ejecución o el usuario decide cerrar nuestra aplicación se llama al método destroyApp():

protected abstract void destroyApp (boolean unconditional);

Este método le dice al MIDlet que termine la aplicación para entrar en el estado Destruido, por lo que la aplicación tiene que liberar todos los recursos usados y guardar los datos persistentes (como preferencias o estados persistentes). Hay que tener en cuenta que este método puede ser llamado tanto desde el estado Activo como del Pausado.

El MIDlet puede pedir que no quiere entrar en el estado Destruido lanzando una excepción MIDletStateChangeException. Esto sólo es valido si el parámetro del método (boolean unconditional) es falso, si es verdadero, el Midlet terminará su ejecución y no se puede evitar de ninguna forma. Si ocurre alguna excepción durante la ejecución de este método, es ignorada y el Midlet pasa a estado Destruido.

Además de los tres métodos vistos para tratar los cambios de estados que se producen en el Midlet por acciones externas (del entorno de ejecución o del usuario). El mismo Midlet puede pedir que se cambio su estado con los siguientes métodos:

public void notiyPaused ();
public void notiyDestroyed ();
public void resumeRequest ();

Estos método sirven para pasar el Midlet al estado Pausado, Destruido o Activo, respectivamente. Hay que tener en cuenta que cuando se utilizan estos métodos las funciones vistas no son llamadas, es decir, si queremos terminar la ejecución del Midlet ejecutando notifyDestroyed() tenemos que tener en cuenta que el método destroyApp() no va a ser llamado. Lo mismo ocurre con notifyPaused() y pauseApp(), y con resumeRequest() y startApp(). También hay que tener en cuenta que resumeRequest() no puede ser llamado desde nuestro Midlet, ya que está en estado pausado, para hacerlo usaremos una hebra en segundo plano o con un temporizador.

Ejemplo de uso de destroyAPP:

    ....
    if (esta_seguro) {
      //caso en que no se puede hacer nada
      try {
          destroyApp(esta_seguro);
      } catch (Exception e) {
        //No se puede hacer nada
      }
      notifyDestroyed();
    } else {
      //caso en que se puede hacer algo
      try {
          destroyApp(esta_seguro);
          notifyDestroyed();
      } catch (Exception e) {
        //Se puede hacer algo
        ....  
      }
    }//fin if-else

   ....

    //Método que se llama cuando se destruye el midlet
    protected void destroyApp(boolean incondicional) {
        if (!incondicional) throw new MIDletStateChangeException();
    }
   ....

3.- Ejercicios

Ejercicio: Realiza un midlet que nos muestre el ciclo de vida de un Midlet. Simplemente mostrar un mensaje por la consola del emulador diciéndonos que estamos cambiando de estado.