繼承IntentService類來實現一個被啟動類型的服務很簡單,但是如果你需要服務執行多線程(而不是通過工作隊列來處理啟動請求),那麼你就要繼承Service類來處理每個Intent。
為便於比較,下面例子中,Service類的實現代碼執行了與之前“繼承IntentService類”一節中的例子相同的工作,也就是說,對於每個啟動請求,它都會使用一個背景工作執行緒來執行工作,並且每次只處理一個請求。
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
正如你看到的,它要比繼承IntentService類多做很多工作。
但是,因為你自己處理每個onStartCommand()方法的調用,你就能夠同時執行多個請求。在上面的例子中沒有這麼做,但是如果你想要這麼做的話,那麼你就能夠給每個請求建立一個新的線程,並且立即運行它們(而不是等待前一個請求完成)。
注意:onStartCommand()方法必須返回一個整數,這個整數是一個描述了在系統的殺死事件中,系統應該如何繼續這個服務的值(雖然你能夠修改這個值,但是IntentService處理還是為你提供了預設實現)。從onStartCommand()方法中返回的值必須是以下常量:
START_NOT_STICKY
如果系統在onStartCommand()方法返回之後殺死這個服務,那麼直到接受到新的Intent對象,這個服務才會被重新建立。這是最安全的選項,用來避免在不需要的時候運行你的服務。
START_STICKY
如果系統在onStartCommand()返回後殺死了這個服務,系統就會重新建立這個服務並且調用onStartCommand()方法,但是它不會重新傳遞最後的Intent對象,系統會用一個null的Intent對象來調用onStartCommand()方法,在這個情況下,除非有一些被發送的Intent對象在等待啟動服務。這適用於不執行命令的媒體播放器(或類似的服務),它只是無限期的運行著並等待工作的到來。
START_REDELIVER_INTENT
如果系統在onStartCommand()方法返回後,系統就會重新建立了這個服務,並且用發送給這個服務的最後的Intent對象調用了onStartCommand()方法。任意等待中的Intent對象會依次被發送。這適用於那些應該立即恢複正在執行的工作的服務,如下載檔案。