星期六, 9月 17, 2011

Service(五)

Android應用程式學習筆記

Service(五)

繼續service(四)的內容,上次的內容提到要實現started類型的service可以繼承IntentService類型,今天繼續學習另外一種方式,繼承Service類別實現started類型的service。

Extending the Service class
從service(四)我們學習到使用IntentService類別實現started service相當容易,然而,如果你需要你的service能執行多執行續(取代通過工作佇列處理啟動請求),那妳可以繼承Service類別來處理Intent物件。

為了有所比較,以下的例子所執行的內容與繼承IntentService所執行的內容是一樣的,對於餒個啟動請求,它使用一個worker thread執行工作且每一次只處理一個請求。


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()的工作,你可以同時處理多個請求。但是,如果你想的話,你可以為每個請求產生一個執行續,並立即運行(取代必須等待前一個請求完成),不過我們的例子不是要實現這樣的功能。

接下來注意到onStartConmmand()回傳了一個整數,該整數表示系統是否在事件被系統殺掉後還要繼續事件中的service。onStartCommand()回傳的職必須式以下值的其中之一。

START_NOT_STICKY
如果在onStartCommand()回傳之後系統銷毀Service,系統不去重建Service,除非有intent物件等待傳送。這是最安全的方式能避免在不需要的情況下以及在你的應用程式重啟未完成的工作時執行你的Service。
START_STICKY
如果在onStartCommand()回傳之後系統銷毀Service,系統重建Service並且呼叫onStartCommand()方法,但不會重新接收最後的intent,系統以null intent呼叫onStartCommand()方法,除非有等待的intent去啟動service,在這樣的例子中,那些intent會被傳送。如此方式適合媒體播放器,不執行命令時,就無限地運行並等待工作。
START_REDELIVER_INTENT
如果在onStartCommand()回傳之後系統銷毀Service,系統重建Service並且以最後的intent物件呼叫onStartCommand(0方法傳送到Serivce。任何等待的intent物件都依次被傳送。

Starting a Service
你可以從activities或其他應用程式組件透過傳遞intent給startService()方法啟動Service,android系統會呼叫onStartCommand()方法並將intent物件傳遞送給它。

例子


Intent intent = new Intent(this, HelloService.class);
startService(intent);

startService()立即回傳且系統呼叫service的onStartCommand(0方法,如果service是第一次被呼叫,系統會先呼叫onCreate(0方法,再呼叫onStartCommand()方法。

如果service沒有提供綁定的功能,以startService()傳遞intent物件是應用程式組件與service之間通訊的唯一方式。然而,如果你想要你的service傳回結果,那麼啟動service的客戶端能為一個廣播(getBroadcast()產生一個broadcast物件)產生PendingIntent,且夾帶在啟動service的intent物件中傳送到service,該service就能用broadcast來傳遞結果。

許多請求能啟動service並導致許多回應呼叫onStartCommand()方法,然而,只有stopself()方法或者stopService()方法的請求能停止servixe。

Stopping a Service
started類型的service必須管理自己生命週期,系統不會停止或銷毀service除非系統必須回收記憶體和在onStartCommand()回傳後service繼續運行。所以,service可以呼叫stopSelf()方法停止service,或者其他應用程式組件呼叫stopService()方法來停止service。

一旦以stopslef()或stopService()來請求停止,系統就會盡可能快的銷毀service。

沒有留言:

張貼留言