MIDlet 生命週期中,startApp() 可能多次被呼叫(每次從 Paused 回 Active 都會觸發)。單次初始化邏輯應置於建構子,而非 startApp()。
// TimerTask:喚醒 MIDlet
public class LifeCycleTask extends TimerTask {
private MIDlet midlet;
public LifeCycleTask(MIDlet m) { this.midlet = m; }
public void run() { midlet.resumeRequest(); }
}
// 主 MIDlet
public class LifeCycleTest extends MIDlet {
private Timer timer = new Timer();
private LifeCycleTask task;
public void startApp() {
System.out.println("startApp Executes");
Display.getDisplay(this).setCurrent(new Form("Test"));
try { Thread.sleep(2000); } catch (Exception e) {}
System.out.println("Ready to paused");
task = new LifeCycleTask(this);
timer.schedule(task, 4000); // 4 秒後喚醒
notifyPaused(); // 主動進入 Paused 狀態
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {
timer.cancel();
}
}
startApp Executes
Ready to paused
startApp Executes
Ready to paused
startApp Executes
Ready to paused
...
畫面在主表單與選單間切換。每次喚醒皆觸發 startApp()。
Timer 放建構子(單次建立),TimerTask 放 startApp() 重新建立(因 TimerTask 單次排程,cancel() 後才能重排)notifyPaused() 主動釋放控制權,resumeRequest() 請求恢復 Active嘗試在 run() 中呼叫 timer.cancel() 會導致競態條件:cancel() 等待 run() 結束,但 startApp() 可能在 cancel() 完成前執行到 schedule(),拋出例外。文中範例用 Thread.sleep() 降低機率,但非安全寫法。
安全做法:每次 startApp() 新建 TimerTask,或使用獨立旗標協調,避免在 run() 中操作 Timer。