RMS (Record Management System) 是 J2ME (MIDP) 提供的持久化儲存機制,類似輕量級資料庫。每個 MIDlet 套件 (JAR) 擁有獨立命名空間的記錄存儲 (RecordStore),每筆記錄包含 recordId (int) 與 data (byte[]) 兩欄。本文詳細說明 RMS 核心 API、操作流程與遊戲最高分儲存實戰。
recordId (int):自動遞增主鍵,從 1 開始data (byte[]):任意二進位資料,開發者自行序列化/反序列化| 方法 | 說明 |
|---|---|
openRecordStore(name, createIfNecessary) | 開啟/建立記錄存儲,傳回 RecordStore 實例 |
getNumRecords() | 取得記錄筆數 |
getRecordSize(recordId) | 取得指定記錄資料大小 (bytes) |
getRecord(recordId, buffer, offset) | 讀取記錄到位元組陣列,傳回實際讀取長度 |
getRecord(recordId) | 直接傳回記錄資料位元組陣列 (較簡便) |
addRecord(data, offset, numBytes) | 新增記錄,傳回新 recordId |
setRecord(recordId, data, offset, numBytes) | 更新指定記錄 |
deleteRecord(recordId) | 刪除單筆記錄 |
deleteRecordStore(name) | 刪除整個記錄存儲 (靜態方法) |
closeRecordStore() | 關閉記錄存儲,釋放資源 |
RecordStore rs = null;
try {
// 1. 開啟或建立 (true=不存在則建立)
rs = RecordStore.openRecordStore("HighScores", true);
// 2. 讀寫操作...
} catch (Exception e) {
// 錯誤處理
} finally {
// 3. 一定要關閉
if (rs != null) {
try { rs.closeRecordStore(); } catch (Exception ignore) {}
}
}
RMS 僅儲存 byte[],基本型別需手動轉換:
// 寫入單一 int 分數
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(score); // 高位在前
dos.flush();
byte[] data = baos.toByteArray();
rs.addRecord(data, 0, data.length);
byte[] data = rs.getRecord(recordId);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bais);
int score = dis.readInt();
// 讀取所有記錄,反序列化為 int 陣列排序
Vector scores = new Vector();
for (int i = 1; i <= rs.getNumRecords(); i++) {
byte[] data = rs.getRecord(i);
scores.addElement(new Integer(readInt(data)));
}
// 排序、截取 Top 10、重寫整個 RecordStore
// (刪除舊存儲重建或逐筆 setRecord)
import javax.microedition.rms.*;
import java.io.*;
public class HighScoreManager {
private static final String STORE_NAME = "GameHighScores";
private static final int MAX_RECORDS = 10;
// 儲存新分數,自動維護 Top 10
public static void saveScore(int newScore) {
RecordStore rs = null;
try {
rs = RecordStore.openRecordStore(STORE_NAME, true);
// 讀取現有分數
Vector scores = new Vector();
for (int i = 1; i <= rs.getNumRecords(); i++) {
scores.addElement(new Integer(readInt(rs.getRecord(i))));
}
// 插入新分數並排序 (降冪)
scores.addElement(new Integer(newScore));
// 簡易排序...
// 只保留前 10
while (scores.size() > MAX_RECORDS) {
scores.removeElementAt(scores.size() - 1);
}
// 重寫存儲:刪除舊記錄、重新寫入
// 策略:刪除整個存儲重建 (最簡單)
rs.closeRecordStore();
RecordStore.deleteRecordStore(STORE_NAME);
rs = RecordStore.openRecordStore(STORE_NAME, true);
for (int i = 0; i < scores.size(); i++) {
int score = ((Integer)scores.elementAt(i)).intValue();
rs.addRecord(toByteArray(score), 0, 4);
}
} catch (Exception e) {
// 記錄錯誤
} finally {
closeQuietly(rs);
}
}
// 取得最高分陣列
public static int[] getTopScores() {
RecordStore rs = null;
Vector scores = new Vector();
try {
rs = RecordStore.openRecordStore(STORE_NAME, false); // 不建立
if (rs != null) {
for (int i = 1; i <= rs.getNumRecords(); i++) {
scores.addElement(new Integer(readInt(rs.getRecord(i))));
}
}
} catch (Exception e) {
} finally {
closeQuietly(rs);
}
int[] result = new int[scores.size()];
for (int i = 0; i < result.length; i++) {
result[i] = ((Integer)scores.elementAt(i)).intValue();
}
return result;
}
// 工具方法
private static byte[] toByteArray(int value) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(value);
return baos.toByteArray();
}
private static int readInt(byte[] data) throws IOException {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data));
return dis.readInt();
}
private static void closeQuietly(RecordStore rs) {
if (rs != null) try { rs.closeRecordStore(); } catch (Exception ignore) {}
}
}
getNumRecords() 可能小於最大 IDRecordStoreException、RecordStoreFullException、RecordStoreNotFoundException,必須捕獲RMS 是 J2ME 遊戲持久化儲存的標準方案。掌握 RecordStore 生命週期管理、位元組陣列序列化、記錄增刪改查核心流程,即可實作最高分、遊戲進度、設定檔等儲存需求。注意資源釋放與異常處理,確保在受限裝置上穩定運行。