J2SE 1.3 裡有一項新的改良,那就是供給了一個可以更簡略的實現多任務調度履行的定時器類,調度由一個後台線程完成。 MIDP 同樣也包含了這一改良,使得 J2ME 開發職員從中受益。
J2ME 提示了兩個類用來定義和調試任務, 他們分辨是 TimerTask 和 Timer。TimerTask 是用戶定義的需要被調度的所有任務的抽象基類。Timer 類在任務履行的時候負責創立和治理履行線程。
要定義一個任務,定義一個 TimerTask 的子類,並實現 run 方法。例如:
import Java.util.*;
public class MyTask extends TimerTask
{
public void run()
{
System.out.println( "Running the task" );
}
}
是不是感到 run 方法很熟悉呢?那是由於 TimerTask 實現了 Java.lang.Runnable 接口。 Timer 類調用這個run 方法來履行各個任務。此外還有一點必需留心到,那就是每個 run 方法所履行的任務必需能夠盡快的終止,由於每個 Timer對象在同一時間只能履行一個任務。
定義好一個任務以後,你可以天生一個 Timer 對象並調用 schedule 方法來調度它,就像下面的代碼演示的那樣:
import Java.util.*;
Timer timer = new Timer();
TimerTask task = new MyTask();
// 在履行這個任務前等候十秒...
timer.schedule( task, 10000 );
// 在履行任務前等候十秒,然後每過十秒再履行一次
timer.schedule( task, 5000, 10000 );
schedule 方法被重載了四次;每一個任務都可以在一個特定的時間點(應用一個 Date對象指定)或者延時特定的時間段(以毫秒為單位)之後履行。你可以安排這個任務只履行一次或者在一段特定的時間段裡重復履行。Timer 還供給了一個scheduleAtFixedRate方法來根據該任務第一次履行的時間來指定重復履行時延伸的時間段。假如一個任務被延時了,被安排在後面履行的任務就被相應的縮短等候時間以“接上”被延時的任務。
每個 Timer 對象都會創立和治理一個後台線程。一般情況下,一個程序創立一個 Timer就夠了,當然也可以根據需要創立任意多個。你還可以在任何時候結束一個 Timer 並終止後台線程,方法是調用 cancel方法。但要留心的是,一旦 Timer 並終止了,就不可能再恢復履行,除非你重新天生一個 Timer 對象並重新安排你想要履行的任務。Timer對象是線程安全的,你可以在多線程的環境下直接拜訪 Timer 對象,而不用任何顯式的同步處理。
另外,每個任務供給了一個cancel 方法(持續自 TimerTask基類),你可以在任務履行的過程當中調用該方法來終止該任務。一旦你終止了該任務,那麼它將退出任務調度。你可以在任何時間調用每個任務的cancel 方法來終止該任務的履行,哪怕該任務還一次都沒有履行過。
下面供給了一個簡示的 MIDlet 示例來演示Timer 的應用,我們將利用定時器來模仿一個星空移動的後果。星星用一個點來表現,這應用到了低界圖形 API。關於低界圖形 API更具體的先容,請參考我的另一篇文章《應用 MIDP 的低界用戶界面 API》。
import Javax.microedition.midlet.*;
import Javax.microedition.lcdui.*;
import Java.util.*;
public class TimerDemo extends MIDlet
{
Display
display;
StarFIEld
field = new StarFIEld();
FieldMover mover = new FIEldMover();
Timer
timer = new Timer();
public TimerDemo()
{
display = Display.getDisplay(this);
}
protected void destroyApp(boolean unconditional)
{
}
protected void startApp()
{
display.setCurrent(fIEld);
timer.schedule(mover, 100, 100);
}
protected void pauseApp()
{
}
public void exit()
{
timer.cancel(); // stop scrolling
destroyApp(true);
notifyDestroyed();
}
class FIEldMover extends TimerTask
{
public void run()
{
fIEld.scroll();
}
}
class StarFIEld extends Canvas
{
int
height;
int
width;
int[]
stars;
Random
generator = new Random();
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] = (generator.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();
}
}
}
TimerDemo MIDlet 應用了一個 Timer 對象 timer 來調度履行一個 TimerTask 任務FieldMover,時間間隙 100 毫秒。FIEldMover處理星空的更新並重繪任務,使得全部星空不斷得往屏幕下方“延伸”。這樣就天生了一個簡略的星空移動的後果。