MIDP Basics

   

In this section, we briefly review the building of a MIDP application. For more information, see Jonathan Knudsen, Wireless Java: Developing with J2ME, Second Edition, Apress 2003.

Canvases and Forms

MIDP supports a graphic library that is similar to the AWT from the prehistoric time before Swing. That library is even simpler than AWT, and it is intended for small screens and numeric keypads.

A MIDP application extends the MIDlet class and minimally extends the three methods startApp, pauseApp, and destroyApp.

The user interface is composed of displayables, each of which fills the screen of the device. The most common displayables are the Canvas and Form classes. A canvas is used for painting of a full-size drawing (such as a theater seating chart or a game board). To create a drawing, subclass Canvas and override the paint method:

 

 public MyCanvas extends Canvas {    public void paint(Graphics g) {       g.drawLine(x1, y1, x2, y2);       ...    }    ... } 

A form contains a vertically arranged sequence of Item objects. Items are user interface components such as TextField and ChoiceGroup. Figure 11-2 shows a typical form.

Figure 11-2. A MIDP Form

graphics/11fig02.jpg


To define a form, simply construct a form object and append items.

 

 Form myForm = new Form("Search Flight"); TextField text = new TextField("Airport", "JFK", 3,    TextField.ANY); ChoiceGroup choices = new ChoiceGroup("Time", Choice.EXCLUSIVE); choices.append("am", null /* no image */); choices.append("pm", null); myForm.append(text); myForm.append(choices); 

You switch to a particular displayable by calling the setCurrent method of the Display class:

 

 public class MyMIDlet extends MIDlet {    public void startApp() {       ...       Display display = Display.getDisplay(this);       display.setCurrent(myForm);    }    ... } 

Commands and Keys

To switch between displayables and to initiate network activity, you define commands. A command has a name, a semantic hint that describes the nature of the command (such as OK, BACK, or EXIT), and a priority. The MIDP environment binds the command to a key or a voice action. Most cell phones have two "soft keys" below the display; these can be mapped to arbitrary commands (see Figure 11-3). If a screen has many commands, the MIDP environment constructs a menu and programs a key to pop up the menu. The priority value gives a hint to the environment whether a command should be bound to an easily accessible key or whether it can be buried inside a menu.

Figure 11-3. The Soft Keys of a Cell Phone

graphics/11fig03.jpg


NOTE

graphics/note_icon.gif

The MIDP environment is in charge of binding commands to keys or menus. Using a high priority value does not guarantee that a command is bound to a key.


Each displayable needs to specify a CommandListener. When the user executes the command, the commandAction method of the listener is executed. As with Swing applications, you can specify a separate listener for each command, or you can provide a single listener that dispatches all commands. For simplicity, we do the latter in our sample application.

 

 public class MyMIDlet extends MIDlet implements CommandListener {    private Command nextCommand;    private Command exitCommand;    ...    public void startApp() {       nextCommand = new Command("Next", Command.OK, 0);       exitCommand = new Command("Exit", Command.EXIT, 1);       myscreen.addCommand(nextCommand);       myscreen.setCommandListener(this);       ...    }    public void commandAction(Command c, Displayable d) {       if (c == nextCommand) doNext();       else if (c == exitCommand) notifyDestroyed();       else ...    }    private void doNext() { ... }    ... } 

In a canvas, you can listen to arbitrary keystrokes. However, not all devices have dedicated cursor keys, so it is best to let the MIDP environment map keys to game actions such as LEFT or FIRE.

 

 public class MyCanvas extends Canvas {    ...    public void keyPressed(int keyCode) {       int action = getGameAction(keyCode);       if (action == LEFT) ...       else ...    } } 

Networking

MIDP contains an HttpConnection class that is similar to its J2SE counterpart. This class manages the details of the HTTP protocol, such as request and response headers. Follow these steps to get information from a web server.

First, you obtain an HttpConnection object:

 

 HttpConnection conn = (HttpConnection) Connector.open(url); 

Next, set the request headers:

 

 conn.setRequestMethod(HttpConnection.POST); conn.setRequestProperty("User-Agent",    "Profile/MIDP-2.0 Configuration/CLDC-1.0"); conn.setRequestProperty("Content-Type",    "application/x-www-form-urlencoded"); 

Now get the output stream of the connection and send your data to the stream. If you issue a POST command, you need to send URL-encoded name/value pairs. If you issue a GET command, you need not send any data.

CAUTION

graphics/caution_icon.gif

If you send POST data to a web server, remember to set the content type to application/x-www-form-urlencoded.


Here we read the POST data from a hash table. Unfortunately, MIDP has no built-in method for URL encoding, so we had to write our own. You can find the code in Listing 11-19 at the end of this chapter.

 

 Hashtable request = ...; OutputStream out = conn.openOutputStream(); Enumeration keys = request.keys(); while (keys.hasMoreElements()) {    String key = (String) keys.nextElement();    String value = (String) request.get(key);    urlEncode(key, out);    out.write('=');    urlEncode(value, out);   if (keys.hasMoreElements()) out.write('&'); } 

Getting the response code automatically closes the output stream.

 

 int rc = conn.getResponseCode(); if (rc != HttpConnection.HTTP_OK)    throw new IOException("HTTP response code: " + rc); 

You can now read the response headers and the server reply.

 

 String cookie = conn.getHeaderField("Set-cookie"); int length = conn.getLength(); InputStream in = conn.openInputStream(); byte[] data = new byte[length]; in.read(data, 0, length); 

If the server does not report the content length, you will need to manually read until EOF see the code in Listing 11-1 on page 520.

Close the connection when you are done.

 

 conn.close(); 

The principal challenge with MIDP networking is to analyze the response data. If the server sends HTML or XML, the client needs to parse the response. The current version of MIDP has no support for XML. We examine this issue on page 515.

Multithreading

When a MIDP application makes a network connection, it needs to use a separate thread. Particularly on a cell phone, network connections can be slow and flaky. Moreover, you cannot freeze the user-interface thread, since the UI may pop up a permission dialog when the network connection is about to be initiated (see Figure 11-4).

Figure 11-4. Network Permission Dialog

graphics/11fig04.jpg


It would be nice if the MIDP library had explicit support for this issue, but unfortunately you need to implement the threading yourself. On a resource-constrained virtual machine, thread creation is expensive, so you want to create one thread for all your connections.

Here is the outline of the threading code:

 

 public class MyMIDlet extends MIDlet {    public void startApp() {       worker = new ConnectionWorker();       workerThread = new Thread(worker);       workerThread.start();       waitForm = new Form("Waiting...");       ...    }    ...    public void connect(String url, Hashtable request) {       display.setCurrent(waitForm);       worker.connect(url, request);    }    public void connectionCompleted(data[] response) {       // analyze response       // switch to the next screen    }    ...    private class ConnectionWorker implements Runnable {       private String url;       private Hashtable request;       private byte[] data;       private boolean busy;       public synchronized void run() {          try {             for (;;) {                while (!busy) wait();                try { data = post(); }                catch (IOException ex) { ... }                busy = false;                connectionCompleted(data);             }          }          catch (InterruptedException ex) {}       }       public synchronized void connect(String url, Hashtable request) {          this.url = url;          this.request = request;          busy = true;          notify();       }       private byte[] post(String url, Hashtable request) { ... }    } } 

The user interface thread calls the connect method, which notifies the worker thread that another connection job is available. As long as there is no possibility that the user interface issues multiple connection commands at the same time, this simple synchronization scheme suffices.

In our sample application, we avoid all the nasty issues of synchronization and cancellation by switching to a wait screen whenever the network connection is in progress. The run method calls the connectionCompleted method of the midlet after the data has been read from the network connection. (We made the connection worker into an inner class to simplify this callback. Note that the callback runs on the worker thread. It should only configure and display the next screen.)

For a more sophisticated implementation, with an animated wait screen and an option to cancel the connection, see the excellent article http://developers.sun.com/techtopics/mobility/midp/articles/threading.

The MIDP Emulator

Sun Microsystems makes available a convenient toolkit for testing wireless applications (see Figure 11-5). The toolkit includes an environment for compiling and packaging wireless applications, as well as emulators for cell phones and other handheld devices. You can download the wireless toolkit from http://java.sun.com/products/j2mewtoolkit/.

Figure 11-5. Wireless Toolkit

graphics/11fig05.jpg


Installing and using the toolkit is straightforward. A tutorial is available at http://developers.sun.com/techtopics/mobility/midp/articles/wtoolkit/.



core JavaServer Faces
Core JavaServer Faces
ISBN: 0131463055
EAN: 2147483647
Year: 2003
Pages: 121

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net