J2ME 單文件寫法雖簡潔,但隨著界面增多、邏輯複雜,「上帝類」 MIDlet 會變得不可維護。將 MIDlet (應用控制器) 與 Displayable (視圖) 分離,遵循 MVC 思想,帶來:
Display,自行 setCurrent() 或由 MIDlet 統一分發。midlet.quitApp() / midlet.showSettings() 等。package testmidlet;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class TestMIDlet extends MIDlet {
private static TestMIDlet instance;
private LoginForm loginForm;
public TestMIDlet() {
instance = this;
loginForm = new LoginForm(this); // 注入自身引用
}
protected void startApp() {
Display.getDisplay(this).setCurrent(loginForm);
}
protected void pauseApp() {}
protected void destroyApp(boolean u) {}
/** 供視圖調用的退出入口 */
public static void quitApp() {
instance.destroyApp(true);
instance.notifyDestroyed();
instance = null; // 釋放單例引用
}
/** 導航到其他界面 */
public void showMainMenu() {
Display.getDisplay(this).setCurrent(new MainMenuForm(this));
}
}
package testmidlet;
import javax.microedition.lcdui.*;
public class LoginForm extends Form implements CommandListener {
private TestMIDlet midlet;
public LoginForm(TestMIDlet midlet) {
super("Login");
this.midlet = midlet;
append(new TextField("User:", "", 20, TextField.ANY));
append(new TextField("Pass:", "", 20, TextField.PASSWORD));
addCommand(new Command("Login", Command.OK, 1));
addCommand(new Command("Exit", Command.EXIT, 2));
setCommandListener(this);
}
public void commandAction(Command c, Displayable d) {
if (c.getCommandType() == Command.OK) {
// 驗證邏輯...
midlet.showMainMenu(); // 導航
} else if (c.getCommandType() == Command.EXIT) {
TestMIDlet.quitApp(); // 退出
}
}
}
當界面超過 5 個時,建議引入 Navigator 統一管理:
public class Navigator {
private static Display display;
private static Displayable previous;
public static void init(MIDlet midlet) {
display = Display.getDisplay(midlet);
}
public static void go(Displayable next) {
previous = display.getCurrent();
display.setCurrent(next);
}
public static void back() {
if (previous != null) display.setCurrent(previous);
}
}
// 視圖中調用:Navigator.go(new SettingsForm()); Navigator.back();
| 要點 | 做法 | 收益 |
|---|---|---|
| MIDlet 不持有具體 UI 類 | 依賴接口或基類 Displayable | 解耦,易測試 |
| 視圖不直接操作生命週期 | 調用 MIDlet 封裝方法 quitApp() | 集中控制,避免重複代碼 |
| Display 獲取集中化 | Display.getDisplay(midlet) 僅在 MIDlet/Navigator 中調用 | 避免傳遞錯誤的 MIDlet 引用 |
| 單例 MIDlet 謹慎使用 | 僅作為靜態工廠入口,退出時置 null | 防止內存洩漏,允許重啟 |
「MIDlet 做調度,UI 做渲染與交互」,這條分界線劃清後,代碼結構清晰、擴展性強。即使專案微小,養成分離習慣也能避免日後重構之痛。