從類Service派生
如你在上節所見,使用類IntentService使得你實現一個"開始的"service非常容易.然而,如果你需要你的service以多線程方式執行(而不是使用工作隊列),那麼你需要從類Service派生來處理每個intent.
相比之下,下面的例子從類Service派生並實現了與上面使用IntentService例子完全相同的工作.也就是在一個線程中序列化的處理每個"開始"請求.
public class HelloService extends Service {<br /> private Looper mServiceLooper;<br /> private ServiceHandler mServiceHandler;</p><p> // 處理從線程收到的訊息們<br /> private final class ServiceHandler extends Handler {<br /> public ServiceHandler(Looper looper) {<br /> super(looper);<br /> }<br /> @Override<br /> public void handleMessage(Message msg) {<br /> // 通常我們在這裡做一些工作比如下載一個檔案<br /> // 在我們的例子中,僅僅是睡5秒鐘.<br /> long endTime = System.currentTimeMillis() + 5*1000;<br /> while (System.currentTimeMillis() < endTime) {<br /> synchronized (this) {<br /> try {<br /> wait(endTime - System.currentTimeMillis());<br /> } catch (Exception e) {<br /> }<br /> }<br /> }<br /> // 使用startId停止服務,從而使我們不會在處理<br /> // 另一個工作的中間停止service<br /> stopSelf(msg.arg1);<br /> }<br /> }</p><p> @Override<br /> public void onCreate() {<br /> // 啟動運行service的線程.注意我建立了一個<br /> // 分離的線程,因為service通常都是在進程的<br /> // 主線程中運行,但我們不想讓主線程阻塞.我們還把新線程<br /> // 搞成後台級的優先順序,從而減少對UI線程(主線程的影響).<br /> HandlerThread thread = new HandlerThread("ServiceStartArguments",<br /> Process.THREAD_PRIORITY_BACKGROUND);<br /> thread.start();</p><p> // Get the HandlerThread's Looper and use it for our Handler<br /> mServiceLooper = thread.getLooper();<br /> mServiceHandler = new ServiceHandler(mServiceLooper);<br /> }</p><p> @Override<br /> public int onStartCommand(Intent intent, int flags, int startId) {<br /> Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();</p><p> // 對於每個開始請求,發送一訊息來開始一次工作,並且把<br /> // start ID也傳過去,所以當完成一個工作時,我們才知道要停止哪個請求.<br /> Message msg = mServiceHandler.obtainMessage();<br /> msg.arg1 = startId;<br /> mServiceHandler.sendMessage(msg);</p><p> // 如果我們在這裡返回後被被殺死了,重啟之.<br /> return START_STICKY;<br /> }</p><p> @Override<br /> public IBinder onBind(Intent intent) {<br /> // We don't provide binding, so return null<br /> return null;<br /> }</p><p> @Override<br /> public void onDestroy() {<br /> Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();<br /> }<br />}<br />
如你所見,要做的工作比使用IntentService時多一些.
然而,因為你自己處理每次對onStartCommand()的調用,你可以同時執行多個請求.這個例子並沒有那樣做,但是如果那是你所需要的,那麼你可以為每個請求建立一個新的線程並且立即運行它們(而不是等待上一個請求完成).
注意方法onStartCommand()必須返回一個整數.這個整數描述了在系統殺死它的事件中系統如何繼續這個服務(如前面所述,IntentService的預設實現為你處理這些,當然你也能夠去改寫它).onStartCommand()也傳回值必須是下面常量之一:
START_NOT_STICKY
如果系統在onStartCommand()返回後殺死了服務,不要重新建立這個service,除非還有掛起的intent需要被傳送.這是避免在不必要時運行你的service和當你的應用可以簡單重啟任何未竟的工作時的最佳選擇.
START_STICKY
如果系統在onStartCommand()返回後殺死了這個service,會重新建立這個service並且調用onStartCommand(),但是不再重新發送上次最後一個intent,而是使用一個nullintent調用onStartCommand(),除非有一些掛起的intent,在此情況下,這些掛起的intent被派送.這適合於媒體播放器(or或相似也的服務),它不執行命令,但是無限期的運行並等待一個工作.
START_REDELIVER_INTENT
如果系統在onStartCommand()返回後殺死了service,重新建立這個service並且使用上次最後一個intent調用onStartCommand().任何掛起的intent都順序地被派送.這適合於活躍地執行一個工作並且應被立即恢複的服務,比如下載一個檔案.