首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 101 深度教程(三):RMS 記錄管理系統進階應用

     編輯:J2ME

教程系列回顧

本文為 J2ME 101 系列第三部分,聚焦 MIDP 持久化核心——RMS。前情提要:MIDlet 生命週期、高級 UI;後續將講網絡編程。

RMS 資料模型

  • 表 = RecordStore(名稱 ≤ 32 字元,套件內唯一)
  • 行 = Record(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");

完整 API 速覽

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)

實戰範例 1:ReadWrite MIDlet(字串存取)

核心便利方法:

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。

實戰範例 2:ReadWritePrimitives MIDlet(基本型別 + Data流)

寫入:DataOutputStream → ByteArrayOutputStream → byte[] → addRecord

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();  // 重用緩衝區

讀取:getRecord → ByteArrayInputStream → DataInputStream

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();  // 重用緩衝區

RecordEnumeration 為何不可或缺

解決「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();

RecordComparator:多欄位排序實戰

場景:記錄格式 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; }
    }
}

RecordFilter:關鍵字搜尋實戰

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 → 顯示結果

RecordListener:事件驅動同步

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 即時刷新、備份觸發。

完整案例:StringSearch MIDlet

  • 預載 4 條名言記錄
  • UI:Form + TextField("Find") + Command(Find/Exit)
  • 事件:commandAction → searchRecordStore() → enumerateRecords(filter, null, false) → 結果追加至 Form
  • 清理:re.destroy() 釋放枚舉器資源

最佳實踐總結

  1. **永遠用枚舉器遍歷**,不要假設 ID 連續。
  2. **流式讀寫基本型別**,避免手動 byte[] 拼裝。
  3. **比較器/過濾器統一實作介面**,業務邏輯與存儲分離。
  4. **監聽器用於解耦**,而非核心邏輯路徑。
  5. **定期備份關鍵 Store**,防止裝置遺失/刷機資料歸零。

結語

RMS 雖簡陋,卻是 J2ME 唯一標準持久化 API。掌握流式序列化 + 枚舉器遍歷 + 比較器排序 + 過濾器查詢組合拳,即可構建出健壯、高效的本地存儲層。下一講將進入 J2ME 網絡編程領域——HTTP、Socket、HTTPS 與推送註冊,敬請期待。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved