MIDP 引入 java.util.Timer / TimerTask(J2SE 1.3 同源),以單一後台線程調度所有任務,避免每個動畫/輪詢都開線程導致線程爆炸。本文詳解 API、陷阱、實戰模式。
| 類/方法 | 說明 |
|---|---|
Timer() | 創建調度器,內部啟動單一守護線程 |
schedule(TimerTask task, long delay) | 延遲 delay ms 執行一次 |
schedule(TimerTask task, long delay, long period) | 延遲 delay,之後每 period ms 重複(固定延遲) |
scheduleAtFixedRate(TimerTask task, long delay, long period) | 固定頻率:以首次執行時間為基準,追趕延遲 |
schedule(TimerTask task, Date time) | 指定絕對時間點執行 |
TimerTask.cancel() | 取消自身,從隊列移除 |
Timer.cancel() | 終止調度線程,清空隊列,不可重用** |
Timer 同一時刻只能執行一個任務。任務 run() 必須極快返回(< 10ms),否則阻塞後續任務,導致動畫掉幀、定時器漂移。run() 拋出未捕獲異常會導致 Timer 線程死亡,所有已排程任務永不再執行。務必在 run() 內部 try-catch 所有代碼。Timer 方法線程安全,可多線程並發 schedule。destroyApp() 時 timer.cancel()。public class TimerDemo extends MIDlet {
private Display display;
private StarField field = new StarField();
private Timer timer = new Timer();
protected void startApp() {
display = Display.getDisplay(this);
display.setCurrent(field);
// 100ms 延遲,100ms 週期 → 10 FPS
timer.schedule(new FieldMover(), 100, 100);
}
protected void destroyApp(boolean u) { timer.cancel(); notifyDestroyed(); }
protected void pauseApp() {}
// 內部任務類
class FieldMover extends TimerTask {
public void run() {
try { field.scroll(); } catch (Exception e) { e.printStackTrace(); }
}
}
// 低級 UI 繪製
class StarField extends Canvas {
int h, w; int[] stars; Random r = new Random(); boolean painting;
public StarField() {
h = getHeight(); w = getWidth();
stars = new int[h];
for (int i=0; i0; i--) stars[i] = stars[i-1];
stars[0] = (r.nextInt() % (3*w)) / 2;
if (stars[0] >= w) stars[0] = -1;
repaint(0, 0, w, h); // 部分重繪
}
protected void paint(Graphics g) {
painting = true;
g.setColor(0); g.fillRect(0,0,w,h);
g.setColor(0xFFFFFF);
for (int y=0; y
scheduleAtFixedRate,保證長期平均幀率精準(如 20 FPS = 50ms),即使單幀偶爾超時也會追趕。schedule(task, delay, period)(固定延遲),允許任務執行時間抖動,不追趕,避免擠佔 CPU。schedule(task, 5000) 替代 Thread.sleep(5000),不阻塞業務線程。timer.schedule(new OneShotTask(), 0) 立即插入;任務內 this.cancel() 自銷毀。| 現象 | 原因 | 修正 |
|---|---|---|
| 定時器停止不執行 | run() 拋出異常導致 Timer 線程死掉 | run() 內部包裹 try-catch(Exception e){log} |
| 動畫卡頓、幀率不穩 | run() 耗時 > period | 將耗時運算移至獨立線程,run() 只做狀態更新+repaint |
| 銷毀後仍收到回調 | Timer 未 cancel,任務仍在隊列 | destroyApp() 必調 timer.cancel() |
| 多 Timer 導致內存/線程洩漏 | 到處 new Timer() | 全局單例 Timer,模塊共享 |
Timer/TimerTask 是 J2ME 定時調度的標準解法:單線程、串行、輕量。核心紀律是「任務極快、異常全捕獲、統一生命週期管理」。掌握固定頻率與固定延遲的語義區別,能讓動畫流暢、輪詢穩健、資源釋放乾淨。