HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

A Beginner's Guide To Writing Applications For The MID Profile, by Jason Briggs

The first thing you're likely to see, upon sitting down to learn a new language, is the ubiquitous ""Hello..."" application. My father bought me the TRS-80 Basic for Kids book when I was 8-years old, and I'm pretty sure that the first example was either ""Hello World"" or ""Hello, my name is....""

As the years progressed and I acquired different computers (BBC, Commodore, Macintosh, PC, etc.) and learned different languages (Assembler, Cobol, Pascal, Modula-2, C, C++), it's always been ""Hello World"" in some form that I've ended up writing for my first exercise with the language.

If you're sitting down to Java for the very first time, I suggest you initially start with the excellent Java Tutorial ( http://java.sun.com/docs/books/tutorial/), and then come back to this article. However, for the rest of us - and in the very best tradition of Hello World applets, applications, servlets, and EJBs - may I present the Hello JDJ MIDlet... at the very least, so I won't be lynched by the ""Secret Society for Ensuring that the First Thing Anyone Learns Is ""Hello World.""

In the beginning there was...
If you haven't done so already, download and install the latest version of the Java Development Kit (1.3.0 or higher) and also download and install the J2ME Wireless Toolkit. You can currently find the toolkit at http://java.sun.com/products/j2mewtoolkit/download.html.

Note that the MIDP reference implementation is also usable, but the WTK has customizable skins (see Definitions), so it's a bit more fun. If you intend to use Sun's Forte Integrated Development Environment for your development efforts, then you can also install the WTK integrated with Forte. However, for the purposes of these examples, we'll work from the command prompt - and we'll also assume a couple of standard directories, namely:

c:\jdk1.3 - the root directory for the JDK
c:\j2mewtk - the root directory for the toolkit

And then there was code...
There's nothing truly unusual about writing a MIDlet (MID applications that run on the K virtual machine). There are a couple of new packages to import, a couple of new methods to implement, but apart from that there's nothing really frightening - if you've written applets and applications in the past.

So let's look at our first MIDlet, defined in a file called HelloJDJMIDlet.java (see Listing 1).

Looking at the important lines of the code, we see that lines 1 and 2 import the necessary classes for the MIDlet - the MIDlet super class itself, and all the classes in the javax.microedition.lcdui package (lcdui being LCD user interface).

Line 6 declares a display object, which is the controller for display and input devices for the system.

Line 7 declares a TextBox, which we will use to display a message to the user.

Line 10 declares and instantiates a Command object, which defines an action containing a label (""Exit""), a type (specifying what the command will be used for), and a priority (describing the importance of the command in comparison to other commands on the screen).

Lines 11-18 declare and instantiate a command listener (used to handle events) - this listener checks to see whether an event occurred on the command defined in line 10, and if so, exits the MIDlet.

Line 22 retrieves the single instance of the Display object for the MIDlet. (Note: there is only one instance of a Display per MIDlet, hence we call the getDisplay() method, passing this as the parameter.)

Line 23 instantiates the TextBox with a title (""Simple MIDlet""), text contents (""Hello JDJ!""), a maximum size (256) and input constraints (TextField.ANY). Input constraints are used to restrict the user's input - in this case, we're not restricting the input at all.

Line 26 is the beginning of one of the methods required by a MIDlet - startApp() is called when the MIDlet is made active.

Lines 27 and 28 add the command bye to the text object, and then set the command listener.

Line 30 sets the current displayable object of the display to be the TextBox.

Finally, lines 33 and 36 define the other two methods required by a MIDlet: pauseApp() is called - rather obviously - when the MIDlet is paused, and destroyApp(), when the MIDlet is required to release its resources and shut down.

One thing to note about this MIDlet is that unlike an applet, the MIDlet is not, itself, a displayable object; therefore, you would not necessarily want to define a paint() method in the MIDlet code as you might in an applet. An applet extends from java.awt.Panel (and, further up the chain, from java.awt.Component), which means it's a displayable component - in MIDP, objects that can be placed on the screen extend from the javax.microedition.lcdui.Displayable abstract class (whereas MIDlet extends from java.lang.Object).

Compiling the Code
If you're anything like me, when working from a text editor and command prompt (rather than using a development environment, which does everything for you), you end up creating batch files to automate processes - because we developers are a lazy lot. And why not?

In this case, I've created a working directory on my C drive (dev\midp) with two subdirectories below it called classes and tmpclasses. HelloJDJMIDlet.java is located in the midp directory.

c:\dev\midp
|
|------ classes
|
|------ tmpclasses

To compile the MIDlet, we use the Java compiler as we would with any other Java code:

c:\jdk1.3\bin\javac -g:none -d tmpclasses -bootclasspath
c:\j2mewtk\lib\midpapi.zip -classpath tmpclasses;classes
HelloJDJMIDlet.java

Where:

  • -g:none: Means we want to generate no debugging info
  • d: Specifies the output directory for our files
  • bootclasspath: Forces the compiler to use the midpapi.zip file instead of its default bootclasspath.
  • classpath: Defines where other supporting classes might be found
So in tmpclasses we should end up with two files: HelloJDJMIDlet.class and HelloJDJMIDlet$1.class (this is the result of compiling the CommandListener inner class, used for handling events - see lines 11-19 of Listing 1).

Preverification
Before running an application, all classes must be preverified. This prepares them for use in the KVM (K virtual machine). To preverify the files we have just created:

c:\j2mewtk\bin\preverify -classpath
c:\j2mewtk\lib\midpapi.zip -d
classes tmpclasses

We should now have preverified copies of both files in the classes directory.

Application Descriptor and Application Jar
Each suite of applications to be run in a MIDP-capable device will have a descriptor and a Jar file. The descriptor defines a number of parameters that describe the environment and individual MIDlets in the suite. The Jar file contains the classes, plus a manifest file with some extra information to a standard Java jar. If you don't know anything about Jar files and manifests, I recommend looking at the following tutorial: http://java.sun.com/docs/books/tutorial/jar/basics/index.html

The next example shows some of the information required for the descriptor we'll be using for our Hello test (note, the line numbers are not necessary in the actual file itself):

  1. MIDlet-Name: JDJ
  2. MIDlet-Vendor: Java Developers Journal
  3. MIDlet-Version: 1.0.0
  4. MicroEdition-Configuration: CLDC-1.0
  5. MicroEdition-Profile: MIDP-1.0
  6. MIDlet-1: HelloJDJMIDlet,, HelloJDJMIDlet
  7. MIDlet-Jar-Size: 1770
  8. MIDlet-Jar-URL: jdj.jar

Line 1 names the suite.
Line 2 names the vendor of the suite.
Line 3 is the version of the suite.
Line 4 defines the Configuration that is required by this suite (in this case, the Connected, limited Device Configuration 1.0)
Line 5 defines the Profile required by the suite (Mobile Information Device Profile 1.0)
Line 6 describes the MIDlet included in this suite. The information required is the MIDlet name, the name of a PNG image in the jar to be used as an icon for this MIDlet, and finally the name of the class. If there was more than one MIDlet, there would be other lines beginning MIDlet-2, MIDlet-3, MIDlet-4, and so on.

There are two items missing from the descriptor. These are MIDlet-Jar-Size and MIDlet-Jar-URL. I include them separately (below), because the above information is used in both the descriptor and the jar manifest file.

The steps to package the application so far are:

1. Create a manifest file (for example: manifest.mf) with the above information (minus the line numbers) in the classes directory
2. Jar the class files and include the contents of the manifest file. For example:

cd classes
C:\jdk1.3\bin\jar -cfm jdj.jar manifest.mf HelloJDJ*.class

Where:

  • jdj.jar: The name of the jar file we are creating
  • manifest.mf: The manifest file whose contents we want to include
  • HelloJDJ*.class: Grabs Hello JDJMIDlet.class and Hello JDJMIDlet$1.class
3. Create an application descriptor (jdj.jad) - duplicating the manifest file and including the information from lines 7 and 8.

Line 7 is the size of the Jar file, in bytes.
Line 8 is a URL from which the Jar can be loaded. (As we are delivering this application locally, I've just entered the URL as jdj.jar.)

Running the MIDlet
At the end of this process, we should have two files:

  1. An application descriptor - jdj.jad
  2. An application jar - jdj.jar - containing the class files and a manifest
We are now ready to test the application. There are a couple of ways to run the emulator, but as we're following a command-line driven approach, we will continue using this method:

c:\jdk1.3\bin\java -cp c:\j2mewtk\lib\kenv.zip -
Dkvem.home=c:\j2mewtk
com.sun.kvem.midp.Main
DefaultColorPhone -descriptor
jdj.jad

Where:

  • cp: Ensures the classpath points to the kenv.zip file
  • Dkvem.home: The only required parameter for the emulator, the home directory of the toolkit
  • DefaultColorPhone: The device for the emulator to use (De- faultGrayPhone, DefaultColorPhone, MinimumPhone, or Pager)
  • Descriptor: The name of the application descriptor to use
The emulator should display a list of applications in the Jar file (there is only one in this case), and when you select the application, you should see something similar to Figure 1.

Figure 1
Figure  1:

Of course, just to make life a bit more difficult, Sun has just released an ""early access"" version (1.0.2) of the toolkit, which works slightly differently from the previous release. So if you've downloaded this version, use the following command to run the app:

c:\j2mewtk\bin\emulator -
Xdevice:DefaultColorPhone -
Xdescriptor:jdj.jad

Where:

  • Xdevice: Specifies the device to use
  • Xdescriptor: The descriptor of the application to run
A More Advanced Example - Graphics
Graphics operations in a MIDlet are similar to those available in Java Standard Edition, such as drawImage(), drawRect(), drawArc(), and fillRect(), fillArc(). There are, however, a couple of notable exceptions. Methods such as draw3DRect(), drawOval() and, interestingly, drawPolygon() are missing from the graphics class. While drawing 3D rectangles and ovals can be quite easily accomplished by using either a combination of normal rectangles and/or lines, and with the latter, a call to drawArc() - the omission of polygons is a little more difficult to overcome.

Look at Figure 2 for an example of the problems caused by this lack of polygon drawing capability.

Figure 2
Figure  2:

The left car is constructed from two rectangles for the body and two arcs for the wheels.

The right car is constructed from two rectangles and three triangles for the body, and again two arcs for the wheels.

Two things should be plainly obvious from this diagram:

  1. The car on the right is slightly more realistic than the car on the left.
  2. My artistic abilities are severely limited.
So, for our first graphics example in MIDP we will attempt to provide the missing polygon routine. To do this we will need to create a displayable component that we can paint on. We'll call our displayable component PolygonScreen and it will extend from the Canvas class in the javax.microedition.lcdui package:

public class PolygonScreen extends
javax.microedition.lcdui.Canvas {

...

}

In addition, we will need to provide a paint() method. This works in exactly the same fashion as it would in an applet: the paint method takes a Graphics object (one slight difference here: the class is javax.microedition.lcdui.Graphics, and not java.awt.Graphics), for which you can then invoke any of the various draw methods (see Listing 2).

Lines 2-4 just check to make sure we actually want to paint at the moment.

Line 6 sets the current drawing color to a random color using a function called randRange(), listed below.

Lines 8-13 set each value in an integer array to a random number to create a list of coordinates for a triangle - in the form (x,y),(x,y),(x,y).

Finally, line 15 calls drawPoly() with the coordinates array, the number of coordinates (six because it's a triangle) and the Graphics object.

The supporting methods for the paint method are shown in Listing 3.

The method randRange() returns a random number not greater than n. The ""guts"" of the drawPoly() method are discussed below.

Drawing a polygon
Way back in 1994, Chris Egerter (www.egerter.com) wrote a tutorial on drawing filled polygons, using C code for his example. Hunting through - literally - a pile of source code I've built up over the years, I found a copy of this source and have ported it to Java with a few minor changes to get things working. The drawPoly() routine is used for painting convex polygons, and not for concave polygons (see Definitions). The process - called scan conversion - calculates the left and right edges for the polygon shape based on the current Y coordinate (placing the results into two integer arrays), and then draws a horizontal line between these two points with the following method:

g.drawLine(startx[y], y, endx[y], y);

See Figure 3 for a simple illustration of how this process works.

Figure 3
Figure  1:

The other addition to the application is PolygonEngine.java:

public class PolygonEngine implements Runnable {

...

}

This adds simple thread handling so we can provide animation in our MIDlet. PolygonEngine is constructed by passing the PolygonScreen component as a parameter. The run() method repeatedly sleeps an animation thread for a few milliseconds before calling the repaint() method on the screen component (see Listing 4).

The final result is an application that continually paints colored triangles on the screen until the user decides to exit (see Figure 4) - completely useless, of course, apart from situations where you might want a visual demonstration of the graphics performance of a particular device.

Figure 4
Figure  4:

Summary
That's a basic introduction to writing applications for the MID profile. We've discussed how to write a simple MIDlet, compiling and packaging, and looked at some of the graphics operations available. Next time we'll take a look at the packages we have not covered yet - persistence and IO - and look at how we might interact with a server in our apps.

Definitions

  • Polygon: A closed figure made by joining line segments, where each line segment only intersects two others.
  • Convex polygon: If, for any two points that lie within a polygon, a line segment connecting them is also inside the polygon, then it is convex.
  • Concave polygon: Any polygon that is not convex.
  • Skin: A customizable user interface for an application.

Author Bio
Jason Briggs is a Java developer. He is currently thinking about designing a Java-enabled, hand-held device that will sell in the billions (of course) - and be used to brainwash the world's population - allowing him to complete his 10-year plan for global domination. [email protected]

	



Listing 1

1.  import javax.microedition.midlet.MIDlet;
2.  import javax.microedition.lcdui.*;
3.
4.  public class HelloJDJMIDlet extends MIDlet {
5.
6.    private Display display;
7.    private TextBox text;
8.
9.    // provide a command to exit the app
10.   private Command bye = new Command("Exit", Command.SCREEN, 12);
11.   private CommandListener commandListener = new
                                        CommandListener() {
12.     public void commandAction(Command c, Displayable s) {
13.       if (c == bye) {
14.         destroyApp(true);
15.         notifyDestroyed();
16.         return;
17.       }
18.     }
19.   };
20.
21.   public HelloJDJMIDlet() {
22.     display = Display.getDisplay(this);
23.     text    = new TextBox("Simple MIDlet", "Hello JDJ!", 256, 0);
24.   }
25.
26.   public void startApp() {
27.     text.addCommand(bye);
28.     text.setCommandListener(commandListener);
29.
30.     display.setCurrent(text);
31.   }
32.
33.   public void pauseApp() {
34.   }
35.
36.   public void destroyApp(boolean unconditional) {
37.   }
38. }




Listing 2

1.  public void paint(Graphics g) {
2.    if (!running) {
3.      return;
4.    }
5.
6.    g.setColor(randRange(255), randRange(255), randRange(255));
7.
8.    triangle[0] = randRange(w);
9.    triangle[1] = randRange(h);
10.   triangle[2] = randRange(w);
11.   triangle[3] = randRange(h);
12.   triangle[4] = randRange(w);
13.   triangle[5] = randRange(h);
14.
15.   drawPoly(triangle,6,g);
16.
17. }



 Listing 3

1.    private final int randRange(int n) {
2.      int r = random.nextInt() % n;
3.      if (r < 0) {
4.        r += n;
5.      }
6.      return r;
7.    }
8.
9.
10.   private final void drawPoly(int coords[], int numcoords, Graphics g) {
11.
12.   ...
13.
14.   }



 Listing 4

1.  public void run() {
2.    int n = 0;
3.
4.    stopped = false;
5.
6.    while (!stopped) {
7.      now = System.currentTimeMillis();
8.      if (nextTime < now + 15)
9.        nextTime = now + 15;
10.     try {
11.       runner.sleep(nextTime - now);
12.     }
13.     catch(Exception e){}
14.     nextTime = System.currentTimeMillis() + 50;
15.
16.     screen.repaint();
17.
18.   }
19. }


 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.