- The javax.microedition.rms Package
- Accessing Record Stores with the RecordStore Class
- Building an Address Book for J2ME Devices
- Conclusion
- Additional Resources
Building an Address Book for J2ME Devices
This example builds a basic address book application that enables a user to view contact information from a mobile device. I'll cheat a little and simply hardcode the records being added into the application. (In the next article in this series, I'll actually use J2ME networking capabilities to retrieve a comma-delimited data file from a Web server!) The user will be able to view a list of addresses and select one from the list to be viewed. To do this, you separate the data access logic from the UI logic by creating two separate classes: the AddressDB class encapsulates all the RMS code; the AddressBookMIDLet class encapsulates the GUI code. The code for AddressDB is listed below.
import javax.microedition.rms.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; public class AddressDB { private static RecordStore rs = null; public AddressDB() { try { rs = RecordStore.openRecordStore("addressbook", true); } catch (RecordStoreException e) { System.out.println(e); e.printStackTrace(); } } public void addAddress(String Name, String Address) { // Store each address within the "addressbook" record store. // For simplicity's sake, separate the Name and Address // fields with a comma. ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream output = new DataOutputStream(os); try { output.writeUTF(Name + "," + Address); } catch (IOException e) { System.out.println(e); e.printStackTrace(); } //Now that the address is in the stream, extract it // and add it to the store. byte[] b = os.toByteArray(); try { rs.addRecord(b, 0, b.length); } catch (RecordStoreException e) { System.out.println(e); e.printStackTrace(); } } public static String getName(int index) { int counter = 1; int commalocation = 0; String name = null; //Retrieve the UTF string from the data store. Note that // we start at position 2 because the writeUTF() method // writes two bytes at the beginning of the stream to // indicate the number of bytes to follow. try { RecordEnumeration enumRec = rs.enumerateRecords(null, null, false); while ((counter <= index) && (enumRec.hasNextElement())) { String strTemp = new String(enumRec.nextRecord()); commalocation = strTemp.indexOf(','); name = strTemp.substring(2, commalocation); counter++; } } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return name; } public static String getAddress(int index) { int counter = 1; int commalocation = 0; String address = null; try { RecordEnumeration enumRec = rs.enumerateRecords(null, null, false); while ((counter <= index) && (enumRec.hasNextElement())) { String strTemp = new String(enumRec.nextRecord()); commalocation = strTemp.indexOf(','); address = strTemp.substring(commalocation + 1); counter++; } } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return address; } public static int recordCount() { int count = 0; try { count = rs.getNumRecords(); } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return count; } }
The AddressDB class contains several public access methods that hide the details of record store access from the outside caller. The AddressDB() constructor makes the call to RecordStore.openRecordStore(), just as discussed earlier. I've also created four "helper" methods for accessing the underlying record store: recordCount(), getAddress(), getName(), and addAddress(). Notice that the addAddress() method simply places a comma between the name/address "fields" for this example. Likewise, getAddress() and getName() retrieve the name/address fields from the record store by parsing the record using the comma delimiter.
The AddressBookMIDLet class (shown below) builds on the UI work I did in the simple "Hello World!" example discussed in an earlier article. Primary differences include the addition of an AddressDB object, a List GUI component, and a Back command to accompany the Exit command. We'll populate the database using the addAddress() method from the AddressDB class. Inside the startApp() method, the List is populated through the use of List.append() and AddressDB.addAddress() method calls. To view an individual record, it's necessary to process a List selection event. This is done within commandAction() and results in a new TextBox being created and added to the display. Because the cmdBack command object was created using the Command.BACK variable, when a second element is added to the display, the environment knows to display a Back command button. You process "back" command events by setting the display focus back to the mnuMain List object.
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class AddressBookMIDLet extends MIDlet implements CommandListener { Display display = null; List mnuMain = null; TextBox txtAddress = null; static final Command cmdBack = new Command("Back", Command.BACK, 0); static final Command cmdExit = new Command("Exit", Command.STOP, 3); AddressDB dbAddress = null; public AddressBookMIDLet() { //Create the AddressDB and add some sample records dbAddress = new AddressDB(); dbAddress.addAddress("John Doe", "123 Elm Street"); dbAddress.addAddress("Lisa Smith", "742 Avenue B"); dbAddress.addAddress("Albert Einstein", "853 Franklin Avenue"); dbAddress.addAddress("Bryan Morgan", "101 Scenic Highway"); dbAddress.addAddress("Marc Robards", "741 Highway 101"); } public void startApp() throws MIDletStateChangeException { display = Display.getDisplay(this); mnuMain = new List("Addresses", Choice.IMPLICIT); int count = dbAddress.recordCount(); for (int i=0; i < count; i++) { mnuMain.append(dbAddress.getName(i+1), null); } mnuMain.addCommand(cmdExit); mnuMain.setCommandListener(this); display.setCurrent(mnuMain); } public void pauseApp() { display = null; } public void destroyApp(boolean unconditional) { notifyDestroyed(); } public void commandAction(Command c, Displayable d) { String str = c.getLabel(); if (str.equals("Exit")) { destroyApp(true); } else if (str.equals("Back")) { display.setCurrent(mnuMain); } else { List select = (List)display.getCurrent(); String txtSelect = AddressDB.getName(select.getSelectedIndex() + 1) + ", " + dbAddress.getAddress(select.getSelectedIndex() + 1); txtAddress = new TextBox("Address", txtSelect, 255, TextField.ANY); txtAddress.addCommand(cmdBack); txtAddress.setCommandListener(this); display.setCurrent(txtAddress); } } }
Figures 1 and 2 below illustrate the AddressBook list and text box used to display our application data.
The AddressBook list.
Address data in a text box.