by Jonathan Knudsen
May 2002
Download:
[MIDlet suite JAD]
[MIDlet suite JAR]
[Source code ZIP]
API documentation
Legal notices
The PeekAndPick application allows you to browse news headlines and have
story links emailed to your desktop. This article describes the
client application from a developer's perspective. It covers relevant background
information, provides a high-level view of the application, and describes
components that you can use in your own applications.
PeekAndPick is an end-to-end Java application, consisting of both a MIDlet
client and a simple servlet. This article presents the client side of
PeekAndPick and discusses the protocol used between the client and server.
You may wish to
download the source code
so you can examine the files as you read the article.
I'll also assume you are already familiar with PeekAndPick from a user's
perspective; if you need to find out more, read the
User's Guide.
The PeekAndPick source code is available as a
zipped archive. There are two ways to
build the application. You can use the J2ME Wireless Toolkit (J2MEWTK) graphic
interface (KToolbar)
to build PeekAndPick, or you can use Ant on the command line. Both methods rely
on tools in the J2MEWTK, which in turn relies on an installation of
Java 2,
Standard Edition (J2SE) SDK. See Wireless
Development Tutorial Part I for details about installing the J2MEWTK.
Building PeekAndPick
To build PeekAndPick using KToolbar, follow these steps:
-
Unzip the source archive into the apps directory of the J2MEWTK
installation. This will create a new project directory, PeekAndPick11,
and upack files into bin, build, lib, res, and
src subdirectories.
-
Run KToolbar.
-
Click on Open Project... and choose PeekAndPick11 from the list.
Click on Open Project.
-
Click on Build. The project should build without errors. You can now run
PeekAndPick by clicking on Run.
To build PeekAndPick using Ant, follow these steps:
-
Download and install Ant.
-
Unzip the PeekAndPick source archive in the directory of your choice.
-
Edit the build/build.xml script. You may need to adjust the value of the
midp property to point to your J2MEWTK installation.
-
Open a command window and change to the build directory of
the source code. Type
ant. The project should build without errors.
-
To run the project in the emulator, type
ant run.
If you wish to
use the JAX obfuscator, you will need to download and install it separately.
Make sure the jax property in build.xml points to the
JAX classes and change the depends attribute of the preverify
target from obfuscate_null to obfuscate_jax.
Similarly, if you wish to use the Retroguard obfuscator, make sure the
retroguard and midp_lib_empty properties are
properly defined. Change the depends attribute of the preverify
target from obfuscate_null to obfuscate_retroguard. (For more
information on Retroguard, see
Obfuscating a J2ME MIDlet suite.)
The build.xml script provides several other targets that may interest you:
-
The clean target removes subdirectories of the build directory
that are created during the build process.
-
The reallyclean target does what clean does and also removes the
compiled project and other files.
-
The docs target uses
javadoc to generate API documentation
for the PeekAndPick classes. You can also browse this documentation
online.
RSS Crash Course
To understand how PeekAndPick works, you'll need to understand something about
RSS feeds. RSS stands for Rich Site Summary; it's an XML
application. An RSS file (a feed) contains a description of the
contents of a Web site. The site you are reading has an RSS feed located at
http://wireless.java.sun.com/xml/wd.rss. (Depending on your browser and
configuration, you may or may not be able to view this file easily.) This site's
RSS feed lists the most recently added items on the site. For each item, the RSS
feed contains a title, a URL, and a short description.
The power of this simple XML file is that any client application that recognizes
RSS can now read a summary of this site. RSS clients are available for
many different platforms. Such clients can easily pull news summaries from
various feeds around the Internet and present them in a variety of ways to the
user.
The Meerkat
service, hosted by the O'Reilly Network, takes the idea of RSS one
step further. Meerkat aggregates many different RSS feeds and can output the
aggregated items as RSS again. Meerkat has a
documented API which makes it an extremely powerful
and flexible tool for extending other applications. You can ask for specialized
results, for example
retrieval of items that have been added in the
last ten days that come from feeds
that pertain to wireless technology. You can perform keyword searches. You can
retrieve results in a variety of formats, not just RSS.
RSS is well documented and widely supported. For more information, try these
resources:
PeekAndPick Architecture
PeekAndPick is an RSS client application written in Java for the Mobile
Information Device Profile (MIDP). Its architecture looks like this:
PeekAndPick architecture
|
PeekAndPick makes two different kinds of network connections. First, it
connects to RSS feeds to download article information and display it to the
user. Second, PeekAndPick connects to the PeekAndPick server to send email.
PeekAndPick can, in theory, connect to any RSS feed on the Internet. The current
version is limited to several feeds that have been hardcoded in the application.
PeekAndPick downloads and parses a feed and displays a list of the item
titles. The user can browse through the titles, view details for an item, and
check off items that look interesting.
After the user has finished checking items, the links for those items can be
placed in an email message and sent to the user. The PeekAndPick
client application
makes an HTTP connection to the PeekAndPick servlet running on a Web server.
The servlet connects to an
email server and sends the message.
Internal Architecture
The PeekAndPick client consists of about 20 classes and interfaces:
PeekAndPick UML class diagram excerpt
(Click for a full size image.)
|
The application's center is PeekAndPick, which is a
MIDlet. PeekAndPick controls all the other classes
in the application. It also responds to the user's input from several different
screens and figures out what to do next.
PeekAndPick calls on classes and interfaces in four packages. The
contents of these packages are described below; later I'll go into more
detail, especially about code that you might use in your own applications.
-
The default package contains classes that are specific to the PeekAndPick
application. Instances of
Feed represent the
RSS feeds used by PeekAndPick. FeedStore provides persistent
storage for Feeds, and Parameter also supports
Feed.
-
The
rss package is dedicated to parsing RSS documents.
Parser is an abstract class that defines basic behavior. Concrete
subclasses are expected to be able to parse an RSS document
represented by an InputStream. While they parse, they should spit
out events to registered ParserListeners. One concrete subclass,
kXML12Parser, is provided. It uses the kXML 1.2 parser.
-
The
util package contains a generalized Worker class
that is used for threading support. PeekAndPick's performs its network access
in a separate
thread to avoid locking up the user interface. The Worker
class maintains a queue of tasks that will be run in a single separate worker
thread. The tasks are represented by instances of the WorkerTask
interface, which contains only a run() method, just as
Runnable does. When tasks are complete, or when tasks
throw exceptions,
a registered WorkerListener is notified.
The util package also contains a generalized
Preferences class and an associated GUI; PeekAndPick uses
Preferences to store the user's email address and the
address of the PeekAndPick server.
-
Finally, the
display package contains generalized user interface
components. ListCanvas, ItemCanvas, and
DisplayItem handle display of the list of titles as well as
details for a particular article. SplashScreen displays
the starting image for the application, and WaitDisplayable shows
an animated wait screen while PeekAndPick makes network connections.
Using a Worker Thread
util.Worker provides a general approach to the problem of running
tasks in a separate thread. Worker maintains a queue of
WorkerTasks, which are run in the order they are added to the
queue. When one task finishes, the next is started. If the queue is empty,
Worker patiently waits for a new task to be added.
An application is notified about task completion or exceptions if it
implements the WorkerListener interface.
PeekAndPick uses Worker to execute two tasks. The first,
ParseTask, retrieves and parses RSS files. The
second, MailTask, connects to the PeekAndPick server to
request that it send email.
Using the Worker class is straightforward. PeekAndPick
begins by creating a Worker and registering itself as the listener
object. This code is in PeekAndPick's initialize()
method:
// mWorker is a member variable.
mWorker = new Worker();
mWorker.setWorkerListener(this);
It's easy to use the worker thread in an application of your own; just create
an instance of WorkerTask and
pass it to the Worker. For example, the following code from
PeekAndPick's commandAction() shows how to
create a task for parsing an RSS feed:
// mParser is a member variable, a Parser instance.
// feed contains the currently selected Feed.
ParseTask task = new ParseTask(mParser, feed, null);
mWorker.queue(task);
Creating a task isn't even that hard. All you do is implement the
WorkerTask interface and put the code for the task inside the
run() method. See ParseTask and MailTask
for examples.
Why doesn't Worker just use java.lang.Runnable instead
of the new WorkerTask interface? Worker needs to
catch exceptions thrown by tasks. The run() method of
Runnable throws no exceptions, so it doesn't provide the
functionality that Worker needs.
You can read more about the general problem of running network activity in its
own thread in Networking, User Experience,
and Threads.
Persistent Preferences
One common problem faced by network client MIDlets is storing user preferences.
PeekAndPick's Preferences class provides a generalized class for
maintaining and storing user preferences.
User preferences are stored as key and value pairs, where each key and each
value is
a String. This is a lot like the java.util.Properties
class in J2SE. You can add or replace a value using put(),
or pass a
key to get() to retrieve a value. Preferences also
includes a putIfNull() method that you can use to initialize
missing values. This excerpt from PeekAndPick's
initialize() method shows how the Preferences object
is created. If the preferences can't be loaded
(if the application is being run for the first time), the values are initialized
from system properties.
// mPreferences is a member variable.
mPreferences = new Preferences("PeekAndPick.preferences");
String email = getAppProperty("PeekAndPick.preferences.email");
String server = getAppProperty("PeekAndPick.server.URL");
mPreferences.putIfNull("Email address", email);
mPreferences.putIfNull("PeekAndPick Server", server);
|
Preferences store themselves using MIDP's RecordStore. When you
create a Preferences object you pass the name of a record store
to the
constructor. Preferences attempts to load itself from that
record store. To save a Preferences object after making changes,
call the save() method.
Editing Preferences
PreferencesEditor is a user interface component that provides
controls to allow users to modify the values of a Preferences
object. It is a subclass of javax.microedition.lcdui.Form. To
create a PreferencesEditor, pass a Preferences object
and a String array of non-editable keys to the constructor. The
PreferencesEditor will not display user interface controls for
non-editable values.
PeekAndPick maintains an email address and a server URL in its
Preferences object. The email address (key is "Email address")
is entered by the user, but the server URL (key is "PeekAndPick Server")
should not be editable and should not even be shown to the user.
PeekAndPick's getPreferencesEditor() method
creates the
editor this way:
// mPreferences is a member variable.
String[] noShows = { "PeekAndPick Server" };
mPreferencesEditor = new PreferencesEditor(mPreferences, noShows);
This editor form is shown when you choose the Prefs command.
PreferencesEditor creates one TextField for each
editable value in the Preferences object. For PeekAndPick, the
"Email address" is the only editable value, so the
PreferencesEditor contains a single TextField:
PreferencesEditor with a single field
|
You can reset an existing PreferencesEditor to the new values of a
Preferences object by calling its initialize() method.
To retrieve the edited values from the form, call the extract()
method. This method returns a Hashtable with keys and values for
each of the fields in the form. Note that the returned Hashtable
does not contain any of the non-editable key and value pairs. You can take the
values returned by extract() and pass them to the
set() method in Preferences, which adds to or
overwrites the existing values.
Pluggable Parsing
Parsing RSS is one of the simpler tasks in PeekAndPick. I designed the parsing
classes so it would be easy to swap in different XML parsers with minimal
changes to the code in the rest of the application. In PeekAndPick, the job of
parsing XML is implemented by a concrete subclass of the abstract
rss.Parser.
Parser is relatively simple. It contains the plumbing for
maintaining a list of listeners, and protected methods for firing
various events to those listeners. Its one abstract method is
parse(). This method is expected to parse the given RSS byte stream
and notify the listeners appropriately.
rss.kXML12Parser is a concrete subclass that uses the kXML 1.2
parser. It's relatively simple; it just walks through the document, searching
for item tags and pulling out the information it needs.
Fortunately for code maintenance, PeekAndPick doesn't know much
about
kXML12Parser. The only place the name even comes up is at creation
time, in PeekAndPick's initialize() method.
PeekAndPick creates the parser and adds itself as an event
listener.
// mParser is a member variable of type rss.Parser.
mParser = new kXML12Parser();
mParser.addParserListener(this);
Thereafter, PeekAndPick treats the object as a Parser
instance, which means it would be easy to drop in a different implementation.
Suppose kXML 2.0 is released. I could write a kXML20Parser class that uses
the new version
and change the initialization in PeekAndPick to use the new class.
Everything else would stay the same.
Instead of creating the parser subclass explicitly, I could even use
Class.forName() and use a system property to specify the name of
the implementation class, but I feel that going this far would be overkill.
For more information about using XML parsers in MIDP and the specific task of
parsing RSS, read Parsing XML in J2ME.
Lists and Details
The class that displays PeekAndPick's list of article titles is
display.ListCanvas. It is not specific to PeekAndPick or RSS. It
can display any list of items, where each item consists of a name, a
description, and another piece of text that is not shown to the user. In
addition, ListCanvas allows the user to check or uncheck each item
in the list.
ListCanvas in action
|
You can add items to ListCanvas by calling addItem().
Item information can be retrieved using the getShortText(),
getLongText(), and getExtra() methods, each of which
takes an index to the item. Alternately, you can retrieve a complete item with
getItem(), which returns an instance of DisplayItem.
ListCanvas is a subclass of Canvas and handles key
events. Specifically, a press on the right-arrow key of the device will cause
ListCanvas to display details for a single item using
ItemCanvas. You can also request this behavior using the
details() method. Similarly, ItemCanvas will respond
to a left-arrow key press by returning to the original ListCanvas.
The setMarkingAllowed() method in ListCanvas controls
whether or not marking (checking) will be supported. If it is,
ListCanvas will toggle the check mark for an item each time the
select key is pressed. You can find out whether an item is checked by calling the
isMarked() method.
This class is similar, functionally, to the
MULTIPLE type of javax.microedition.lcdui.List.
I created ListCanvas to allow more sophisticated navigation without
relying on Commands exclusively. Note that, like List,
ListCanvas adjusts itself to the available screen size, so it looks
right on a mobile phone as well as a Palm OS device.
A Simple Splash Screen
The display.SplashScreen class is a simple implementation of a
splash screen that displays an image. To create it, pass the constructor
the name of the image
file, a Display object, and the next screen that should appear
after the splash screen goes away.
The splash screen dismisses itself after a hardcoded time-out (two seconds).
It will also dismiss itself in response to a key press or a pointer press.
Client-Server Protocol
You already understand how PeekAndPick parses RSS feeds. In this section I'll
describe how the PeekAndPick client MIDlet talks to the PeekAndPick server. The
purpose of this communication is to allow the MIDlet to request the server to
send email. The protocol
is very simple; the client MIDlet sends an HTTP POST request whose
body is of this form:
log line
destination line
message line 1
message line 2
...
message line n
|
The first line contains information that the servlet can write into the server
log. In PeekAndPick's current implementation this line is blank. The second line
is the destination email address, which is the address the user entered into the
preferences screen. The remainder of the request body is the message itself.
The MIDlet creates this message from the items that are
marked in the title list.
On the server side, the servlet simply parses out the information from the HTTP
POST request and uses the Java Mail API to create a message and send it.
Summary
In this article you learned about the design and implementation of the
PeekAndPick client MIDlet. You encountered many classes you can use in
your own applications. PeekAndPick is a useful application and a demonstration
of MIDP client
programming. It should give you a taste of how an end-to-end Java solution
works. Please feel free to use pieces of PeekAndPick in your own applications,
subject to the license.
About the Author: Jonathan Knudsen
[e-mail]
[home page]
is the author of several books,
including
Wireless Java (second edition),
The Unofficial Guide to LEGO MINDSTORMS Robots,
Learning Java (second edition), and
Java 2D Graphics.
Jonathan has written
extensively about Java and Lego robots,
including articles for JavaWorld, EXE, NZZ Folio,
and the O'Reilly Network.
Jonathan
holds a degree in mechanical engineering from Princeton University.
Back To Top
|