
Creating
Games using J2ME
By
David
Fox
Gamasutra
September
17, 2001
URL: http://www.gamasutra.com/features/20010917/fox_01.htm
With the advent
of Java 2 Micro Edition (J2ME) on mobile phones, it is now possible to create
mobile games that aren't all that crappy!
Now, don't get me wrong. Some creative folks <http://www.jamdat.com/html/games.html>
have devised truly interesting games using the Wireless Application Protocol
(WAP). But that's sort of like building a skyscraper out of Popsicle sticks-in
the end the simple text-pushing protocol just won't cut muster if you want
responsive, graphically rich games. Gladiator, one of the most popular WAP
games, is really nothing more than a rock-paper-scissors clone!
For several years now, phone manufacturers have had native hardware capable
of supporting decent games. Nokia's Snake game <http://www.nokia.com/snake/>
is probably the most notable example. But mobile phone developer's kits
are often proprietary. And downloading, installing, sharing, and porting
these games is an all-but impossible task.
J2ME Overview
The Java 2 Micro Edition (J2ME) is a true-to-its-word subset of the standard
Java libraries. J2ME consists of:
While
various J2ME profiles can run on anything from advanced
set-top boxes to tiny chips on smart credit cards, for
the sake of this article we will focus MIDlets-applets
in the CLDC configuration written to the MIDP profile.
Note that you can run MIDlets on your Palm as well. Check
out this page <http://developer.java.sun.com/developer/products/wireless/midp/articles-palm/convert/>,
which has full instructions on converting MIDlet packages
and deploying them on the Palm.
Games on Phones?
Mobile phones are a bold new platform for gaming. Today,
there are more than 600 million mobile-phone users worldwide.
Mobile phone users generally tend to be affluent, educated,
and they often have lots of time on their hands. In the
United States, for example, people spend 50-percent more
time commuting than any other country (Yankee Group).
This is the perfect time to pull out a mobile phone and
play some quick games.
In the near future, we will likely see micro devices become
even smaller and specialized. Phones the size of earplugs,
voice-activated assistants on wristwatches, and smart
chips on credit cards are all becoming a reality.
Unsurprisingly, games are keeping up and even helping
to lead this paradigm. While it may seem silly to try
to achieve a rich, meaningful immersion on a tiny 100x100
pixel screen, there's one thing mobile phone games give
you that even the best consoles can't provide: They're
always with you, and can be played anywhere you go. This
not only means that games can now be more convenient,
but wholly new types of games can be designed that take
advantage of new lifestyles.
The Joy of Java
Most every major mobile phone and handheld device manufacturer
immediately realized the potential of J2ME: If Java were
to be placed on the gadget, then hundreds of thousands
of developers would immediately be able to create applications
and add value. Furthermore, because it's Java, a program
written for one device would be able to run on another
device with little or no modifications. That certainly
makes more sense that trying to force developers to learn
a native language and API in order to create programs
for your phone.
And so, most every major mobile phone manufacturer joined
with Sun to create something called the CLDC: The Connected,
Limited Device Configuration, along with the MIDP: The
Mobile Information Device Profile. Mobile phone manufacturers
have definitely embraced Java in a way that not even PC
manufacturers and browser makers have. Java is clearly
the future platform of choice for mobile devices, and
an ideal platform for mobile games.
The Bad News
Programming games for handheld devices is a total pain.
The screen is miniscule160 by 160 on the Palm, and
much less on mobile phones. The memory is limitedthe
Palm only gives you 2 to 8 Meg, depending on the model.
You have little dynamic memory to play around withmost
mobile phones only give you 32K, the Palm has a 96K heap
limit. There's limited network connectivity, with a teeny,
tiny 9.6 kilobit per second bandwidth. And the processor
itself is often hundreds of times slower than your average
desktop.
Programming in a language like Java only adds a layer
onto this hard-to-digest cake. Sun's Kilobyte Virtual
Machine (KVM) gets its name because it takes up a few
kilobytes of space. But even those few bytes are wasteful.
The KVM also usurps a fair bit of memory. A native application
is the size and power it is, asking for nothing more.
In addition, Java classes have the added overhead of a
slow startup. While startup is going on, the KVM is going
through the class, allocating heap space and verifying
the bytecode.
Additionally, a Java programmer is restricted to the capabilities
of the virtual machine. Because Java must work on a wide
variety of devices, it is written for the lowest common
denominator.
For example, here are some big stumbling blocks:
Additionally,
the Anfyteam in Italy has put together a detailed list of gaming and graphics-related
stuff that MIDP is missing <http://www.anfyteam.com/dev/j2me/midpimage.html>.
Due to all the restrictions on a small device, there is no way of fitting in
a just-in-time compiler (JIT). This means code will run quite slowly. In fact,
while playing around with some casual tests, a Java 2 Micro Edition (J2ME) application
runs about three to eight times slower than a native Palm application written
in a compiled language such as C.
If you want to get some idea of the graphics speed of J2ME, the Anfyteam has
created a great benchmark called Amark. Download it here <http://www.anfyteam.com/dev/j2me/amark12.zip>.
So is J2ME like war - good for absolutely nothing?
The Good News
First, some very good news: Java-enabled mobile phones embed the KVM right on
the chipset. That means there are no memory hits, quick startup times, and quicker
processing times.
Another interesting development is that several brands of Java phones offer
neat extension APIs that let you access special, native features. Motorola and
Nokia, for example, have announced game APIs that allow for audio, animations,
transparency, and better graphics.
Additionally, it's important to remember that Java is perhaps the easiest modern
language to develop in. With garbage collection of old objects and lack of memory
allocation and pointers, it's a great way to create quick prototypes and develop
them out into full apps. The object-oriented nature of Java makes it easy to
maintain, making sweeping code changes with a little modification to a superclass.
Writing a native handheld application requires countless hours of debugging,
emulating, testing, deploying, redebugging, and packaging. Write to a wrong
memory location, and you can easily fry the machine. Waste a little memory on
a desktop or server application, and nobody will bat an eye. But when dealing
with a tiny space like the Palm, every bad byte hurts. Memory leaks in Java
are possible, but they are much easier to avoid.
Perhaps the most compelling argument for using Java is that - you guessed it
- you can write once and run every-damn-where. Theoretically, an application
written for a Motorola cell-phone can also run on Nokia, an Ericsson, a Siemens,
or a Palm. The same code could even be compiled and run as an applet in a Web
browser, as an application on a million-dollar server machine, in your car's
dashboard, oreventuallyin a Java-powered neural link to your own
brain!
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:
The only thing
that should set off your mental alarms is step number threepreverification.
This may sound weird and complicated, but is actually quite easy. The purpose
of preverification, theoretically, is to go through your bytecode and set hints
up so that the actual verification of bytecode on the Palm will happen much
more quickly, saving you valuable startup time.
There are many development environments that do all the compiling, preverification,
and 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. See the resources
list at the end of this article for more info.
Sun's own J2ME Wireless Toolkit is free, complete, really easy, 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.
![]() |
|
Sun's
own J2ME Wireless Toolkit is free, complete,
really easy, and available for Windows, Linux, and Solaris. |
We'll be using the Wireless Toolkit throughout this article. Download it here <http://java.sun.com/products/j2mewtoolkit/>.
Note that in order
to run the Wireless Toolkit, you'll need Java itself (JDK1.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 here <http://java.sun.com/j2se/1.3/download-windows.html>.
Be sure to install it per directions, with all the proper settings for classpaths
and paths.
Write Your Program
Just like an applet is based on the java.applet.Applet calss, class, a MIDLet
always extends javax.microedition.midlet.
A MIDlet handles basic event handling and can be thought of as the one and only
"window" that your application runs within.
Enough talk. Let's look at some code. Let's pass up the wonderful cliché
of a nice Hello World program and create a full single-player Tic-Tac-Toe
game instead.
Writing the Midlet
The heart of every MIDlet is the startApp()
method. It kicks the MIDlet into action and should set up all the components
or other objects you are interested in. Every MIDlet must also contain a pauseApp()
and destroyApp() methods, which
are called if and when a user chooses to either pause or quit your program.
Graphically speaking, the actual screen on your mobile phone or other devices
is a Display object. Every MIDlet has one and only one Display object, which
you can access using getDisplay(this).
The Display
A Display can consist of either a Screen object or a Canvas. Every Screen has
an optional title (usually at the top) and Ticker (usually running along the
bottom). Specific types of Screens include:
You should always
create your own Canvas subclass. For example:
class SillyCanvas extends Canvas
{
public void paint(Graphics g)
{
g.drawRect(1,1,getWidth()-2,getHeight()-2);
g.setFont(Font.getFont(Font.FACE_MONOSPACE,
Font.STYLE_PLAIN,Font.SIZE_SMALL));
g.setColor(0);
g.drawString("Hello World",
getWidth() / 2, 0,
Graphics.HCENTER
| Graphics.TOP);
g.drawImage(house, 10,30, g.TOP|g.LEFT);
}
}
This Canvas contains
a rectangle bordering the entire screen with the string "Hello World"
at the top, horizontal center. A house image is also drawn at the (10,30) coordinate.
You could drop this canvas into the Display by creating it in your MIDlet:
private SillyCanvas aCanvas = new SillyCanvas();
And then, in the
MIDlet's startApp() method or anywhere else that made sense, you could set the
current Display to show the special canvas:
theDisplay.setCurrent(aCanvas);
Note that a mobile
phone's Display can only show one Screen or Canvas at a time. A typical application
starts with a List as a main menu of choices, branching into other types of
Screens depending on the user's selection.
Animating
The typical way of animating with MIDP is to use double buffering:
Rolling your own
double buffering can make for smoother animations, but copying images can very
slow and memory-intensive. Also, some systems repaint the screen slower than
the image can be copied-these phones will show graphic flickering.
Be aware that the refresh rate of most mobile phone screens is much slower than
you may be used to for PC game programming. Frame rates of 4 fps are common...
if you're lucky.
Creating Tic Tac
Toe
![]() |
|
Tic
Tac Toe MIDlet
running on the Motorola i85s |
So let's create a quick and dirty Tic Tac Toe MIDlet would create a form and add it to the display using Display's setCurrent() method.
Our TicTacToe game will consist of a 3x3 array of characters. Each square in the grid will be assigned a number, corresponding to the position on the phone's keypad. When you hit a number, you put either an X or an O in the array, depending on whose turn it is. So we won't even use any graphics. We'll simply use the Canvas to draw the array, as a few rows of Strings. The game continues as so until somebody wins. [Code Listing: Tic Tac Toe]
If all goes well,
you'll wind up with a fresh, happy TicTacToe.class
file. To test the application out, Sun has been kind enough to release a nice
emulator. Just hit the Build button in the Wireless Toolkit. This will create
the necessary Java classes. Your classes
will also be automatically preverified and packaged into JAR and JAD files.
You can now hit the Run button. You can choose which Device you want to emulate
by playing with the Device pull-down menu.
If you happen
to actually own an i85s phone, you can plug it into your PC and use the phone's
linking software to install the MIDlet directly (the JAR and the JAD file in
the \J2mewtk\apps\TicTacToe directory) into the phone's memory. This is similar
to the way you might install an application on the Palm Pilot.
In the very near future, Motorola and other mobile phone manufacturers may make
it easy for users to download MIDlets right to their phones, on demand.
[Code Listing: Tic Tac Toe]
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class TicTacToe extends MIDlet implements CommandListener {
// The main display elements
private Display theDisplay;
private TicTacToeCanvas canvas;
// Keep track of winner
private String winner = "";
private boolean gameOver = false;
// The game state
private int whoseturn = 0;
private char board[][] = { {'1' , '2' , '3'} ,
{'4' , '5' , '6'} ,
{'7' , '8' , '9'} };
// Command
static final Command exitCommand = new Command("Exit", Command.STOP,
1);
public TicTacToe()
{
// Create the main Display
theDisplay = Display.getDisplay(this);
}
class TicTacToeCanvas extends Canvas
{
TicTacToeCanvas()
{
}
public void paint(Graphics g)
{
int width = getWidth();
int height = getHeight();
g.setColor( 0,
0, 0 );
g.fillRect( 0,
0, width, height );
g.setColor( 255, 255,
255);
String r1 = board[0][0]+"|"+board[0][1]+"|"+board[0][2]+"\n";
String r2 = board[1][0]+"|"+board[1][1]+"|"+board[1][2]+"\n";
String r3 = board[2][0]+"|"+board[2][1]+"|"+board[2][2];
g.drawString("TIC TAC
TOE",15,0, Graphics.LEFT|Graphics.TOP);
g.drawString(r1,30,15,
Graphics.LEFT|Graphics.TOP);
g.drawString(r2,30,30,
Graphics.LEFT|Graphics.TOP);
g.drawString(r3,30,45,
Graphics.LEFT|Graphics.TOP);
if (winner != "")
{
g.drawString("WINNER:
"+winner,0,60,Graphics.LEFT|Graphics.TOP);
}
else
{
g.drawString("TURN: Player
"+(whoseturn+1),0,60,Graphics.LEFT|Graphics.TOP);
}
}
// Check for keyboard entry
protected void keyPressed(int keyCode)
{
// Fill in the X and Os
if (keyCode >= 49 &&
keyCode <= 57 && !gameOver)
{
int x = 0, y =
0;
keyCode -= 49;
if (keyCode <
3)
{
x = keyCode;
y = 0;
}
else if (keyCode
< 6)
{
x = keyCode-3;
y = 1;
}
else
{
x = keyCode-6;
y = 2;
}
// If this
slot is open...
if (board[y][x] != 'X'
&& board[y][x] != 'O')
{
if (whoseturn
== 0)
board[y][x] = 'X';
else
board[y][x] = 'O';
//
Next player's turn
whoseturn
= 1-whoseturn;
checkForWinner();
//
repaint
canvas.repaint();
}
}
}
}
protected void startApp() throws MIDletStateChangeException
{
canvas = new TicTacToeCanvas();
// Add the exit command
canvas.addCommand(exitCommand);
canvas.setCommandListener(this) ;
theDisplay.setCurrent(canvas);
}
protected void pauseApp() { }
public void destroyApp(boolean unconditional)
{
}
// Handle events.
public void commandAction(Command c, Displayable d)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}
private void checkForWinner()
{
int i,j;
int numXConsec = 0; //
Number of consecutive Xs
int numOConsec = 0; //
Number of consecutive Os
boolean tie=true;
// Check for a tie
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
if (board[i][j] != 'X' || board[i][j] != 'O')
{
tie = false;
break;
}
}
if (tie)
{
GameOver(-1);
return;
}
// Check Horizontally first
for (i=0; i<3; i++)
{
numXConsec = numOConsec = 0;
for (j=0; j<3; j++)
{
if (board[i][j] == 'X')
numXConsec++;
else if (board[i][j] == 'O')
numOConsec++;
else
break;
}
if (numXConsec > 2)
{
GameOver(0);
return;
}
else if (numOConsec > 2)
{
GameOver(1);
return;
}
}
// Check Vertically
for (i=0; i<3; i++)
{
numXConsec = numOConsec = 0;
for (j=0; j<3; j++)
{
if (board[j][i] == 'X')
{
numXConsec++;
}
else if (board[j][i] == 'O')
numOConsec++;
else
break;
}
if (numXConsec > 2)
{
GameOver(0);
return;
}
else if (numOConsec > 2)
{
GameOver(1);
return;
}
}
// Finally Check both diagnals
if ( ((board[0][0] == board[1][1])
&& (board[1][1] == board[2][2]) &&
(board[2][2] == 'X')) ||
((board[0][2] == board[1][1]) &&
(board[1][1] == board[2][0]) &&
(board[2][0] == 'X')) )
{
GameOver(0);
return;
}
if ( ((board[0][0] == board[1][1])
&& (board[1][1] == board[2][2]) &&
(board[2][2] == 'O')) ||
((board[0][2] == board[1][1]) &&
(board[1][1] == board[2][0]) &&
(board[2][0] == 'O')) )
{
GameOver(1);
return;
}
}
private void GameOver(int p)
{
if (p == -1)
winner = "Tie!";
else if (p == 0)
winner = "Player
1!";
else
winner = "Player
2!";
gameOver = true;
}
}
Networking
Of course the real fun of having an application on a mobile phone is networking.
The mobile games that are most likely to be successful will involve lots of
multiplayer ability, bringing players together in ways that nobody has ever
experienced before.
The MIDP specification makes it extremely easy to pass data back and forth.
Many phones support Datagrams, though they are not guaranteed to work on every
device. The most common and easy method of MIDP network communication, of course,
is using HTTP.
Every Motorola i85s phone, for example, has its own static IP address. Having
one phone communicate with another is only a matter of simple peer-to-peer networking.
In addition, the phone can connect to any outside server machine. This server
can be used as a gateway for pretty much any type of game traffic or other network
communication imaginable. For instance, a gateway can be set up to access an
entire database of sports scores, and then stream only the latest requested
scores to a MIDlet.
To connect to a server, simply have the MIDlet use the Connector class:
Datagram dgram = dc.newDatagram(message,
msglength,
"datagram://www.myserver.com:9000");
dc.send(dgram);
dc.close();
The remote "server"
could, of course, be another device. Just create an endless loop that listens
to a port and waits for some data:
DatagramConnection dc = (
DatagramConnection)Connector.open
("datagram://:"+receiveport);
while (true)
{
dgram = dc.newDatagram(dc.getMaximumLength());
dc.receive(dgram);
reply = new String(dgram.getData(), 0,dgram.getLength());
}
Since the Datagram protocol is standard, one could write a dastardly-simple server component in Java Standard Edition (or any other language), running on any PC. For instance:
DatagramSocket receiveSocket
= null;
DatagramPacket receivePacket = new DatagramPacket(bytesReceived, bytesReceived.length);
receiveSocket.receive(receivePacket);
A simple game can be written with relative ease. For instance, NumberPick.java is a MIDlet that allows a user to pick a number between 0 and 9. It then sends this number to a server (at a fictitious machine with the host name of myserver.com) Note that for the sake of testing, it's a good idea to set the server to 'localhost' - that way you can run the server and the client from the comfort of your desktop machine.
[Code Listing: Number Picker]
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.util.*;
public class NumberPick extends MIDlet implements CommandListener
{
// This hostname may be a server or the IP of another phone
static final String hostname = "myserver.com";
static final int sendport
= 9000;
static final int receiveport = 9001;
static boolean gotResult = false;
private Display myDisplay;
Receive receiveThread = new Receive();
private Alert responseAlert;
private Form searchwait;
private Form pickscreen;
TextField pickedNumber;
private Command PICK = new Command("Pick One", Command.OK,
1);
private Command OK = new Command("Try Again", Command.OK,
1);
public NumberPick()
{
}
public void startApp()
{
// Set up the Pick A Number screen
pickscreen = new Form("Pick A Number");
pickedNumber = new TextField("Between 0
and 9:","",1, TextField.NUMERIC);
pickscreen.append(pickedNumber);
pickscreen.addCommand(PICK);
pickscreen.setCommandListener(this);
// Set up a Searching, Please Wait screen
searchwait = new Form("Searching...");
searchwait.append(new StringItem("Wait","Please
wait..."));
searchwait.addCommand(OK);
searchwait.setCommandListener(this);
// Set up a Response Alert screen
responseAlert = new Alert("And Your Guess
Is...");
responseAlert.setTimeout(Alert.FOREVER);
myDisplay = Display.getDisplay(this);
myDisplay.setCurrent(pickscreen);
// Start the Listening thread
receiveThread.start();
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
public void commandAction(Command c, Displayable d)
{
if (d == pickscreen && c
== PICK)
{
String request
= pickedNumber.getString();
if ( !request.equals("")
)
{
myDisplay.setCurrent(searchwait);
sendPick(request);
}
}
}
void sendPick(String thepick)
{
// Now send the pick...
byte[] message = new byte[1];
System.arraycopy(thepick.getBytes(),
0, message, 0,1);
DatagramConnection dc = null;
String destAddr = "datagram://" +
hostname + ":" + sendport;
try {
dc = (DatagramConnection)Connector.open(destAddr);
// Create
a datagram socket and send
Datagram
dgram= dc.newDatagram(message,1,destAddr);
dc.send(dgram);
dc.close();
}
catch (Exception e)
{
System.out.println("Connecting
Exception: " + e.getMessage());
if (dc !=
null) {
try {
dc.close();
}
catch
(Exception f)
{
System.out.println("Exception Closing: " + f.getMessage());
}
}
}
}
class Receive extends Thread
{
public void run()
{
doReceive();
}
void doReceive()
{
DatagramConnection
dc = null;
Datagram
dgram;
try
{
dc = (DatagramConnection)Connector.open("datagram://:"+receiveport);
String reply;
while (true)
{
dgram = dc.newDatagram(dc.getMaximumLength());
dc.receive(dgram);
reply = new String(dgram.getData(), 0,dgram.getLength());
if (reply.equals("Y"))
{
responseAlert.setString("100%
right!");
myDisplay.setCurrent(responseAlert,pickscreen);
}
else
{
myDisplay.setCurrent(responseAlert,pickscreen);
responseAlert.setString("Wrong as can be!");
}
try
{
Thread.sleep(500);
}
catch
(Exception e)
{
}
}
}
catch
(Exception e)
{
System.out.println("Exception: " + e.getMessage());
if (dc != null)
{
try
{
dc.close();
}
catch
(Exception f)
{
System.out.println("Exception: " + f.getMessage());
}
}
}
}
}
}
Running on the myserver.com machine is NumberServer.java, which simply sits there and waits for a message on port 9000. If the number is 4, then the server sends back a simple one-byte "Y" message. Otherwise it sends back an "N".
Maybe not as compelling a game as Unreal or Quake III, but it's a start.
[Code Listing: Number Server]
import java.io.*;
import java.net.*;
import java.lang.*;
public class NumberServer
{
public
static void main(String args[])
{
DatagramSocket
receiveSocket = null;
try
{
byte[] receiveBytes = new byte[1];
InetAddress
receiveAddr = InetAddress.getByName("localhost");
int
receivePort = 9000;
receiveSocket = new DatagramSocket(receivePort, receiveAddr);
while
(true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveBytes, receiveBytes.length);
receiveSocket.receive(receivePacket);
String data = new String(receivePacket.getData(), 0, receivePacket.getLength());
byte[] reply = receivePacket.getData();
String replyString = new String(reply);
if (replyString.equals("4"))
sendResultsBack(true, receivePacket.getAddress());
else
sendResultsBack(false, receivePacket.getAddress());
}
}
catch
(Exception e)
{
System.err.println("Exception " + e);
}
finally
{
if (receiveSocket != null)
{
try
{
receiveSocket.close();
}
catch
(Exception e)
{
System.err.println("Exception " + e);
}
}
}
}
//
Send results back to the phone on port 9001
public
static void sendResultsBack(boolean rightanswer, InetAddress sendAddr)
{
byte results[] = new byte[1];
if (rightanswer)
results[0] = (byte)'Y';
else
results[0] = (byte)'N';
DatagramSocket sendSocket = null;
int
sendPort = 9001;
try
{
sendSocket
= new DatagramSocket();
DatagramPacket
sendPacket = new DatagramPacket(results,1, sendAddr, sendPort);
sendSocket.send(sendPacket);
}
catch
(Exception e)
{
System.out.println("Exception " + e);
}
finally
{
if (sendSocket != null)
{
try
{
sendSocket.close();
}
catch
(Exception e)
{
System.err.println("Exception " + e);
}
}
}
}
}
Final Tips
As you go forth into the world coding games more complicated and sophisticated
than TicTacToe and NumberPick, be sure to remember that every
byte counts! It's exceptionally easy to run out of memory on these phones.
Try to avoid Hashtables and Vectors, and recycle any objects you no longer need.
For example, instead of creating two buttons on two separate screens, try to
merely change the label on an existing button.
Also, avoid using costly operations like string concatenations. Use a StringBuffer
instead. As for interface design, remember your audience and the limitation
of the device. Use few, large, simple components that require as few keypad
presses as possible.
While your application is running, you can sniff out the memory using
Runtime.getRuntime().freeMemory()
and
Runtime.getRuntime().totalMemory()
Remember to strategically
garbage collect whenever resources fall too low using:
Runtime.getRuntime().gc()
Since the MIDlet
classes only contain a basic set of graphic user interface controls, you might
want to opt for a better library.
A site called Trantor in Germany offers a package known as kAWT <http://www.trantor.de/kawt/index.html>.
This is a lightweight version of Java's AWT specially tailored for J2ME. There
are versions for the Palm, as well as for MIDP. It allows your MIDlets to use
standard Java widgets such as Panels and Containers and makes the MIDlet code
truly upwardly compatible with applets. The only caveat is that kAWT will suck
away an additional 27K or so of memory.
Finally, I highly recommend you use a code packer or obfuscator to compress
your bytecode as much as possible. A good obfuscator such as IBM's jax <http://www.alphaworks.ibm.com/tech/JAX>
can make your final application as much as 30 percent smaller!
Resources
More info about J2ME:
http://java.sun.com/j2me/
More info about
the MIDP specifically:
http://java.sun.com/products/midp/
For some great
tutorials and sample programs, check out:
http://webdev.apl.jhu.edu/~rbe/kvm/
The Java Mobile
site has lots of articles, tips, and sampleapplications:
http://www.javamobile.org/
The Micro Java
Network has all sorts of great articles and forums. Here are the games:
http://www.microjava.com/downloads/games
Visit Bill Day's
J2ME Archive with tons of sample applications, links to IDEs and SDKs, and anything
else J2ME related. There is also lots of source code:
http://www.billday.com/j2me/
http://www.gamasutra.com/features/20010917/fox_01.htm
Copyright © 2003 CMP Media Inc. All rights reserved.