MIDP UI 採事件回調機制:系統 UI 線程維護組件,開發者註冊 CommandListener,事件觸發時回調 commandAction()。處理簡單的「是/否」確認對話框時,不得不:
if-else 判斷來源,邏輯碎片化期望體驗:像 Win32 DialogBox() 一樣阻塞當前線程,同步等待返回值:
int choice = Dialog.show("確認退出?", Dialog.YES_NO);
if (choice == Dialog.YES) { exitGame(); }
else { resumeGame(); }
// 代碼連貫、邏輯內聚
| 難點 | 解決方案 |
|---|---|
| 不能阻塞系統 UI 線程 | 將所有遊戲邏輯移至獨立工作線程,UI 線程僅負責渲染/轉發事件 |
| 工作線程如何等待用戶輸入 | 引入信號量(boolean flag = false)+ wait()/notifyAll() 機制 |
public class SyncDialog {
private static final int YES = 1, NO = 0, CANCEL = -1;
private int result = CANCEL;
private boolean ready = false;
private final Object lock = new Object();
// 由 UI 線程調用:顯示對話框並註冊臨時 Listener
public void show(final Display display, final String title, final int type) {
// 必須在 UI 線程執行
Display.getDisplay(midlet).callSerially(new Runnable() {
public void run() {
Form form = new Form(title);
if ((type & YES) != 0) form.addCommand(new Command("是", Command.OK, 1));
if ((type & NO) != 0) form.addCommand(new Command("否", Command.NO, 2));
form.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c.getCommandType() == Command.OK) result = YES;
else if (c.getCommandType() == Command.NO) result = NO;
else result = CANCEL;
synchronized (lock) { ready = true; lock.notifyAll(); }
}
});
display.setCurrent(form);
}
});
}
// 由工作線程調用:阻塞等待結果
public int waitForResult() throws InterruptedException {
synchronized (lock) {
while (!ready) lock.wait(); // 釋放鎖並進入等待
}
return result;
}
}
public class GameThread extends Thread {
private SyncDialog dialog = new SyncDialog();
private Display display;
public void run() {
// ... 遊戲循環 ...
if (playerHitsExit()) {
// 同步彈窗,不阻塞 UI 線程
dialog.show(display, "確定退出?", SyncDialog.YES | SyncDialog.NO);
int choice = dialog.waitForResult(); // 當前線程掛起
if (choice == SyncDialog.YES) {
saveAndExit();
}
// 否則繼續遊戲循環
}
}
}
callSerially() 確保對話框創建在系統 UI 線程,不違反 MIDP 單線程 UI 規則。wait() 釋放 CPU,不佔用資源;用戶點擊後 notifyAll() 喚醒。result + ready 雙變量避免虛假喚醒競態。將上述模式封裝為 SyncUI 工具類,提供:
confirm(title) → booleaninput(title, defaultText) → Stringselect(title, String[] options) → intprogress(title, max) → ProgressHandle(支援取消)所有方法內部均採用「UI 線程創建組件 + 工作線程 wait()」模式,業務代碼保持同步寫法,極大降低認知負荷。
waitForResult(),會導致死鎖(UI 線程自己等待自己永遠不會發出的通知)。paint() 中維持幀更新,僅邏輯線程阻塞。ready 標誌正確重置。