本文為 J2ME 101 系列第三部分,聚焦 MIDP 持久化核心——RMS。前情提要:MIDlet 生命週期、高級 UI;後續將講網絡編程。
recordId 從 1 遞增,刪除後永久空缺)recordId (int) + data (byte[])// 1. 標準:同套件、可讀寫
RecordStore.openRecordStore("name", true);
// 2. 進階:授權控制
RecordStore.openRecordStore("name", true,
RecordStore.AUTHMODE_PRIVATE, // 僅同套件可存取
true); // 可寫入
// 3. 跨套件:需知廠商名與套件名
RecordStore.openRecordStore("name", "Vendor", "SuiteName");
void closeRecordStore()
void deleteRecordStore(String name)
String[] listRecordStores()
int addRecord(byte[] data, int offset, int len)
void setRecord(int id, byte[] data, int offset, int len)
void deleteRecord(int id)
byte[] getRecord(int id)
int getRecord(int id, byte[] buf, int offset)
int getRecordSize(int id)
int getNextRecordID()
int getNumRecords()
long getLastModified()
int getVersion()
String getName()
int getSize()
int getSizeAvailable()
RecordEnumeration enumerateRecords(RecordFilter, RecordComparator, boolean)
void addRecordListener(RecordListener)
void removeRecordListener(RecordListener)
void setMode(int authMode, boolean writable)
核心便利方法:
private void writeRecord(String str) {
rs.addRecord(str.getBytes(), 0, str.length());
}
private void readRecords() {
byte[] buf = new byte[50];
for (int i = 1; i <= rs.getNumRecords(); i++) {
int len = rs.getRecord(i, buf, 0);
System.out.println(new String(buf, 0, len));
}
}
缺陷:假設 recordId 連續,刪除後會拋 InvalidRecordIDException。
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeBoolean(bool[i]);
dos.writeInt(intArr[i]);
dos.writeUTF(strArr[i]);
dos.flush();
rs.addRecord(bos.toByteArray(), 0, bos.size());
bos.reset(); // 重用緩衝區
ByteArrayInputStream bis = new ByteArrayInputStream(recData);
DataInputStream dis = new DataInputStream(bis);
System.out.println(dis.readBoolean());
System.out.println(dis.readInt());
System.out.println(dis.readUTF());
bis.reset(); // 重用緩衝區
解決「ID 不連續」導致遍歷失效:
// 錯誤寫法
for (int i = 1; i <= rs.getNumRecords(); i++) rs.getRecord(i, ...); // 刪除後崩潰
// 正確寫法
RecordEnumeration re = rs.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
byte[] rec = re.nextRecord();
// 處理
}
re.destroy();
場景:記錄格式 UTF字串 + int優先級,按優先級排序:
class PriorityComparator implements RecordComparator {
private byte[] buf = new byte[100];
public int compare(byte[] r1, byte[] r2) {
try {
// 讀取第一欄字串(丟棄)
new DataInputStream(new ByteArrayInputStream(r1)).readUTF();
int p1 = new DataInputStream(new ByteArrayInputStream(r1)).readInt();
// 同理 r2
new DataInputStream(new ByteArrayInputStream(r2)).readUTF();
int p2 = new DataInputStream(new ByteArrayInputStream(r2)).readInt();
return (p1 == p2) ? EQUIVALENT : (p1 < p2 ? PRECEDES : FOLLOWS);
} catch (Exception e) { return EQUIVALENT; }
}
}
class SearchFilter implements RecordFilter {
private String text;
public SearchFilter(String t) { text = t.toLowerCase(); }
public boolean matches(byte[] candidate) {
return new String(candidate).toLowerCase().indexOf(text) >= 0;
}
}
// UI 整合:TextField 輸入 → SearchFilter → enumerateRecords → 顯示結果
rs.addRecordListener(new RecordListener() {
public void recordAdded(RecordStore rs, int id) { log("Added: " + id); }
public void recordDeleted(RecordStore rs, int id) { log("Deleted: " + id); }
public void recordChanged(RecordStore rs, int id) { log("Changed: " + id); }
});
應用:多 MIDlet 協作、UI 即時刷新、備份觸發。
Form + TextField("Find") + Command(Find/Exit)commandAction → searchRecordStore() → enumerateRecords(filter, null, false) → 結果追加至 Formre.destroy() 釋放枚舉器資源RMS 雖簡陋,卻是 J2ME 唯一標準持久化 API。掌握流式序列化 + 枚舉器遍歷 + 比較器排序 + 過濾器查詢組合拳,即可構建出健壯、高效的本地存儲層。下一講將進入 J2ME 網絡編程領域——HTTP、Socket、HTTPS 與推送註冊,敬請期待。