Chapter 9. Creating a MIDlet

If you have any experience creating Java applications or applets, then programming in J2ME won't seem like such a stretch. The steps are basically the same:

  1. Write your program and save it as a text file with the .java extension.

  2. Compile it.

  3. Pre-verify it.

  4. Package it.

  5. Test it.

  6. Debug it.

  7. Release it!

The only thing that should set off your mental alarm is step number 3—pre-verification. This might sound weird and complicated, but it's actually quite easy. The purpose of pre-verification is to go through your bytecode and set hints up so that the actual verification of bytecode on the micro device will happen much more quickly, saving you valuable startup time.

Command-Line MIDlet Development

You don't really need any fancy tools to create a MIDlet. Simply install Java SDK 1.3 and the MIDlet libraries. Get the Java SDK 1.3 from http://java.sun.com/j2se/1.3/. Get the CLDC packages from http://www.sun.com/software/communitysource/j2me/cldc/download.html. And grab the MIDP libraries from http://java.sun.com/products/midp/.

Install everything into the same directory. To do so, create a directory similar to mkdir j2me. You should then unzip the j2me_cldc-1_0-src-winsol.zip file into the C:j2me directory. Then unzip midp-1_0a-spec.zip into the same directory.

You are now ready to write your MIDlet application. A bit later in this chapter, we will discuss what all these methods mean and how it all works. For now, just use a text editor to create the file Hello.java:

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

public class Hello extends MIDlet {
  private Display display;
  TextBox t = null;

  public Hello()
  {
    display = Display.getDisplay(this);
  }

  public void startApp()
  {
    t = new TextBox("Hello ", "Howdy!", 256, 0);
    display.setCurrent(t);
  }

  public void pauseApp() { }

  public void destroyApp(boolean unconditional) { }
}

Make sure the Hello.java program is in the c:j2me directory.

You can now compile the program the same way you would compile any other Java application. Simply point to the appropriate MIDP and CLDC classes:

javac -bootclasspath c:j2memidpclasses Hello.java

This should create the Hello.class file. You can now pre-verify the class:

c:j2mecldcpreverify HelloMIDlet

This command will automatically create an “output” directory beneath the current directory and put the pre-verified class into this new directory. Move to the output directory as follows:

cd output

Then package your application into a JAR file. Whenever you build a MIDP application, you should place all pre-verified class files, images, and other resources into a JAR.

The command to package things up into a JAR named “HelloWorld” is thus:

jar cf HelloWorld.jar Hello.class

Every MIDlet package should also include a special JAD file. This simple text file is a description of what the JAR contains, what device it is intended for, and how much memory it takes up. Typically, a micro device will read the JAD file to determine how to download or otherwise deploy the JAR file.

So, create a file called HelloWorld.JAD with the following content:

MIDlet-1: HelloWorld, HelloWorld.png, HelloMIDlet
MIDlet-Jar-Size: 1178
MIDlet-Jar-URL: HelloWorld.jar
MIDlet-Name: HelloWorld
MIDlet-Vendor: Sun Microsystems
MIDlet-Version: 1.0

That's it! You can now load and run the HelloWorld.JAR and HelloWorld.JAD files onto any MIDP emulator or device!

Development Environments

The procedure outlined in the previous section is kind of complicated, though, isn't it? Luckily, there are many development environments that do all the compiling, pre-verification, creation of JAR and JAD files, and other packaging for you. Metrowerk's Code Warrior has a J2ME plug-in, and Borland's JBuilder has a Handheld Express add-on. In addition, Nokia, Siemens, RIM, Zucotto, and Motorola all offer special SDKs and IDEs for J2ME development. Many of these vendor-specific IDEs are discussed in later chapters, but you can also get more information about each on the Web:

Wireless Toolkit

Throughout this book, we will be focusing on a product called the J2ME Wireless Toolkit. You can download it from http://java.sun.com/products/j2mewtoolkit/.

The Wireless Toolkit, developed by Sun, is free of charge, complete, easy to use, and available for Windows, Linux, and Solaris. It also comes with a bunch of source code, including sample games such as Snake, Sokoban, a tile-sliding game, Pong, and Star Cruiser. It also includes a slew of emulators, shown in Figure 9.1, that enable you to test your applications on a black and white phone, a color phone, a pager, a Palm, or vendor-specific phones, such as the Motorola i85s.

Sun's Wireless Toolkit. To run the Wireless Toolkit, you'll need Java itself (JDK 1.3 or better), which has all the engines and libraries necessary to compile code. If you don't already have the JDK, you can grab it at http://java.sun.com/j2se/1.3/. Be sure to install it per directions, with all the proper settings for classpaths and paths.

Figure 9.1. Sun's Wireless Toolkit. To run the Wireless Toolkit, you'll need Java itself (JDK 1.3 or better), which has all the engines and libraries necessary to compile code. If you don't already have the JDK, you can grab it at http://java.sun.com/j2se/1.3/. Be sure to install it per directions, with all the proper settings for classpaths and paths.

NOTE

The Java SDK must be installed before you install the Wireless Toolkit.

If you like, you can integrate the Wireless Toolkit with Sun's free Forte development environment. You can download Forte at http://www.sun.com/forte/ffj/.

The Wireless Toolkit can also be integrated into Borland's JBuilder.

Developing a MIDlet with the Wireless Toolkit

Let's walk through the process of writing, compiling, testing, and packaging a MIDlet.

NOTE

The Wireless Toolkit is installed by default in the directory C:j2mewtk. If you have chosen to install to a different directory, then modify all the following commands appropriately.

First off, you can run the Wireless Toolkit Preferences program to set up a proxy server, as well as the preferred heap size to emulate.

You can then run the Ktoolbar shortcut, which loads up a graphical menu with all your development options, as shown in Figure 9.1.

  1. To create a new project, hit the New Project button. Give your project a simple name (with no spaces), and type in the name of the main MIDlet class. For example, if you are creating a Hello World application, use Project name “HelloWorld” and MIDlet Class name “Hello.”

  2. The settings dialog for the project will appear as in Figure 9.2. These are the properties that will eventually appear in the application's JAD file. You can modify the properties as you see fit. Underneath the MIDlets tab you can modify the display name of your MIDlet, the application's icon, and the application's main class file. Using an icon is optional.

    The settingsSettings dialog (Wireless Toolkit)dialogsSettings (Wireless Toolkit) dialog.

    Figure 9.2. The settings dialog.

    Note that any given JAR file might have several applications included within it. For example, you might want to package several games together into the same arcade.

    In any event, hit the OK button to save the settings. You can modify the settings at any time by hitting the Settings button.

  3. A new directory will be created beneath the C:J2mewtkapps directory. In this case, we'll have a C:J2mewtkappsHelloWorld directory. Beneath this directory will be four other directories: bin, lib, res, and src.

  4. You can create your Java class or classes using any text editor or other development environment. Drop all the Java files into the C:J2mewtkappsHelloWorldsrc directory.

    For example, drop the Hello.java file (listed in the previous section) into this directory.

  5. If your application uses any PNG images or other resources, drop those in the C:J2mewtkappsHelloWorld es directory.

  6. You can now compile, pre-verify, and package your application in one step. Just hit the Build button.

    If all goes well, the console will give you a Build Complete message. Otherwise, any errors will be shown. Go through your Java source files and correct any bugs.

  7. You can test the program using the built-in emulator. Choose which device you want to emulate using the Device pull-down menu. You can choose DefaultGrayPhone for a phone with a black and white screen, DefaultColorPhone for a color screen, MinimumPhone for a the simplest possible MIDP device, Motorola i85s, Palm device, or RIM pager device.

    To run the emulator, hit the Run button. A list of all the MIDlets available for launching will appear. Select HelloWorld and then hit the Launch button. The application will run, as shown in Figure 9.3.

    The Hello World MIDlet.

    Figure 9.3. The Hello World MIDlet.

  8. You can now actually build the JAR file. Select the top Project menu and choose the Package option. Look under the C:J2mewtkappsHelloWorldin directory. You'll notice a HelloWorld.jar file and a HelloWorld.jad file.

    Actually installing the JAR and JAD files differs from device to device. Later chapters in this book cover how to deploy MIDlets on Siemens, NTT DoComo, and other devices.

Lifecycle of a MIDlet

Why is a MIDlet called a MIDlet? Because it is a special type of applet that runs on MIDP-compliant devices. Cute, eh? Just as a standard Java applet extends the java.applet.Applet class, a MIDlet extends the javax.microedition.MIDlet.MIDlet class.

The MIDlet class contains all the goodies that the phone's application management system needs to tap into your application and start, pause, and end processes. The javax.microedition.midlet.MIDlet class has several abstract methods that you must define in your main class file:

  • public void startApp()—. This method is called the moment your MIDlet becomes active. While active, your MIDlet might run and access the phone's resources. The method is called when your program is first run, as well as when your program is released from the paused state.

  • public void pauseApp()—. Most MIDP devices permit the user to pause the current application. For example, if a player's phone rings, then she might choose to pause the game and answer the call. Whenever a pause event takes place, this method is called. While in the paused state, your MIDlet must release shared resources. This is also a good place to pause any game timers, and so on. This method will only be called when the MIDlet is in the active state. Some devices (such as the Siemens SL45i) never call this method; however, the method must always be included in your program.

  • public void destroyApp(boolean unconditional)—. When the user chooses to end the game, the phone will automatically call this method. At this point, your MIDlet will terminate and enter the destroyed state. In the destroyed state, the MIDlet should release all resources, stop all threads, and save any persistent state. This method can be called while the MIDlet is in either the paused or active state.

    The unconditional flag determines whether the program must quit, or whether it would just be nice if the program quits. If the flag is set to true, then the phone's user definitely wants out. The MIDlet must be sure to clean up all resources properly. However, some phones might try to quit the application after a given amount of idle time. In such a case, the unconditional flag will be set to false. The MIDlet can avoid entering the destroyed state by throwing a MIDletStateChangeException.

These states—active, paused, and destroyed—enable the handheld device's application management software to manage the activities of multiple MIDlets within the same runtime environment. It can select which MIDlets are active at a given time by starting and pausing them individually. The application management software maintains the state of the MIDlet and invokes methods on the MIDlet to change the states. The MIDlet implements these methods to update its internal activities and resource usage as directed by the application management software. The state change is not considered complete until the state change method has returned. It is intended that these methods return quickly. Listing 9.1 shows the structure of the world's simplest (and most useless) Java MIDlet:

Example 9.1. A Minimal MIDlet Implementation

import javax.microedition.midlet.*;

public class Game extends MIDlet
{
  public void startApp() {}
  public void pauseApp() {}
  public void destroyApp(boolean b) {}

  public void exit()
  {
    destroyApp(false);
    notifyDestroyed();
  }
}

The method exit() is added to provide a remote call to help terminate the application.

Displaying Stuff

To draw something on the micro device screen, you need to access the display. To do so, you can use the javax.microedition.lcdui.Display class, which is statically included with every MIDlet.

Display represents the system's graphical display and input devices. It includes methods for retrieving properties of the device and for requesting that objects be displayed on the device.

There is exactly one instance of the Display class per MIDlet. To get a reference to the instance, call the getDisplay() method. The application may call the method anywhere in the code, at any time.

Any user interface objects that you can paint on the display must extend the Displayable class. Any Displayable object may have commands and listeners associated with it. The contents displayed and their interactions with the user are defined by subclasses. Basically, every screen that you'll want to show should be defined as a separate Displayable object.

A device can only show one Displayable object at a time. This object is referred to as the current Displayable object.

The Display class has the following important methods:

  • isColor()—. Returns true if the current device has a color screen, returns false otherwise.

  • numColors()—. Returns the number of colors or grayscales that can be represented on the device.

  • getCurrent()—. Returns the current Displayable object. The Displayable object returned might not actually be visible on the display if the MIDlet is running in the background, or if the Displayable object is currently obscured by a system screen. The value returned by getCurrent() might also be null if the setCurrent() method has not been called yet.

  • setCurrent(Displayable nextDisplayable)—. This is a key method that actually changes the current display. Simply pass in a new Displayable object. The change will typically not take effect immediately, but may be delayed so that it occurs between event delivery method calls. Because of this delay, a call to getCurrent() shortly after a call to setCurrent() is unlikely to return the value passed to setCurrent().

    When a MIDlet application is first started, there is no current Displayable object. It is the responsibility of the application to ensure that a Displayable object is visible and can interact with the user at all times. Therefore, an application should always call setCurrent() as part of its initialization.

  • setCurrent(Alert alert, Displayable nextDisplayable)—. This is a version of setCurrent() specially suited for alerts. An alert is a special type of Displayable object that is intended to be shown and immediately dismissed. For example, a typical alert might be a dialog box that warns the player about some imminent problem.

    To use this method, set the alert as the current Displayable object and choose another screen as the nextDisplayable. As soon as the alert box is dismissed, the next Displayable screen will be shown.

Working with Screens

The javax.microedition.lcdui.Screen class is the common superclass of all high-level user interface objects. The Screen itself is pretty simple. It simply allows you to add a title or scrolling ticker to the Displayable class.

Every screen that a user will see should be created as its own class. The display will automatically refresh whenever the contents of a screen are updated. For example, suppose a List object featuring a main game menu is currently being displayed. If the application inserts a new element at the beginning of the List, it is displayed immediately and the other elements will be rearranged appropriately. There is no need for the application to call another method to refresh the display.

WARNING

It is good programming practice to only change the contents of a screen when it is not visible (that is, while another Displayable is current). Changing the contents of the screen while it is visible may result in performance problems on some devices, and might also be confusing if the screen's content changes at the same moment when a user is interacting with it.

The following classes are subclasses of the Screen class:

  • Form

  • Alert

  • List

  • TextBox

All these classes inherit four methods from Screen:

  • getTitle()—. Gets the title of the Screen.

  • setTitle(String title)—. Sets the title of the Screen. If the Screen is physically visible, the visible effect should take place no later than immediately after the callback.

  • getTicker()—. Gets the scrolling ticker object used by the Screen.

  • setTicker(Ticker ticker)—. Sets a scrolling ticker to be used for this Screen, replacing any previous ticker. Several Screen objects within an application can share the same ticker. This is done by calling setTicker() on different screens with the same Ticker object.

Forms

The javax.microedition.lcdui.Form class is the most commonly used child of Screen. It might contain an arbitrary mixture of items, such as images, text fields, date fields, gauges, and choice groups. In general, any subclass of the Item class can be contained within a Form.

Every mobile device will handle the layout, traversal, and scrolling of a form in a slightly different way.

The items contained in a Form are referred to by their indices, which are consecutive integers starting from zero. These items can be edited using the append(), delete(), insert(), and set() methods. More information about dealing with user interface items can be found in Chapter 13, “High-Level Approach.”

Listing 9.2, for example, creates a start-up form and sets it as the current Displayable.

Example 9.2. Creating and Calling a Form

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

public class Game extends MIDlet
{
  private Display display;

  public void startApp()
  {
    display = Display.getDisplay(this);
    StartForm form = new StartForm(this);
    display.setCurrent(form);
  }

  public void pauseApp() {}
  public void destroyApp(boolean b) {}

  public Display getDisplay()
  {
    return display;
  }

  public void exit()
  {
    destroyApp(false);
    notifyDestroyed();
  }
}

The code for the StartForm class can be seen in Listing 9.3.

Example 9.3. The StartForm Class

import javax.microedition.lcdui.*;

public class StartForm extends Form
{
  private Game game;

  public StartForm(Game game)
  {
    super("Micro Racer");
    this.game = game;
    StringItem item = new StringItem(
        "Welcome to Micro Racer!", null);
    append(item);
  }
}

The final product can be seen in Figure 9.4.

Game intro screen.

Figure 9.4. Game intro screen.

New forms must extend the Form class. The form's constructor must call the parent's constructor, which accepts the title as a parameter. To be able to access the MIDlet's exit() and other methods, a global variable pointing to the main Game class is provided.

javax.microedition.lcdui.StringItem is a user interface component to present different read-only text labels. More information about StringItem and other user interface components can be found in Chapter 13, “High-Level Graphical User Interfaces.”

Each Form has the following important methods:

  • append (Item item)—. Adds a user interface item into the Form.

  • append(String str)—. Adds a string to the Form.

  • append(Image img)—. Adds an image to the Form.

  • insert(int itemNum, Item item)—. Inserts an item into the Form just prior to the item number specified. The size of the Form grows by one. The itemNum parameter must be within the current range of actual items.

  • delete(int itemNum)—. Deletes the item at itemNum.

  • set(int itemNum, Item item)—. Sets the item referenced by itemNum to the specified item, replacing the previous item. The previous item is removed from the Form.

  • get(int itemNum)—. Gets the item at given position.

  • setItemStateListener(ItemStateListener listener)—. Sets the item state listener for the Form, replacing any previous listener. If the listener is null, it simply removes the previous listener. An item state listener enables your application to dynamically handle any changes to the form's items.

  • size()—. Returns the number of items in the Form.

Every Screen's subclass also implements the Displayable interface, which means you can use the isShown() method that returns true only if the Form is actually visible on the display. In order for a Displayable to be visible, all the following must be true:

  • The MIDlet must be running in the foreground

  • The Displayable must be the display's current screen

  • The Displayable must not be obscured by a system screen

Menus and Commands

Because the MIDP user interface is highly abstract, it does not dictate any concrete interaction techniques, such as soft buttons or menus. Even low-level interactions such as scrolling are hidden to the application.

Instead, MIDP defines the javax.microedition.lcdui.Command class. Whenever a user hits a button, menu, dial, touch-screen, or other supported input element, a particular command will be triggered.

Because every Screen's subclass implements the Displayable interface, every screen has access to a slew of command methods:

  • addCommand(Command cmd)—. Adds a command to the Displayable.

  • removeCommand(Command cmd)—. Removes a command from the Displayable.

  • setCommandListener(CommandListener listener)—. Sets a listener for Commands to this Displayable, replacing any previous CommandListener. A null reference is allowed, and has the effect of removing any existing listener.

Whenever the user hits a key (or does something else command-worthy), a command will be issued to any registered command listener. Every Command is made up of three elements:

  • Label

  • Command type

  • Priority

A command label is a String that will be shown to let the user know what a command actually does. For example, most phones have two soft keys right beneath their display. A typical label might be set to “Quit.” The word “quit” would then appear above the first soft key. When this key is pressed, the application will catch the command and exit smoothly.

Other times, a menu of various commands might be presented to the user, as shown in Figure 9.5. The user can use the phone's arrow keys to scroll to a particular command and select it.

A sample menu of commands.

Figure 9.5. A sample menu of commands.

A command's type specifies the intent of the command. For example, if the application specifies that the command is of type BACK (to go back to the previously shown screen), then some devices will automatically associate all back commands with a given soft key. The defined command types are as follows:

  • BACK—. Returns the user to the previous screen.

  • OK—. A command that is a standard positive answer to a dialog.

  • CANCEL—. A command that is a standard negative answer to a dialog.

  • EXIT—. A command used for exiting from the application.

  • HELP—. A request for online help.

  • ITEM—. A command type relevant to a particular user interface item on the screen.

  • SCREEN—. An application-defined command that somehow pertains to the current screen.

  • STOP—. A command that will stop some currently running process or operation.

Finally, the command's priority value describes the importance of this command relative to other commands on the same screen. Priority values are integers, where a lower number indicates greater importance. The actual values are chosen by the application. A priority value of one indicates the most important command.

Typically, a mobile device will position a command on the screen based on its type and then order similar commands based on their priority. This usually means that the command with the highest priority is placed so that user can trigger it directly (using the soft keys), and that commands with lower priority are placed on an inner menu.

It is also possible for several commands to have the same priorities and types. If this occurs, each device will choose the order in which they are presented. Usually, the first command you create in your code will be given higher priority.

The javax.microedition.lcdui.CommandListener interface is used by applications to receive high-level events that are invoked by commands. The application must provide an implementation of a listener and must provide an instance of it on a screen in order to receive high-level events on that screen.

WARNING

The specification does not require the platform to create multiple threads for event delivery. Thus, if the listener method does not return, or the return is delayed, the system might be blocked. The Listener method should always return immediately.

Listing 9.4 shows a typical set of commands, along with a listener. The first command, Play, will appear in the bottom row of the screen, linked to the first soft key. The second soft key will be linked to an command named Menu (created automatically by the phone).

When the Menu soft key is hit, the remaining commands will appear in a menu, as shown in Figure 9.5.

Example 9.4. A Command Listener

import javax.microedition.lcdui.*;

public class StartForm extends Form
    implements CommandListener
{
  private Game game;
  private Command playCommand;
  private Command helpCommand;
  private Command aboutCommand;
  private Command exitCommand;

  public StartForm(Game game)
  {
    super("Micro Racer");
    this.game = game;
    StringItem item = new StringItem(
        "Welcome to Micro Racer!", null);
    append(item);
    playCommand = new Command("Play", Command.SCREEN, 1);
    helpCommand = new Command("Help", Command.HELP, 2);
    aboutCommand = new Command("About",
         Command.SCREEN, 3);
    exitCommand = new Command("Exit", Command.EXIT, 4);
         addCommand(playCommand);
    addCommand(helpCommand);
    addCommand(aboutCommand);
    addCommand(exitCommand);
    setCommandListener(this);
  }

  public void commandAction(Command c, Displayable s)
  {
    if (c.equals(playCommand))
    {
      // The Play Command has been selected.
    }
    else if (c.equals(helpCommand))
    {
      // The Help Command has been selected.
    }
    else if (c.equals(aboutCommand))
    {
      // The About Command has been selected.
    }
    else if (c.equals(exitCommand))
    {
      // The Exit Command has been selected.
      game.exit();
    }
  }
}

To create commands, add them as a global variable, construct them using new, then plop them on a screen using the addCommand() method.

To actually catch the commands, implement a CommandListener and register it using the setCommandListener() method.

Creating Help and About Alert Screens

An alert is a screen that shows data to the user and waits for a certain period before proceeding to the next screen. An alert generally contains some descriptive text, an optional image icon, and several special commands—usually OK and, optionally, CANCEL. Figure 9.6 illustrates an example.

The Help alert.Help alertalertsHelp

Figure 9.6. The Help alert.

The Alert Class

The javax.microedition.lcdui.Alert class makes it easy to create alerts. The intended use of an alert is to inform the user about information, errors, and other exceptional conditions. Every alert can have an javax.microedition.lcdui.AlertType class associated with it to provide an indication of its nature.

An Alert's constructor accepts four parameters:

  • Title (for example, “Help” or “About”)

  • Alert text

  • Alert image (may be set to null if not needed)

  • Alert type

After constructing an alert, an application should set the alert timeout. The timeout may be set to infinity by using the setTimeout(Alert.FOREVER) method. In this case, the alert is considered to be modal—forcing the user to hit the OK or CANCEL command to dismiss it.

WARNING

If you put too much content in a timed alert, the alert dialog will scroll, and might automatically become a modal alert.

The following alert types are defined:

  • ALARM—. Alerts the user to an event for which the user has previously requested to be notified. For instance, “You are out of time!”

  • CONFIRMATION—. Confirms an action. For example, “Are you sure you want to quit this game?”

  • ERROR—. Alerts the user to an erroneous operation. For example, “No Network Connection Detected.”

  • INFO—. Provides non-threatening information to the user. For example, “Congrats! You just passed level one.”

  • WARNING—. Warns the user of a potentially dangerous operation. For example: “Hitting the OK button will erase your saved game. Are you sure you want to do this?”

Alerts do not accept application-defined commands. As such, some of the command-relevant methods inherited from Screen will throw exceptions. Methods useful in the Alert class are the following:

  • getDefaultTimeout()—. Returns the default time for showing an alert. This is either a positive value, which indicates a time in milliseconds, or the special value FOREVER, which indicates that alerts are modal by default.

  • getTimeout()—. Gets the timeout for the current alert box. This is either a positive value, which indicates a time in milliseconds, or the special value FOREVER, which indicates that this alert is modal.

  • setTimeout(int time)—. Sets the timeout for the alert box. This must either be a positive time value in milliseconds, or the special value FOREVER.

  • getType()—. Returns the type of the alert.

  • setType(AlertType type)—. This method sets the type of the alert.

  • getString()—. Returns the text string used in the alert.

  • setString(String str)—. Sets the text string used in the alert.

  • getImage()—. Gets the image used in the alert.

  • setImage(Image img)—. Sets the image used in the alert.

Alerts are a great and easy way to add Help or About screens to your game.

Listing 9.5 shows how to implement a Help alert screen and an About alert screen.

Example 9.5. Implementing Help and About Screens

import javax.microedition.lcdui.*;

public class StartForm extends Form
    implements CommandListener
{
  private Game game;
  private Command playCommand;
  private Command helpCommand;
  private Command aboutCommand;
  private Command exitCommand;

  public StartForm(Game game)
  {
    super("Micro Racer");
    this.game = game;
    StringItem item = new StringItem(
        "Welcome to Micro Racer!", null);
    append(item);
    playCommand = new Command("Play", Command.SCREEN, 1);
    helpCommand = new Command("Help", Command.SCREEN, 2);
    aboutCommand = new Command("About",
        Command.SCREEN, 3);
    exitCommand = new Command("Exit", Command.SCREEN, 4);
        addCommand(playCommand);
    addCommand(helpCommand);
    addCommand(aboutCommand);
    addCommand(exitCommand);
    setCommandListener(this);
  }

  public void commandAction(Command c, Displayable s)
  {
    if (c.equals(playCommand)) {}
    else if (c.equals(helpCommand))
    {
      String str = "Under construction.";
      Alert alert = new Alert("Help", str, null,
           AlertType.INFO);
      alert.setTimeout(Alert.FOREVER);
      game.getDisplay().setCurrent(alert, this);
    }
    else if (c.equals(aboutCommand))
    {
      StringBuffer buf = new StringBuffer("");
      buf.append("Developed by David Fox");
      buf.append("and Roman Verhovsek.
");
      Alert alert = new Alert("About", buf.toString(),
           null, AlertType.INFO);
      alert.setTimeout(Alert.FOREVER);
      game.getDisplay().setCurrent(alert, this);
    }
    else if (c.equals(exitCommand))
    {
      game.exit();
    }
  }
}

When putting an alert on the screen, the display's setCurrent() method is called with two parameters. The second parameter is the screen that should be shown after the alert is dismissed.

Splash Screens

A splash screen is an informational screen that introduces the game with specific logo and text. It is shown during a game's startup, and usually turns off after a period of time. You can use the Alert class to create such a screen, but oftentimes you will want more control and may want to show several images along with several text elements.

In these cases, the Canvas or Form classes can be used instead. A Canvas is the most flexible type of screen, but you must implement your own scrolling and component positioning. The Canvas class is discussed in much more detail in Chapter 14, “Low-Level Approach.”

An easier solution is the Form object, which is discussed in Chapter 13. For now, check out Listing 9.6 to see how a simple intro screen, shown in Figure 9.7, is created.

The splash splash screensscreens splashAlert classclassesAlertappletsAlert classMIDletsAlert classlistingsForm object splash screenscreen.

Figure 9.7. The splash screen.

Example 9.6. A Form Object Splash Screen

import java.util.*;
import javax.microedition.lcdui.*;

public class IntroForm extends Form
{
  private Game game;
  private Form form;

  public IntroForm(Game game, Form form)
  {
    super("");
    this.game = game;
    this.form = form;
    Image image = null;
    try
    {
      image = Image.createImage("/logo.png");
    }  catch (Exception ex) {}
    ImageItem item = new ImageItem(null, image,
        ImageItem.LAYOUT_CENTER, null);
    append(item);
    Task task = new Task();
    Thread thread = new Thread(task);
    thread.start();
  }

  public class Task implements Runnable
  {
    private final int DELAY = 5000;

    public void run()
    {
      try
      {
        Thread.sleep(DELAY);
      }  catch (Exception ex) {}
      game.getDisplay().setCurrent(form);
    }
  }
}

The IntroForm constructor takes two parameters: a reference to a MIDlet (so that we can access the current display object) and a reference to the form that must replace the current one. An invoked thread waits for five seconds, then makes the change to the new form.

An image is loaded using the static method Image.createImage() where the filename should start with a slash (/) to indicate that the image is in the same directory or JAR file as the MIDlet class.

To call up the intro dialog, your main MIDlet Game class would use code similar to the following:

public void startApp()
{
  display = Display.getDisplay(this);
  StartForm form = new StartForm(this);
  IntroForm introForm = new IntroForm(this, form);
  display.setCurrent(introForm);
}

Global Properties

Part of the challenge of writing a professional game is being sure it runs as smoothly as possible, no matter what the operating system, device, screen resolution or colors, or language.

You can accomplish a great deal by sniffing out a MIDlet's various application and system properties.

Getting Application Properties

The getAppProperty(String key) method within the MIDlet class provides the program with a mechanism to retrieve named properties from the application management software. These properties are retrieved from the combination of the application descriptor file (JAD) and the manifest (built within every JAR). For example, one could call the following methods on the Hello World program:

System.out.println("Vendor: " +
  getAppProperty("MIDlet-Vendor"));
 System.out.println("MIDlet: " +
  getAppProperty("MIDlet-Version"));

Doing so would produce the following output in the debug console:

Vendor: Sun Microsystems
MIDlet Version: 1.0

Getting System Properties

MIDP includes four valid system properties:

  • microedition.profiles—. Returns the available profile (for example, MIDP-1.0)

  • microedition.locale—. Returns the current locale of the device (for example, en-US for United States English).

  • microedition.platform—. Returns the current phone being used. For example, Motorola i85s.

  • microedition.encoding—. Returns the type of String encoding this phone uses. Every CLDC implementation supports the ISO8859_1 (Latin 1) encoding. But Japanese phones, for example, will support the SJIS (Shift-JIS) encoding.

The values of these properties can be retrieved using the static method getProperty(String key) in the System class. This method gets the system property indicated by the specified key.

The microedition.locale property is very important for games and other apps that want to achieve international support. The locale is represented by two values. The first one is a two-letter code defined in the ISO-639 standard, and the second one is a two-letter code defined by ISO-3166, separated by a hyphen.

Creating a Global Cache Class

Let's begin writing our first game class. Most games, not to mention other MIDP applications, will want a nice place to store global variables and other values that might need to be accessed throughout. To accomplish this, we will build a Cache class.

One important global value is the language that the player speaks. Listing 9.7 shows a simple Cache class that can handle English and Slovakian.

Example 9.7. The Cache Class

public class Cache
{
  public static final int ENGLISH = 0;
  public static final int SLOVENE = 1;

  private int language;

  private Cache() {}

  static
  {
    String locale =
        System.getProperty("microedition.locale");
    if (locale == null)
      language = ENGLISH; // Default value
    else
      if (locale.startsWith("si")
        language = SLOVENE;
      else
        language = ENGLISH; // Default
  }

  public static int getLanguage()
  {
    return language;
  }
}

Note that the Cache class' constructor is private. Because of this, the class can't be instantiated; all methods are going to be static.

Summary

Hopefully, this chapter gives you an idea of how simple it is to get up and running using MIDP.

And this is just the beginning. We've already accomplished quite a bit: Our game has an intro screen, a main user interface menu, a help screen, and the ability to be readable in both Eastern Europe and the United States.

Throughout the next few chapters, we will be adding more to our racing game, creating a more complex game interface, graphics, animations, sprites, sounds, and more—much, much more!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.24.180