J2SE 1.3 引入 java.util.Timer/TimerTask,MIDP 同步納入,讓 J2ME 開發者擁有背景執行緒排程能力,無需手寫執行緒管理。
| 類別 | 角色 |
|---|---|
TimerTask | 抽象基類,實作 Runnable,開發者繼承並實作 run() |
Timer | 排程器,內部維護單一背景執行緒,負責建立/管理任務執行 |
import java.util.*;
public class MyTask extends TimerTask {
public void run() {
System.out.println("Running the task");
}
}
注意:每個Timer同一時間只能執行一個任務,run()必須**快速結束**,避免阻塞後續任務。
Timer timer = new Timer();
TimerTask task = new MyTask();
// 10 秒後執行一次
timer.schedule(task, 10000);
// 5 秒後首次執行,之後每 10 秒重複
timer.schedule(task, 5000, 10000);
// 指定時間點執行
timer.schedule(task, new Date(System.currentTimeMillis() + 10000));
// 固定頻率 (以首次執行時間為基準校正漂移)
timer.scheduleAtFixedRate(task, 5000, 10000);
task.cancel():取消單一任務 (可在任務內部呼叫自殺)timer.cancel():終止 Timer 背景執行緒,**不可恢復**,需重新 new Timer()Timer 內部同步處理,多執行緒環境可直接呼叫其方法,無需額外同步。
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;
public class TimerDemo extends MIDlet {
private Display display;
private StarField field = new StarField();
private FieldMover mover = new FieldMover();
private Timer timer = new Timer();
public TimerDemo() {
display = Display.getDisplay(this);
}
protected void destroyApp(boolean unconditional) {}
protected void pauseApp() {}
protected void startApp() {
display.setCurrent(field);
timer.schedule(mover, 100, 100); // 100ms 間隔重複執行
}
public void exit() {
timer.cancel(); // 停止滾動
destroyApp(true);
notifyDestroyed();
}
class FieldMover extends TimerTask {
public void run() {
field.scroll();
}
}
class StarField extends Canvas {
private int height, width;
private int[] stars;
private Random random = new Random();
private boolean painting = false;
public StarField() {
height = getHeight();
width = getWidth();
stars = new int[height];
for (int i = 0; i < height; i++) stars[i] = -1;
}
public void scroll() {
if (painting) return;
for (int i = height - 1; i > 0; i--) {
stars[i] = stars[i - 1];
}
stars[0] = (random.nextInt() % (3 * width)) / 2;
if (stars[0] >= width) stars[0] = -1;
repaint();
}
protected void paint(Graphics g) {
painting = true;
g.setColor(0, 0, 0);
g.fillRect(0, 0, width, height);
g.setColor(255, 255, 255);
for (int y = 0; y < height; y++) {
int x = stars[y];
if (x == -1) continue;
g.drawLine(x, y, x, y); // 畫點
}
painting = false;
}
protected void keyPressed(int keyCode) {
exit(); // 任意鍵退出
}
}
}
Timer,所有週期性任務共用repaint(),實際繪製交給事件執行緒scroll() 與 paint() 並發存取 stars 陣列exit() 中呼叫 timer.cancel() 確保背景執行緒正常終止Timer 將「時間」維度從業務邏輯中剝離,讓開發者以宣告式方式描述排程需求,是 J2ME 開發中被低估卻極實用的工具類。