Thursday, February 10, 2011

Understanding J2ME Application Models

The management of an application - how it's started and stopped, when it can access system resources, how it discovers its initialization parameters - is shared between the operating system (or other system-level software) and the application itself. The application model defines how an application is managed and how management responsibilities are divided between the application and the underlying system. The Java 2 Platform, Micro Edition (J2ME) currently supports four different application models. This article describes each of them.

The Traditional Application Model
The simplest is the traditional application model, as described in Chapter 12 of The Java Language Specification. The entry point to the application is a static method called main(), as in this example:

public class MyClass {
public static void main( String[] args ){
// application starts here
}
}


The class that defines this method is usually referred to as the main class. To start the application, the Java Virtual Machine loads the main class and invokes its main() method. The application runs until it terminates itself by calling System.exit() (if the security manager allows the call) or until all non-daemon threads (including the one that started the application) have terminated. For example, the following application can be stopped only by the operating system, because it spawns a foreground thread that never terminates:

public class NeverEnding extends Thread {
public void run(){
while( true ){
try {
sleep( 1000 );
}
catch( InterruptedException e ){
}
}
}

public static void main( String[] args ){
NeverEnding ne = new NeverEnding();
ne.start();
}
}


Although the operating system can terminate the application without notice at any time, the application effectively has complete control over its life-cycle - when it terminates and when it acquires or releases system resources. The application is really an unmanaged application; the operating system participates only in its activation. If the operating system suddenly terminates the application, the application may not have the chance to save its state or release the system resources it has acquired.

For many purposes, the traditional application model works very well. Most interactive J2SE and PersonalJava applications are unmanaged, terminating only at the user's direction. This model works because the user can move or minimize application windows in order to access other applications without having to shut down or pause the current application to free system resources.

On the J2ME platform, the traditional application model is supported by both the Connected Device Configuration (CDC) and the Connected Limited Device Configuration (CLDC), although individual profiles may not support it. For example, the Personal Basis Profile and the Personal Profile do, but the Mobile Information Device Profile and the Personal Digital Assistant Profile don't.

The Applet Model
An applet is an embedded application that runs under the control of a web browser. The applet is closely linked to the web page that contains it, because the page provides the applet's display area. In effect, the applet's user interface is not entirely under its own control: the user can move from page to page in the browser without asking for the applet's permission to do so. It makes sense to pause or even destroy the applet when the user moves to a different page, and to resume or restart the applet if the user returns to the original page. Unlike traditional applications, then, applets are managed applications, because an applet's life-cycle is under the browser's control.

The applet model is not new, of course, and has been supported since the first public release of Java. On the J2ME platform, applet support is currently found only in the Personal Profile.

The Applet Life-Cycle
The main class in an applet extends java.applet.Applet, which itself extends java.awt.Panel. Besides providing the applet's display area, the main class defines four life-cycle notification methods: init(), start(), stop(), and destroy().

There are four states in an applet's life-cycle:

* loaded: An applet instance has been constructed, but no initialization has yet occurred.

* stopped: The applet has been initialized but is inactive.

* started: The applet is active.

* destroyed: The applet has been terminated and the applet instance is ready for reclamation by the garbage collector.

An applet is created whenever the web browser loads and displays a page that includes the appropriate tags. Developers of HTML pages customarily use the applet tag, as in this example:

width="300" height="200">



There are other ways to load an applet, but the effect is the same: the browser downloads the applet's main class, and the obligatory public no-argument constructor creates an instance of the class.

The applet's initial state is loaded. Generally, the applet should not perform any initialization in its constructor, because at this point its operating context - including important information like its parent container and any initialization parameters - has not been set. When the context is ready, the browser changes the applet to the stopped state and calls its init() method. This method is called once during the applet's life-cycle, before any of the other notification methods.

Once the applet is initialized, it is ready for activation. Activation occurs whenever the applet moves from stopped to started, generally when the browser displays the web page containing the applet. Activation invokes the applet's start() method. The applet can use this notification to perform further initialization, such as creating background threads and other resource-intensive activities.

The opposite of activation is deactivation, which occurs whenever the applet's state moves back from started to stopped. This transition usually occurs when the browser stops displaying the page containing the applet, for example when the user presses the browser's Back button to return to the previous page. Deactivation invokes the applet's stop() method. The applet normally releases any resources it acquired in the start() method, because it may not be reactivated for a while. Note that releasing resources is voluntary, the system does not force the application to do so.

Whenever it is stopped, the browser may destroy the applet to free the remaining resources devoted to it, immediately after stopping the applet, perhaps, or when a long interval has passed since it was last activated. Destroying the applet invokes its destroy() method - the applet's final chance to do anything while its operating context is still valid.

The code for a basic applet looks like this:

public class BasicApplet extends java.applet.Applet {
public BasicApplet(){
// constructor - don't do much here
}

public void init(){
// applet context is ready, perform all one-time
// initialization here
}

public void start(){
// the applet is being displayed
}

public void stop(){
// the applet is being hidden
}

public void destroy(){
// free up all resources
}
}


The Applet Context
Besides defining life-cycle notification methods, the java.applet.Applet class also defines methods that let the applet interact with its operating context, the environment in which it runs. The getParameter() method, for example, returns applet parameter values. A few of these methods are actually declared by the java.applet.AppletContext interface, an instance of which is returned by the getAppletContext() method.

The applet context is important for two reasons. First, it allows an applet to obtain resources - initialization parameters, images, audio clips - from the web browser. Second, it allows an applet to control the web browser as it runs. The control is limited, however, to the following actions:

* Resizing the applet (the browser may silently refuse to do so)

* Playing an audio clip

* Displaying a message in the browser's status bar

* Opening a new browser window with a specified URL

* Replacing the current web page with a new page

Note that, unlike the other kinds of applications, an applet has no way to affect its life-cycle directly. To deactivate itself, for example, an applet must replace the current web page with a new one.

The MIDlet Model
A MIDlet is a Mobile Information Device Profile (MIDP) application. Like an applet, a MIDlet is a managed application. Instead of being managed by a web browser, however, it is managed by special-purpose application-management software (AMS) built into the device, often a cell phone or a two-way interactive pager. External management of the application makes sense in this context because it may be interrupted at any point by outside events. It would be poor behavior, for example, for a running application to prevent the user from answering incoming phone calls.

The MIDlet model is also supported by the Personal Digital Assistant Profile (PDAP), which extends the model to support applications called PDAlets. For our purposes, however, the two models are equivalent.

The MIDlet Life-Cycle
A MIDlet's main class extends javax.microedition.midlet.MIDlet. The main class defines three life-cycle notification methods: startApp(), pauseApp(), and destroyApp().

There are three possible states in a MIDlet's life-cycle:

* paused: The MIDlet instance has been constructed and is inactive.

* active: The MIDlet is active.

* destroyed: The MIDlet has been terminated and is ready for reclamation by the garbage collector.

Note that there is no equivalent to an applet's loaded state, because there is no initialization method. Normally, a MIDlet initializes itself the first time its startApp() method is invoked.

MIDlets are created by the AMS, typically in response to a user request. For example, the AMS may list all the MIDlets installed on the system and let the user select one.

A MIDlet's initial state is paused. Like an applet, a MIDlet should perform little or no initialization in its constructor, because its operating context has not yet been set.

At some point after construction, the AMS activates the MIDlet and invokes its startApp() method. After performing any necessary initialization, startApp() creates and displays the application's user interface. After it returns from startApp(), the MIDlet's state changes from paused to active. If the MIDlet cannot initialize itself for any reason, it must throw a javax.microedition.midlet.MIDletStateChangeException - at which point it immediately shifts to the destroyed state.

Deactivation occurs on any transition from the active state to the paused state. The MIDlet is not destroyed, of course, but it should release as many system resources as possible. If deactivation is initiated by the AMS, the MIDlet's pauseApp() method is invoked. If the MIDlet deactivates itself, using the MIDlet's operating context, pauseApp() is not called.

Destruction occurs when the MIDlet changes to the destroyed state from either active or paused. If destruction is initiated by the AMS, the MIDlet's destroyApp() method is invoked. A boolean parameter passed to the method indicates whether the destruction is unconditional (it must occur) or optional. The MIDlet can refuse optional destruction by throwing a MIDletStateChangeException. If the MIDlet destroys itself, destroyApp() is not called.

The code for a basic MIDlet looks like this:

import javax.microedition.midlet.*;

public class BasicMIDlet extends MIDlet {
public BasicMIDlet(){
// constructor - don't do much here
}

protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
// called when the system destroys the MIDlet
}

protected void pauseApp(){
// called when the system pauses the MIDlet
}

protected void startApp()
throws MIDletStateChangeException {
// called when the system activates the MIDlet
}
}


The MIDlet Context
The javax.microedition.midlet.MIDlet class also defines methods that let a MIDlet interact with its operating context: getAppProperty() returns initialization property values; resumeRequest() asks the AMS to reactivate the MIDlet; notifyPaused() shifts the MIDlet to the paused state; and notifyDestroyed() shifts the MIDlet to the destroyed state.

MIDlet initialization properties are name-value pairs in the MIDlet's application descriptor or in its manifest. The application descriptor is a separate text file that lists important information about a set of MIDlets packaged together into a single JAR file (a MIDlet suite). The manifest is the standard JAR manifest packaged with the MIDlet suite. When getAppProperty() is invoked, it searches the application descriptor first, then the manifest. (Note that MIDP 2.0 introduces the concept of trusted suites, in which case getAppProperty() searches only the manifest.)

The remaining methods directly affect the MIDlet's life-cycle. A paused MIDlet calls resumeRequest() to be reactivated. An active MIDlet calls notifyPaused() to be deactivated. A paused or active MIDlet calls notifyDestroyed() to be destroyed. Note that resumeRequest() merely asks the AMS to reactivate the MIDlet; the AMS decides whether and when to reactivate the MIDlet. Reactivation invokes the MIDlet's startApp() method. By contrast, notifyPaused() or notifyDestroyed() causes an immediate transition to the new state; as a consequence, neither pauseApp() nor destroyApp() is invoked.

The code for a better basic MIDlet looks like this:

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

public class BetterMIDlet extends MIDlet {

private Display display;

public BetterMIDlet(){
}

protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitApp(); // call cleanup code
}

protected void pauseApp(){
// add pause code here
}

protected void startApp()
throws MIDletStateChangeException {
if( display == null ){
initApp(); // perform one-time initialization
}
// add per-activation code here
}

private void initApp(){
display = Display.getDisplay( this );
// add initialization code here
}

public void exitApp(){
// add cleanup code here
notifyDestroyed(); // destroys MIDlet
}
}


Unlike the BasicMIDlet class, BetterMIDlet defines an initApp() method for one-time initialization (called the first time startApp() is invoked) and an exitApp() method for centralized resource cleanup.

The Xlet Model
An Xlet is yet another kind of managed application. Originally part of the Java TV API, Xlets have been adopted for use in the Personal Basis Profile (PBP) and in its superset, the Personal Profile (PP). Like MIDlets, Xlets are managed by special-purpose application management software.

The Xlet Life-Cycle
An Xlet's main class implements the javax.microedition.xlet.Xlet interface, which declares four life-cycle notification methods: initXlet(), startXlet(), pauseXlet(), and destroyXlet(). Note that, unlike applets or MIDlets, an Xlet does not have to extend any particular class.

Like applets, Xlets have four possible states:

* loaded: The Xlet instance has been constructed, but no initialization has yet occurred.

* paused: The Xlet has been initialized but is inactive.

* active: The Xlet is active.

* destroyed: The Xlet has been terminated and is ready for garbage collection.

When the AMS creates an Xlet, it starts in the loaded state. Soon after construction, the AMS invokes the Xlet's initXlet() method, passing the XletContext that the Xlet must use to interact with its operating context (this parameter is necessary because the Xlet does not extend a specific base class). After initialization, the Xlet changes to the paused state.

At this point, an Xlet behaves more like a MIDlet than an applet. At some point, the AMS activates the Xlet and invokes its startXlet() method. The Xlet activates its user interface, obtains the system resources it needs to function properly, then shifts to the active state.

Deactivation occurs when the Xlet's state changes from active to paused. When the AMS deactivates the Xlet, it invokes the Xlet's pauseXlet() method. The Xlet frees as many resources as possible. If the Xlet deactivates itself, however, the pauseXlet method is not invoked.

An Xlet can change to the destroyed state at any time. If the AMS destroys the Xlet, it invokes the destroyXlet() method. Like MIDlets, Xlets can sometimes abort their destruction by throwing an exception. If an Xlet destroys itself, destroyXlet() is not invoked.

The code for a basic Xlet looks like this:

import javax.microedition.xlet.*;

public class BasicXlet implements Xlet {
private XletContext context;

public BasicXlet(){
// constructor - don't do much here
}

public void initXlet( XletContext context )
throws XletStateChangeException {
// called by the system to initialize the Xlet
this.context = context; // stash the context
// put other initialization code here
}

public void destroyXlet( boolean unconditional )
throws XletStateChangeException {
// called when the system destroys the Xlet
}

public void pauseXlet(){
// called when the system pauses the Xlet
}

public void startXlet() throws XletStateChangeException {
// called when the system activates the Xlet
}
}


The Xlet Context
In the Xlet model, an application interacts with its operating context by way of an object that implements the javax.microedition.xlet.XletContext interface. This interface declares five methods: getContainer() obtains the application's root user-interface object; getXletProperty() returns initialization property values; notifyDestroyed() changes the Xlet's state to destroyed; notifyPaused() changes its state to paused; and resumeRequest() asks the AMS to reactivate the Xlet.

An Xlet uses the resumeRequest(), notifyDestroyed() and notifyPaused() methods the same ways a MIDlet does. A better version of the basic Xlet code looks like this:

import javax.microedition.xlet.*;

public class BetterXlet implements Xlet {
private XletContext context;

public BetterXlet(){
}

public void destroyXlet( boolean unconditional )
throws XletStateChangeException {
exitXlet(); // call cleanup code
}

public void exitXlet(){
// add cleanup code here
context.notifyDestroyed(); // destroys Xlet
}

public XletContext getContext(){ // for convenience
return context;
}

public void initXlet( XletContext context )
throws XletStateChangeException {
this.context = context; // store the context
// add initialization code here
}

public void pauseXlet(){
// add pause code here
}

public void startXlet() throws XletStateChangeException {
// add per-activation code here
}
}

SOURCE:http://developers.sun.com/mobility/midp/articles/models/

0 comments: