J2ME 應用由應用管理軟體 (AMS/JAM) 控制生命週期,包含三種狀態:
startApp() 被呼叫後進入,正常執行中。destroyApp() 完成後進入,資源釋放完畢。| 事件 | 呼叫順序 | 說明 |
|---|---|---|
| 啟動應用 | 建構子 → startApp() | 建構子只執行一次,適合放一次性初始化 |
| 來電/切換到系統選單 | hideNotify() → pauseApp() | 畫面隱藏、進入暫停 |
| 掛斷/返回應用 | showNotify() → paint() → startApp() | 注意:startApp() 會被重複呼叫! |
錯誤寫法:在 startApp() 中 new MyCanvas(),導致每次回來都建立新 Canvas,舊資源洩漏、遊戲狀態重置。
正確寫法一:建構子初始化
public class MyMIDlet extends MIDlet {
Display display;
MyCanvas canvas;
public MyMIDlet() {
display = Display.getDisplay(this);
canvas = new MyCanvas(); // 僅一次
}
public void startApp() {
display.setCurrent(canvas); // 僅設定顯示
}
// ...
}
正確寫法二:延遲初始化 + 旗標
public void startApp() {
if (display == null) { // 首次才執行
display = Display.getDisplay(this);
canvas = new MyCanvas();
}
display.setCurrent(canvas);
}
showNotify() → paint() → 執行緒 run() 開始。hideNotify() → pauseApp()。執行緒 仍在運行(除非你自行停止),但 repaint() 不會觸發 paint()。showNotify() → paint()(系統自動呼叫一次) → startApp()。標準遊戲迴圈範例:
public void run() {
while (running) {
try { Thread.sleep(50); } catch (Exception e) {}
repaint(); // 排程重繪
}
}
許多開發者為了效能,將 paint(Graphics g) 傳入的 Graphics 參考存入成員變數 mg,並在輔助繪圖方法中直接使用 mg.drawString(...)。這在 Nokia 7610、6600 等機型上會導致來電歸來後死機或畫面錯亂。
Graphics mg; // 成員變數
public void paint(Graphics g) {
mg = g; // 危險!g 可能在下次 paint 失效
drawMenu();
drawGame();
}
void drawMenu() { mg.drawString(...); } // 直接用 mg
public void paint(Graphics g) {
drawMenu(g);
drawGame(g);
}
void drawMenu(Graphics g) { g.drawString(...); }
void drawGame(Graphics g) { g.drawString(...); }
public void paint(Graphics g) {
if (mg == null) mg = g; // 僅首次指派
// 但仍有風險:系統可能回收舊 Graphics 實例
// 最佳做法仍是參數傳遞
}
若需在事件執行緒中安全更新 UI,可使用 display.callSerially(this) 並實作 Runnable.run(),系統會在下一次繪製迴圈前執行,避免多執行緒競爭。
startApp() 僅 setCurrent()。Graphics 參數,嚴禁 快取 Graphics 實例。repaint() 排程重繪,不直接呼叫 paint()。pauseApp() 暫停邏輯/音效;destroyApp() 釋放資源、停止執行緒。遵循上述原則,可徹底解決來電/切換應用導致的死機與畫面異常。