MIDlet 生命周期是 J2ME 開發的核心基礎,理解三大核心方法 startApp()、pauseApp()、destroyApp(boolean) 的調用時機、狀態流轉與異常處理,對編寫穩健的移動應用至關重要。本文提供完整的狀態機模型、測試代碼與模擟器實操驗證步驟。
┌──────────────────┐
│ 構造函數 │
│ (對象創建) │
└────────┬─────────┘
│
▼
┌──────────────────┐
┌─────────►│ Paused 狀態 │◄─────────┐
│ │ (初始/暫停/就緒) │ │
│ └────────┬─────────┘ │
│ │ │
│ startApp() │ pauseApp() │ destroyApp(true)
│ ▼ │
│ ┌──────────────────┐ │
│ │ Active 狀態 │ │
└─────────┤ (運行/顯示/交互) │──────────┘
└────────┬─────────┘
│
destroyApp(false/true)
▼
┌──────────────────┐
│ Destroyed 狀態 │
│ (資源釋放/終結) │
└──────────────────┘
| 方法 | 調用方 | 典型觸發場景 | 開發者職責 | 異常處理 |
|---|---|---|---|---|
| 構造函數 | AMS | 應用首次啟動 | 輕量級初始化,不可阻塞 | 拋出異常 → 應用啟動失敗 |
| startApp() | AMS | 啟動、從 Paused 恢復、來電結束 | 獲取資源、啟動線程、顯示 UI、註冊監聽 | 拋出 MIDletStateChangeException 通知 AMS 失敗 |
| pauseApp() | AMS | 來電、短信、用戶切換應用、鎖屏 | 釋放獨佔資源(攝像頭/GPS/網絡連接)、暫停動畫/線程、保存狀態 | 不應拋出異常,必須快速返回 |
| destroyApp(boolean unconditional) | AMS | 用戶退出、系統回收內存、更新覆蓋 | 釋放所有資源、關閉連接、停止線程、持久化關鍵數據 | unconditional=true 必須銷毀;false 可拋 MIDletStateChangeException 拒絕 |
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class LifeCycleDemoMIDlet extends MIDlet implements CommandListener {
private Display display;
private Form mainForm;
private Command cmdExit, cmdPause, cmdResume;
private int startCount = 0, pauseCount = 0, destroyCount = 0;
public LifeCycleDemoMIDlet() {
System.out.println("[構造函數] MIDlet 實例化");
display = Display.getDisplay(this);
mainForm = new Form("生命周期測試");
mainForm.append("查看控制台輸出觀察生命周期調用順序\n");
cmdExit = new Command("退出", Command.EXIT, 1);
cmdPause = new Command("模擬暫停", Command.SCREEN, 2);
cmdResume = new Command("模擬恢復", Command.SCREEN, 3);
mainForm.addCommand(cmdExit);
mainForm.addCommand(cmdPause);
mainForm.addCommand(cmdResume);
mainForm.setCommandListener(this);
}
protected void startApp() throws MIDletStateChangeException {
startCount++;
System.out.println("[startApp] 第 " + startCount + " 次調用 - 進入 Active 狀態");
mainForm.append("▶ startApp() 調用 #" + startCount + "\n");
display.setCurrent(mainForm);
// 實際應用:啟動業務線程、網絡連接、定時器等
}
protected void pauseApp() {
pauseCount++;
System.out.println("[pauseApp] 第 " + pauseCount + " 次調用 - 進入 Paused 狀態");
mainForm.append("❚❚ pauseApp() 調用 #" + pauseCount + "\n");
// 實際應用:釋放資源、暫停線程
}
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
destroyCount++;
System.out.println("[destroyApp] 第 " + destroyCount + " 次調用 - unconditional=" + unconditional);
mainForm.append("■ destroyApp(" + unconditional + ") 調用 #" + destroyCount + "\n");
// 實際應用:清理所有資源
if (!unconditional) {
// 可選:詢問用戶是否保存未完成數據,拋出異常取消銷毀
// throw new MIDletStateChangeException("用戶取消退出");
}
}
public void commandAction(Command c, Displayable d) {
if (c == cmdExit) {
notifyDestroyed(); // 主動請求銷毀
} else if (c == cmdPause) {
// 手動觸發暫停 (模擬 AMS 行為)
System.out.println("[手動] 調用 pauseApp()");
pauseApp();
} else if (c == cmdResume) {
System.out.println("[手動] 調用 startApp()");
try { startApp(); } catch (MIDletStateChangeException e) { e.printStackTrace(); }
}
}
}
[構造函數] → [startApp] #1[pauseApp] #1[startApp] #2[手動] 調用 pauseApp() → [pauseApp] #2[destroyApp] #1 unconditional=false (可拒絕)[destroyApp] #1 unconditional=true (強制)pauseApp 信號暫停,可用 volatile boolean paused 標誌MIDlet 生命周期由 AMS 精確控制,開發者只需正確實現四個回調方法。通過 WTK 模擟器菜單「暫停/恢復」與自定義命令測試,可完整驗證狀態流轉邏輯。掌握「構造→啟動↔暫停→銷毀」閉環,做好資源獲取與釋放的對稱管理,是編寫穩定 J2ME 應用的基石。