J2ME: Writing Java Applications for Mobile and Embedded Devices
Java Micro Edition is a serious attempt to bring Java to devices with kilobytes of RAM rather than megabytes. Here is what the platform looks like and what you can realistically build on it.
J2ME: Writing Java Applications for Mobile and Embedded Devices
Sun has been working on a version of Java for constrained devices — what they are calling the Java Micro Edition, or J2ME. The full specification is not finalised yet but enough is public that it is worth understanding the architecture and what it means for developers who want to target mobile phones, pagers and embedded devices.
I have been following this closely because at Motorola we make the devices these things would run on. Understanding the platform from the developer side is useful context.
The Problem J2ME Solves
Java Standard Edition requires a JVM with at least several megabytes of memory. A mobile phone in 1997 has somewhere between 16KB and 512KB of RAM. Running J2SE on it is not realistic.
J2ME addresses this with a tiered architecture. At the bottom is a configuration — the minimal JVM and core libraries needed for a class of device. Above that are profiles — higher-level APIs for specific device types. An application targets a specific configuration-plus-profile combination.
Two configurations are emerging:
CLDC (Connected Limited Device Configuration) — targets devices with 160KB to 512KB of memory, limited power and intermittent network connectivity. Mobile phones and pagers.
CDC (Connected Device Configuration) — targets devices with 2MB or more of memory, more processing power and more reliable connectivity. Set-top boxes, networked appliances.
Each configuration strips down the JVM itself. CLDC, for instance, omits floating-point arithmetic entirely (many phones do not have hardware floating-point), removes finalize(), and simplifies the threading model.
MIDP: The Profile for Mobile Phones
The profile most relevant to phones is MIDP — the Mobile Information Device Profile. It sits on top of CLDC and adds:
- A display API for rendering to small screens
- A UI widget set (commands, forms, lists)
- Persistent storage via the Record Management System (RMS)
- Network access via
javax.microedition.io
A J2ME application for MIDP is called a MIDlet. It extends javax.microedition.midlet.MIDlet the same way a desktop applet extends java.applet.Applet:
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
public class DeviceQueryMIDlet extends MIDlet {
private Display display;
private TextBox textBox;
public DeviceQueryMIDlet() {
textBox = new TextBox(
"Device Status", // title
"Loading...", // initial text
256, // max characters
TextField.ANY // constraints
);
}
protected void startApp() throws MIDletStateChangeException {
display = Display.getDisplay(this);
display.setCurrent(textBox);
// Begin fetching device status from network
fetchStatus();
}
protected void pauseApp() {
// Save state if needed
}
protected void destroyApp(boolean unconditional)
throws MIDletStateChangeException {
// Clean up resources
}
private void fetchStatus() {
textBox.setString("Connected to: 192.168.1.1\nStatus: OK");
}
}
The lifecycle — startApp, pauseApp, destroyApp — maps to what happens when a call comes in and interrupts the application (pause) or the user exits (destroy).
The Display API
MIDP gives you two levels of UI control.
High-level API — Form, List, TextBox, Alert. The platform renders these in whatever way is appropriate for the specific device's screen. You get portability but no control over appearance.
Low-level API — Canvas. You get a paint(Graphics g) method and a coordinate system. You draw everything yourself with lines, rectangles, images. You get full control but you are responsible for making it look reasonable across different screen sizes.
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
public class DeviceMapCanvas extends Canvas {
protected void paint(Graphics g) {
int w = getWidth();
int h = getHeight();
// Clear background
g.setColor(0xFFFFFF);
g.fillRect(0, 0, w, h);
// Draw a simple device representation
g.setColor(0x000000);
g.drawRect(10, 10, 30, 20);
g.drawString("SW-01", 10, 35, Graphics.LEFT | Graphics.TOP);
g.drawRect(60, 10, 30, 20);
g.drawString("RT-01", 60, 35, Graphics.LEFT | Graphics.TOP);
// Draw a link between them
g.drawLine(40, 20, 60, 20);
}
}
Screen sizes on current devices range from 96x65 pixels to about 200x200. Designing for the smallest common case is the safe approach.
Persistent Storage: The Record Management System
MIDP does not give you a filesystem. Persistent storage goes through the Record Management System (RMS), which is essentially a database of byte arrays:
import javax.microedition.rms.RecordStore;
public class DeviceCache {
private static final String STORE_NAME = "devices";
public void saveDevice(String name, String ip) throws Exception {
RecordStore store = null;
try {
store = RecordStore.openRecordStore(STORE_NAME, true);
String entry = name + "," + ip;
byte[] data = entry.getBytes();
store.addRecord(data, 0, data.length);
} finally {
if (store != null) store.closeRecordStore();
}
}
public String[] loadDevices() throws Exception {
RecordStore store = null;
try {
store = RecordStore.openRecordStore(STORE_NAME, false);
int count = store.getNumRecords();
String[] results = new String[count];
for (int i = 1; i <= count; i++) {
byte[] data = store.getRecord(i);
results[i - 1] = new String(data);
}
return results;
} finally {
if (store != null) store.closeRecordStore();
}
}
}
Record IDs start at 1. The total storage available varies by device — anything from 8KB to a few hundred KB. You cannot rely on having much space and you should design your data model accordingly.
Networking
J2ME uses a generalised connection framework rather than the java.net socket API. The syntax is unusual at first:
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import java.io.InputStream;
public class HttpFetcher {
public String fetch(String url) throws Exception {
HttpConnection conn = null;
InputStream is = null;
try {
conn = (HttpConnection) Connector.open(url);
conn.setRequestMethod(HttpConnection.GET);
int responseCode = conn.getResponseCode();
if (responseCode != HttpConnection.HTTP_OK) {
throw new Exception("HTTP error: " + responseCode);
}
is = conn.openInputStream();
StringBuffer sb = new StringBuffer();
int ch;
while ((ch = is.read()) != -1) {
sb.append((char) ch);
}
return sb.toString();
} finally {
if (is != null) is.close();
if (conn != null) conn.close();
}
}
}
The Connector.open() call takes a URI scheme — http://, socket://, datagram:// — and returns the appropriate connection type. The same pattern handles all connection types, which is elegant but takes getting used to.
Packaging and Deployment
J2ME applications are packaged as JAR files with an accompanying JAD (Java Application Descriptor) file. The JAD is a plain-text properties file that describes the application so the device can decide whether to download it before committing to the full JAR:
MIDlet-1: DeviceQuery, /icon.png, DeviceQueryMIDlet
MIDlet-Jar-Size: 12543
MIDlet-Jar-URL: http://internal.corp/midlets/devicequery.jar
MIDlet-Name: DeviceQuery
MIDlet-Vendor: Motorola
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0
The device's OTA (over-the-air) provisioning system downloads the JAD first, checks that the JAR size and the required configuration/profile match what the device supports, then downloads the JAR.
Where This Platform Is Today
J2ME is still early. The MIDP specification is not yet final and the first MIDP-capable phones are not yet in general release. But the architecture is sound and the level of industry involvement from Nokia, Motorola, Sony Ericsson and others suggests this is the direction mobile Java is going.
The constraints are real — no floating point on CLDC, no generics (but Java SE does not have them yet either), limited storage, small screens. But within those constraints you can build genuinely useful applications: device monitoring tools, configuration checkers, field service applications where an engineer walks the floor and queries equipment from a phone rather than going back to a workstation.
For anyone building software at a company that makes or operates mobile devices, J2ME is worth serious attention now while the specifications are still being shaped.