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

J2ME RMS 記錄存儲系統完整解析:單一記錄構造、RecordStore 操作封裝與實戰應用模式

     編輯:J2ME

RMS 核心定位

Record Management System (RMS) 是 J2ME 唯一的持久化儲存機制,類似輕量級記錄型資料庫,適用於:高分紀錄、遊戲存檔、用戶設定、離線資料隊列、快取資料。

架構分層設計


// 第一層:單一記錄資料模型 (POJO + 序列化)
public class GameRecord {
    private int level;
    private int score;
    private long timestamp;
    private String playerName;
    private boolean completed;

    // 建構子、getter/setter 略...

    // 序列化為位元組陣列 (DataOutputStream + UTF-8)
    public byte[] toBytes() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt(level);
            dos.writeInt(score);
            dos.writeLong(timestamp);
            dos.writeUTF(playerName); // 中文安全
            dos.writeBoolean(completed);
            dos.flush();
            return baos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("序列化失敗", e);
        }
    }

    // 反序列化
    public static GameRecord fromBytes(byte[] data) {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            DataInputStream dis = new DataInputStream(bais);
            GameRecord r = new GameRecord();
            r.level = dis.readInt();
            r.score = dis.readInt();
            r.timestamp = dis.readLong();
            r.playerName = dis.readUTF();
            r.completed = dis.readBoolean();
            return r;
        } catch (IOException e) {
            throw new RuntimeException("反序列化失敗", e);
        }
    }
}

// 第二層:RecordStore 操作封裝 (DAO 模式)
import javax.microedition.rms.*;

public class RecordStoreManager {
    private static final String STORE_NAME = "GameData";

    // 開啟/建立存儲
    private RecordStore open() throws RecordStoreException {
        return RecordStore.openRecordStore(STORE_NAME, true);
    }

    // 新增記錄
    public boolean addRecord(GameRecord record) {
        try {
            RecordStore rs = open();
            rs.addRecord(record.toBytes(), 0, record.toBytes().length);
            rs.closeRecordStore();
            return true;
        } catch (RecordStoreException e) {
            return false;
        }
    }

    // 取得所有記錄
    public GameRecord[] getAllRecords() {
        try {
            RecordStore rs = open();
            int count = rs.getNumRecords();
            GameRecord[] result = new GameRecord[count];
            RecordEnumeration re = rs.enumerateRecords(null, null, false);
            for (int i = 0; i < count; i++) {
                int id = re.nextRecordId();
                result[i] = GameRecord.fromBytes(rs.getRecord(id));
            }
            rs.closeRecordStore();
            return result;
        } catch (RecordStoreException e) {
            return new GameRecord[0];
        }
    }

    // 依 ID 取得單筆
    public GameRecord getRecord(int recordId) {
        try {
            RecordStore rs = open();
            byte[] data = rs.getRecord(recordId);
            rs.closeRecordStore();
            return GameRecord.fromBytes(data);
        } catch (RecordStoreException e) {
            return null;
        }
    }

    // 更新記錄
    public boolean updateRecord(int recordId, GameRecord record) {
        try {
            RecordStore rs = open();
            rs.setRecord(recordId, record.toBytes(), 0, record.toBytes().length);
            rs.closeRecordStore();
            return true;
        } catch (RecordStoreException e) {
            return false;
        }
    }

    // 刪除記錄
    public boolean deleteRecord(int recordId) {
        try {
            RecordStore rs = open();
            rs.deleteRecord(recordId);
            rs.closeRecordStore();
            return true;
        } catch (RecordStoreException e) {
            return false;
        }
    }

    // 記錄總數
    public int getRecordCount() {
        try {
            RecordStore rs = open();
            int c = rs.getNumRecords();
            rs.closeRecordStore();
            return c;
        } catch (RecordStoreException e) {
            return 0;
        }
    }

    // 刪除整個存儲 (重置遊戲)
    public static void deleteStore() {
        try { RecordStore.deleteRecordStore(STORE_NAME); } 
        catch (RecordStoreException ignored) {}
    }
}

高級查詢:RecordFilter 與 RecordComparator


// 篩選:分數 > 1000 的記錄
RecordFilter highScoreFilter = new RecordFilter() {
    public boolean matches(byte[] candidate) {
        try {
            GameRecord r = GameRecord.fromBytes(candidate);
            return r.getScore() > 1000;
        } catch (Exception e) { return false; }
    }
};

// 排序:分數降序
RecordComparator scoreDescComparator = new RecordComparator() {
    public int compare(byte[] rec1, byte[] rec2) {
        try {
            int s1 = GameRecord.fromBytes(rec1).getScore();
            int s2 = GameRecord.fromBytes(rec2).getScore();
            return (s1 > s2) ? RecordComparator.PRECEDES : 
                   (s1 < s2) ? RecordComparator.FOLLOWS : RecordComparator.EQUIVALENT;
        } catch (Exception e) { return RecordComparator.EQUIVALENT; }
    }
};

// 使用
RecordEnumeration re = rs.enumerateRecords(highScoreFilter, scoreDescComparator, false);

實戰應用模式

1. 高分榜 (固定容量,自動淘汰最低)


public class HighScoreManager {
    private static final int MAX_ENTRIES = 10;
    private RecordStoreManager rsm = new RecordStoreManager();

    public void submitScore(String name, int score) {
        GameRecord r = new GameRecord(1, score, System.currentTimeMillis(), name, true);
        GameRecord[] all = rsm.getAllRecords();
        
        // 插入排序位置
        int pos = 0;
        while (pos < all.length && all[pos].getScore() >= score) pos++;
        
        if (pos < MAX_ENTRIES) {
            // 手動維護陣列順序 (RMS 無自動排序)
            // 這裡簡化:重新寫入前 N 筆
            // 實際專案建議用記錄 ID 管理或單獨存儲排序索引
        }
    }
}

2. 遊戲存檔 (單槽位,覆蓋寫入)


public class SaveGameManager {
    private static final String SAVE_STORE = "SaveSlot";
    private static final int SAVE_RECORD_ID = 1; // 固定 ID

    public void save(GameState state) {
        RecordStore rs = null;
        try {
            rs = RecordStore.openRecordStore(SAVE_STORE, true);
            if (rs.getNumRecords() == 0) {
                rs.addRecord(state.toBytes(), 0, state.toBytes().length);
            } else {
                rs.setRecord(SAVE_RECORD_ID, state.toBytes(), 0, state.toBytes().length);
            }
        } catch (RecordStoreException e) {
            // 處理失敗
        } finally {
            if (rs != null) try { rs.closeRecordStore(); } catch (Exception ignored) {}
        }
    }

    public GameState load() {
        try {
            RecordStore rs = RecordStore.openRecordStore(SAVE_STORE, false);
            if (rs.getNumRecords() > 0) {
                byte[] data = rs.getRecord(SAVE_RECORD_ID);
                rs.closeRecordStore();
                return GameState.fromBytes(data);
            }
        } catch (RecordStoreException ignored) {}
        return null; // 無存檔
    }
}

3. 離線網絡隊列 (FIFO,斷網重發)


public class OfflineQueue {
    private static final String QUEUE_STORE = "NetQueue";

    public void enqueue(NetworkRequest req) {
        RecordStore rs = null;
        try {
            rs = RecordStore.openRecordStore(QUEUE_STORE, true);
            rs.addRecord(req.toBytes(), 0, req.toBytes().length);
        } catch (RecordStoreException e) { /* 處理 */ }
        finally { if (rs != null) try { rs.closeRecordStore(); } catch (Exception ignored) {} }
    }

    public NetworkRequest dequeue() {
        try {
            RecordStore rs = RecordStore.openRecordStore(QUEUE_STORE, false);
            RecordEnumeration re = rs.enumerateRecords(null, null, false); // FIFO
            if (re.numRecords() > 0) {
                int id = re.nextRecordId();
                byte[] data = rs.getRecord(id);
                rs.deleteRecord(id);
                rs.closeRecordStore();
                return NetworkRequest.fromBytes(data);
            }
        } catch (RecordStoreException ignored) {}
        return null;
    }
}

效能與限制必知

指標典型限制應對
單一 RecordStore 大小64KB - 512KB (視裝置)分檔存儲、壓縮資料、定期清理
單筆記錄大小通常無硬性限制,但建議 < 4KB大資料分片、外部存儲 (JSR 75)
開啟/關閉開銷較大 (涉及檔案系統)批次操作時保持開啟、單例模式管理
執行緒安全RecordStore 方法同步,但枚舉器非線程安全單執行緒訪問或自行同步
原子性單一 add/set/delete 原子,多操作非事務關鍵業務用臨時檔+重命名模擬事務

最佳實踐清單

  1. ✅ 統一用 DataOutputStream.writeUTF/readUTF 處理中文 (見文章 77945)。
  2. ✅ 記錄類實作 toBytes()/fromBytes() 封裝序列化邏輯。
  3. ✅ DAO 類封裝 RecordStore 操作,業務層零 RMS 依賴。
  4. ✅ 異常統一轉換為 RuntimeException 或布林返回,避免 checked exception 汙染業務碼。
  5. ✅ 關鍵操作 (存檔、高分) 呼叫 RecordStore.closeRecordStore() 確保落盤。
  6. ✅ 定期 RecordStore.getSize()/getSizeAvailable() 監控空間,預警清理。
  7. ✅ 真機測試不同品牌/機型 RMS 行為差異 (Nokia 限制較嚴、Motorola 較寬)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved