Persistent storage

For data storage and retrieval, MIDP 2.0 features a Record Management System (RMS) that is modeled after a simple record oriented database. A record store is a collection of data that remains persistent across multiple invocations of a MIDlet.

MIDlets are allowed to create multiple record stores, as long as the record stores are given different names. The names are case sensitive, and have a maximum of 32 characters. MIDlets can access record stores relating to other MIDlets within the same MIDlet suite. Also, if explicit permission is given, MIDlets within other suites can also access the record store. The RMS can be used for storing both public and private data. The structure of the stored data is flat which makes the system very straightforward to use, but on the downside, if you want to utilise more complex data structures like relative databases, you have to implement the additional logic needed.

A record store is always stored on the same drive as the MIDlet itself (phone memory or memory card). The size of record store database is limited only by free disk space. A RecordStoreFullException is thrown when free space runs out.

Each record in a record store consists of a single binary field of variable size. The responsibility for interpreting the contents of a record falls entirely on the MIDlet. RMS only provides the storage and a unique identifier.

The following methods do not return until all listeners have been called:

  • addRecord()

  • setRecord()

  • deleteRecord()

As implied above, a blocking listener causes blocking of thread that asked for the record modification. The implementation does not, however, block other threads accessing the record store (unless the accesses lead to same blocking condition of a listener.)

Usually one record store per application is sufficient for all the application data. The following snippet demonstrates how to open a record store and read its content.

RecordStore recordStore = null;

try {
    // Open the record store, and create it if it does not exist already
    recordStore = RecordStore.openRecordStore(“myUniqueIdentifier”, true);
}
catch (RecordStoreException rse) {
    rse.printStackTrace();
}

// The data is read into strings which are stored in a vector
Vector result = new Vector();
        
try {
    RecordEnumeration recordEnum = recordStore.enumerateRecords(null, null, false);
    int index = 0;
    byte[] data = null;
            
    while (recordEnum.hasNextElement()) {
        index = recordEnum.nextRecordId();
        data = recordStore.getRecord(index);
        String element = new String(data);
        result.addElement(element);
    }

    // Close the record store handle as it is no longer required
    recordStore.closeRecordStore();
}
catch (RecordStoreException rse) {
    rse.printStackTrace();
}


The following snippets show how to write data into a record store. Opening and closing a handle is omitted.

int recordId = 0; // The record ID for the new record

try {
    // data is a byte array
    recordId = recordStore.addRecord(data, 0, data.length);
}
catch (RecordStoreException rse) {
    rse.printStackTrace();
}

RMS usage guidelines

Basic RMS operations can be divided into three groups performance wise:

  • light: getRecord

  • medium: addRecord, setRecord and deleteRecord, closeRecordstore

  • heavy: openRecordstore

An operation in a heavier group can be about five to ten times more costly than in lighter group.

To optimize RMS usage, keep the record store open as long as possible. Avoid the pattern of opening the record store, getting a single record and closing the record store.

Use case

An application that lists Top-100 Movies in your favorite video rental store. The application has two views: a main window listing Top-100 movies and a Details view with information on the cast, story line and so on. The application uses RMS to store movie information, each movie in its own RecordStore .

The Top-100 view uses RMS in following way:

  • for each of 100 RecordStores

    • open RecordStore

    • get record (movie poster saved as PNG)

    • close RecordStore

  • show movie posters in a list

This means that whenever the user goes back from the Details view to the Top-100, the application opens same the RecordStores again and again. Opening RecordStore is a heavy operation and there is a visible pause in the application when the user returns to the main view.

The user experience of the application can be improved greatly by simply closing RecordStores when application exits. This means that returning to the Top-100 view is practically instant, instead of having a delay of about half a second. The example application illustrates this issue.