J2ME RecordStore 僅提供位元組陣列 byte[] 的增刪改查,開發者需自行處理:
DataInput/OutputStream)本文展示一套生產級封裝模式:BaseRMS 抽象基類 + Score 具體實現,解決上述所有痛點。
abstract public class BaseRMS {
private String rmsName;
private RecordStore recordStore;
BaseRMS(String rmsName) { this.rmsName = rmsName; }
// 開啟:失敗則重建,有資料則載入,無則建立預設
public void open() throws Exception {
try {
recordStore = RecordStore.openRecordStore(rmsName, true);
if (recordStore.getNumRecords() > 0) loadData();
else createDefaultData();
} catch (Exception e) { throw new Exception(rmsName + "::open::" + e); }
}
public void close() throws Exception {
if (recordStore != null) {
try { recordStore.closeRecordStore(); }
catch (Exception e) { throw new Exception(rmsName + "::close::" + e); }
}
}
public RecordStore getRecordStore() { return recordStore; }
public String getRMSName() { return rmsName; }
// 子類必須實現:序列化/反序列化/預設值
abstract void loadData() throws Exception;
abstract void createDefaultData() throws Exception;
abstract void updateData() throws Exception;
}
open() 定義標準流程,子類只關心資料邏輯。Exception 並附帶 rmsName::method::cause,除錯極易定位。close() 防禦性檢查 null,避免重複關閉崩潰。String[3] names、int[3] valuespublic class Score extends BaseRMS {
// 載入:遍歷 3 筆記錄,DataInputStream 讀 int + UTF
protected void loadData() throws Exception {
for (int i=0; i= values[i]) {
open();
for (int j=names.length-1; j>i; j--) {
values[j] = values[j-1];
names[j] = names[j-1];
}
values[i] = score; names[i] = name;
updateData(); close(); break;
}
}
}
public boolean isHighScore(int score) throws Exception {
for (int v : values) if (score >= v) return true;
return false;
}
public void reset() throws Exception { open(); initValues(); updateData(); close(); }
}
| 陷阱 | 對策 |
|---|---|
readUTF() 要求修改版 UTF-8,寫入必須用 writeUTF() | 嚴格配對 DataOutputStream.writeUTF / DataInputStream.readUTF |
| 記錄長度不固定(字串長度可變) | ByteArrayOutputStream 動態擴容,toByteArray() 取實際長度 |
| 記錄 ID 從 1 非 0 開始 | 迴圈 i+1 存取 |
| 並發存取可能損壞資料 | 單執行緒遊戲通常無慮;若多 MIDlet 共享,需外部 synchronized |
作者提到:「遊戲設定本質相同,派生 GameOption extends BaseRMS,啟動時 open() 載入即可」。例如:
class GameOption extends BaseRMS {
boolean soundOn, vibrationOn; int difficulty;
protected void loadData() { ... read boolean/int ... }
protected void createDefaultData() { soundOn=true; vibrationOn=true; difficulty=1; ... }
protected void updateData() { ... write boolean/int ... }
// 對外 getter/setter
}
MIDlet-Data-Size: 8192 // 最小需求 8KB,安裝時裝置會檢查可用空間
MIDlet-1: RMSAnalyzer,,RMSAnalyzer
MicroEdition-Profile: MIDP-1.0
注意: 實際可用空間常大於宣告值,但宣告過大會導致安裝失敗,建議實測目標機型後留 20% 餘量。
javax.microedition.rms + java.io,無第三方庫。BaseRMS 實現三個 abstract 方法。此模式在 Android SharedPreferences、iOS UserDefaults、現代 KV 存儲中依然適用:定義協議、隔離序列化、統一錯誤處理。