O'Reilly logo

Wireless Java by Qusay H. Mahmoud

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

A Simple Example

The examples that we’re going to demonstrate here, and throughout the rest of the book, are called MIDlets. If you’ve programmed with Java applets or servlets before, then you’ll likely recognize the similarities in the “fill-in-the-method” program structure. This first example, HelloMidlet.java, shown in Example 1-1, creates a text box and then prints the archetypal “Hello World” in a text box.

Example 1-1. “Hello World”

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

public class HelloMidlet extends MIDlet {

    // The display for this MIDlet
    private Display display;
    // TextBox to display text
    TextBox box = null;

    public HelloMidlet(  ) {
    }

    public void startApp(  ) {
        display = Display.getDisplay(this);
        box = new TextBox("Simple Example", "Hello World", 20, 0);
        display.setCurrent(box);
    }

    /**
     * Pause is a no-op since there are no background activities or
     * record stores that need to be closed.
     */
    public void pauseApp(  ) {
    }

    /**
     * Destroy must cleanup everything not handled by the garbage 
     * collector. In this case there is nothing to cleanup.
     */
    public void destroyApp(boolean unconditional) {
    }
}

This MIDlet consists of a public class definition that extends the MIDlet class found in javax.microedition.midlet . This superclass forms the base of all MIDlets in J2ME. Our HelloMidlet class contains a constructor, as well as the startApp() , pauseApp( ) , and destroyApp( ) methods that have been inherited from the MIDlet class. Note that there is no main() method in this program. Instead, the startApp(), pauseApp( ), and destroyApp( ) methods are called by the underlying framework to start up the MIDlet, to pause it, or to destroy it.

Let’s start off by compiling our program on the command line. Using the command line is a bit more complex than the KToolbar application that comes with the Wireless Toolkit, so in order to simplify it, be sure that you have entered the additional environment variables shown above. However, there are several steps that we need to perform when compiling J2ME applications, and it’s important to see each of the steps as they occur.

As you would expect, the program must be saved in a file called HelloMidlet.java. However, before you compile it, create a directory called tmpclasses. Then use the following command to compile the MIDlet from the command line in Windows:

C:\midlets> javac -g:none -d tmpclasses -bootclasspath %MIDPAPI% -classpath 
    %J2MECLASSPATH% HelloMidlet.java

In Linux and Solaris, the command looks like the following:

>javac -g:none -d tmpclasses -bootclasspath $MIDPAPI -classpath $J2MECLASSPATH
    HelloMidlet.java

This command compiles the Java source file without any debugging info, and sets the appropriate boot and J2ME classpaths to ensure that we don’t pick up any J2SE classes. The end result of this command is the creation of the HelloMidlet.class file in the tmpclasses directory.

With the J2SE, a class file was all you needed to run the application. However, all MIDlet classes must be preverified before they can be run on a target device. Why is this necessary? Remember that one of the tasks of the standard Java virtual machine (the one that comes with the J2SE) is to perform bytecode verification . Bytecode verification is one of the most important steps of the Java security model. It performs such tasks as ensuring that the bytecodes of a Java class (and their operands) are all valid; that the code does not overflow or underflow the VM stack; that local variables are not used before they are initialized; that field, method, and class access control modifiers are respected, and other important tasks. However, most of the bytecode verifier is not included with the KVM due to size constraints. The preverifier ensures that the equivalent security checks still take place.

Before you run the preverifier, create another directory called classes. Then, use this command to preverify the HelloMidlet class:

C:\midlets> preverify -classpath %MIDPAPI%;tmpclasses -d classes tmpclasses

Or on Solaris and Linux:

> preverify -classpath $MIDPAPI:tmpclasses -d classes tmpclasses

The resulting output should look something like this:

[Output directory for verified classes: classes]

This command takes all the classes inside the tmpclasses directory (of which HelloMidlet.class is the only one) and preverifies them, writing the resulting classes to the classes directory. Note that the names of the preverified classes remain exactly the same, which is why we created two separate directories to hold them.

Tip

If you received an “Illegal constant pool index” class loading error and you’re using JDK 1.4, try using JDK 1.3 until this issue is resolved.

The next step is to compress all the classes in the program (again, we have only one) as well as their resources, into a Java Archive (JAR) file. You can use the J2SE jar command to create a JAR file. Make sure you are in the classes directory to execute the following command:

> jar cvf HelloMidlet.jar HelloMidlet.class

The program will compress the HelloMidlet class into a JAR file, creating a manifest for it as well.

Note that with the javac compiler, you can create MIDlets of practically any size. However, that doesn’t guarantee that they will fit on the target device for which you’re writing the MIDlet. It would nice if there were a way to check if the target device can handle the MIDlet and run it before it is downloaded. Obviously, if a device can’t handle the MIDlet, there is no reason to even attempt a download.

To accomplish this, we need a file that manually specifies some pre-download properties, including the size of the MIDlet and its storage requirements. This can be accomplished by creating a Java Application Descriptor (JAD) file with your favorite text editor. Example 1-2 shows a sample JAD file that we can use. Note that you will need to change the MIDlet-Jar-Size entry to correspond to the size of the JAR file that you just created. (In Chapter 3, we will explain the JAD file syntax in more detail.)

Example 1-2. HelloMidlet.jad

MIDlet-1: Hello,,HelloMidlet
MIDlet-Name: HelloMidlet
MIDlet-Version: 1.0
MIDlet-Vendor: ORA
MIDlet-Jar-URL: HelloMidlet.jar
MIDlet-Jar-Size: 863

Let’s save this example JAD file as HelloMidlet.jad , again in the classes directory that holds the JAR file. Finally, to run this MIDlet, invoke Sun’s MIDP emulator to point at the JAD file using the following command:

> emulator -Xdescriptor:HelloMidlet.jad

If everything worked correctly, you should see a phone similar to Figure 1-4, although the display may be different. Here, the HelloMidlet is running in the default phone that comes with the Java Wireless Toolkit. If you click on the MIDlet on the menu (use the directional arrow pad to move the cursor and the button in the middle to select), and instruct it to “Launch” using the soft button on the lower right, you should see output similar to Figure 1-4. Congratulations! You just created your first Java MIDlet!

HelloMidlet

Figure 1-4. HelloMidlet

The gist of this program is in the startApp( ) method. Here, we obtain the current display that the device uses, then create a text box with the words “Hello World” inside of it. Finally, we show the text box on the current display. Don’t worry if you don’t understand these objects yet; the architecture of MIDlets will become clearer as we move through the book.

A Login MIDlet

Let’s move to a more advanced MIDlet. Example 1-3 shows a MIDlet with a hypothetical login screen that prompts the user to log in. If the login is incorrect, the program will repeatedly ask the user to try again.

Example 1-3. A login MIDlet

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

public class LoginMidlet extends MIDlet implements CommandListener {
   private Display display;
   private TextField userName;
   private TextField password;
   private Form form;
   private Command cancel;
   private Command login;

   public LoginMidlet(  ) {
      userName = new TextField("LoginID:", "", 10, TextField.ANY);
      password = new TextField("Password:", "", 10, TextField.PASSWORD);
      form = new Form("Sign in");
      cancel = new Command("Cancel", Command.CANCEL, 2);
      login = new Command("Login", Command.OK, 2);
   }

   public void startApp(  ) {
      display = Display.getDisplay(this);
      form.append(userName);
      form.append(password);
      form.addCommand(cancel);
      form.addCommand(login);
      form.setCommandListener(this);
      display.setCurrent(form);
   }

   public void pauseApp(  ) {
   }

   public void destroyApp(boolean unconditional) {
      notifyDestroyed(  );
   }

   public void validateUser(String name, String password) {
     if (name.equals("qm") && password.equals("j2")) {
       menu(  );
     } else {
       tryAgain(  );
     }
   }     

   public void menu(  ) {
     List services = new List("Choose one", Choice.EXCLUSIVE);
     services.append("Check Mail", null);
     services.append("Compose", null);
     services.append("Addresses", null);
     services.append("Options", null);
     services.append("Sign Out", null);
     display.setCurrent(services);
   }

   public void tryAgain(  ) {
     Alert error = new Alert("Login Incorrect", "Please try again", null,
         AlertType.ERROR);
     error.setTimeout(Alert.FOREVER);
     userName.setString("");
     password.setString("");
     display.setCurrent(error, form);
   }

   public void commandAction(Command c, Displayable d) {
      String label = c.getLabel(  );
       if(label.equals("Cancel")) {
        destroyApp(true);
      } else if(label.equals("Login")) {
         validateUser(userName.getString(), password.getString(  ));
      }
   }
}

Again, don’t worry if you can’t understand the entire program at this point; this example is just meant to give you a flavor of MIDP programming and some sample applications to compile and run. Chapter 5 and Chapter 6 will explain the GUI classes (such as Display, Form, and TextField), as well as the event-handling classes (such as Command) in much more detail.

That being said, let’s present a beginner’s overview of how this MIDlet works. As in the previous example, LoginMidlet extends the MIDlet abstract class. It also implements the CommandListener interface by providing an implementation for the commandAction( ) method. In this method, there are two commands: Login and Cancel. The label of the command is checked: if it is Cancel, the LoginMidlet is destroyed, and if it is Login, then the username and passwords are validated.

In the LoginMidlet’s constructor, a Form object, two TextField objects, and two Command objects are created. The TextField and Command objects are added to the form in the startApp() method. In addition, pauseApp() and destroyApp( ) perform minimal tasks.

Here is how the program operates: if the Login command is given, the application calls the validateUser( ) method to validate the username and password. If they are valid (in this case, they are hardcoded into the program for simplicity), then the menu( ) method is called to simulate a list of “useful services.” Otherwise, the tryAgain( ) is called to display an error message and to allow the user to reenter their name and password.

If you are using the command line to compile and execute, save this file named LoginMidlet.java, make sure that you have a classes and a tmpclasses directory, and use javac:

C:\midlets> javac -g:none -d tmpclasses -bootclasspath %MIDPAPI% -classpath
    %J2MECLASSPATH% LoginMidlet.java

If you are using Solaris or Linux, the command becomes:

>javac -g:none -d tmpclasses -bootclasspath $MIDPAPI -classpath $J2MECLASSPATH
    LoginMidlet.java

Next, remember that we must preverify the resulting class:

C:\midlets> preverify -classpath %MIDPAPI%;tmpclasses -d classes tmpclasses

or

> preverify -classpath $MIDPAPI:tmpclasses -d classes tmpclasses

Again, the preverified class is saved to the classes subdirectory in the current directory. Next, compress the resulting class into a JAR file:

 jar cvf  LoginMidlet.jar LoginMidlet.class

And finally, create a JAD file that describes the resulting JAR file in detail, as shown in Example 1-4.

Example 1-4. LoginMidlet.jad

MIDlet-1: Login,,LoginMidlet
MIDlet-Name: LoginMidlet
MIDlet-Version: 1.0
MIDlet-Vendor: ORA
MIDlet-Jar-URL: LoginMidlet.jar
MIDlet-Jar-Size: 1786

Again, don’t forget to change the size of the JAR file to match the size of the LoginMidlet.jar file after you create it.

At this point, the MIDlet can be run as in the previous example, using the MIDP emulator of the Java Wireless Toolkit, with the following command:

emulator -Xdescriptor:LoginMidlet.jad

In addition, the MIDlet can be run with any other emulator you may have available. For example, to whet your appetite, Figure 1-5 shows the LoginMidlet running on the Motorola i85s emulator (the i85s is a J2ME-enabled cell phone available from Motorola and Nextel).

LoginMidlet running in the Motorola i85s emulator (cropped)

Figure 1-5. LoginMidlet running in the Motorola i85s emulator (cropped)

Working with the Emulator

Note that the objects represented by the Command class are shown above the two “soft buttons” on the phone (the buttons with the black circles). If a soft button below the command is pressed, the command immediately above it is executed. Here, if the user enters the correct username and matching password and presses the Login button, the menu of services will be displayed. Otherwise, the alert will be displayed and the user can try again.

Also, you might be caught off guard the first time you try to enter text with your computer keyboard. It doesn’t work! That’s because you must use the input keys on the phone to enter the text. In this case, to enter the letter “G”, press the number “4.” To enter the letter “K”, press the number “5” twice. Note how each time you press a numeral, the system “cycles” through the letter corresponding to that number. To move down to entering text for the password, use the down arrow.

Well, that’s it! You’ve just created two professional MIDlets using J2ME! In the next two chapters, we’re going to take a much closer look at the CLDC and the MIDP, two exciting new areas of wireless Java development.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required