Develop系列-API Guides-應用組件-Services

Services

Services:可在後臺長時間運行,無UI界面。html

Started:android

Services經過其餘組件調用startService啓動,能在後臺一直運行,即便啓動它的組件已經銷燬。通常這種服務執行特定的操做並且沒有返回值,好比經過網絡下載或上傳一個文件,一旦操做結束,服務須要中止本身。安全

Bound:網絡

Service經過其餘組件調用bindService綁定,提供一個CS架構的接口容許其餘組件與Service交互、發消息、獲取返回值、甚至跨進程通訊。bound service與綁定它的組件共存亡,多個組件能夠綁定一個服務,當這個服務全部綁定它的組件都解綁後,服務會被銷燬。多線程

Caution:Service在宿主進程的主線程運行,也就是說Service不會建立本身的線程,也不會運行在另外一個進程(除非你指定)。這就意味着,若是Service執行一些高CPU負載或阻塞界面操做的任務時,你須要建立新的線程來運行它,以下降ANR的風險。架構

(使用service仍是thread?若是你只是須要在與用戶交互時,在主線程以外執行額外的任務,那麼你須要建立一個新線程而不是Service。好比在activity在前臺顯示的時候播放音樂,你須要在onCreate裏面建立線程,在onStart執行線程,在onStop裏中止線程,固然也可使用AsyncTask或者HandleThread來替代線程類。)app

基礎

建立Service的子類,覆寫Service生命週期中的關鍵回調函數,若是有必要,提供綁定Service的機制。最重要的回調函數以下:ide

onStartCommand函數

系統在其餘組件調用startService啓動Service時執行,以後,Service一直在後臺執行。若是你實現了這個方法,那麼你有責任在Service完成其工做時經過stopSelf或stopService來中止Service。(若是隻是提供綁定Service,能夠不用實現這個方法)oop

onBind

系統在其餘組件調用bindService綁定Service時執行,在這個方法的實現中,你須要返回一個IBider接口用於clients與service交互。若是你不須要綁定,能夠直接返回null

onCreate

Service第一次建立時執行,在onStartCommand和onBind以前,用於執行一次性須要初始化好的數據。

onDestroy

service銷燬時執行,用於清理資源,相似線程、註冊監聽器,receiver等。

 

系統會在低內存時強制中止service。若是service綁定在一個有用戶焦點的activity,那麼它不多會被銷燬;若是服務定義爲在前臺運行的,那麼它永遠不會被銷燬。

在manifest定義service

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

android:name是惟一必填的屬性,其餘能夠選填。一旦你的應用發佈出去了,那麼android:name永遠不要再變。

爲了安全性,請使用顯式Intent啓動或綁定服務,而不是定義filiters。若是確實容許多個服務來響應,那麼請務必在Intent中經過setPackage來指定報名,以下降目標服務匹配出意外值得機率。

設置android:exported爲false,能夠避免其餘應用啓動這個服務。

建立service

Service

全部服務的基類,若是你擴展這個類,那麼你可能須要建立一個新的線程,由於這個服務室在app的主線程中執行,有可能會下降activity的流暢度

IntentService

Service 的子類,經過工做線程來處理全部請求,每次處理一個。若是你的service不須要同時處理多個請求,IntentService是最佳的選擇。

擴展IntentService

由於大部分服務不須要同時處理多個請求(其實是個多線程場景),IntentService是最好的推薦

IntentService工做流程以下:

  • 建立一個默認的新工做線程來執行全部分發給onStartCommand的intents
  • 建立一個工做隊列來依次傳遞intent去執行onHandleIntent具體實現,因此不須要考慮多線程場景
  • 全部請求執行完以後,自動銷燬,你不須要執行stopSelf
  • 提供默認的onBind實現:直接返回null
  • 提供onStartCommand默認實現:發送intent給工做線程執行onHandleIntent實現

實際上,你須要作的就是實現onHandleIntent,以下例子:

  public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // 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) {
              }
          }
      }
  }
}

若是你須要覆寫其餘回調,好比onCreate、onStartCommand、onDestroy,請確保要調用父類的實現,這樣IntentService才能處理工做線程的生命週期。onHandleIntent和onBind是例外。

擴展Service

若是服務須要支持多線程(而不是經過工做隊列來一一處理),那麼你要擴展Service來處理每個intent。

做爲對比,以下代碼和上面代碼功能同樣。

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必須返回一個整型,這個值用來描述系統如何處理這個服務,當它被異常銷燬時。

START_NOT_STICKY

若是服務執行完onStartCommand後被異常銷燬,不須要從新建立服務,除非還有未處理的intents。避免服務被沒必要要地啓動,你的應用可以很容易地從新啓動未完成的工做,選擇這個。

START_STICKY

若是服務執行完onStartCommand後被異常銷燬,從新建立服務並執行onStartCommand,可是不會使用發給這個服務的最後一個intent,而是經過一個null intent來執行onStartCommand,除非還有未處理的intents。這種狀況比較適合不執行命令,一直在後臺運行或者等待任務的媒體播放。

START_REDELIVER_INTENT

若是服務執行完onStartCommand後被異常銷燬,從新建立服務,用發給這個服務的最後一個intent調用onStartCommand,其餘未處理的intents依次分發。這種狀況適合執行的任務須要理解恢復的場景,好比下載文件。

啓動服務

startService –> onStartCommand

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

startService方法當即返回。

若是service不能綁定,只能經過startService啓動,並且須要發送返回值時,能夠經過建立帶延遲廣播的PendingIntent(用getBroadcast)來啓動服務,服務能用裏面的廣播來分發結果。

中止服務

若是服務同步地處理多個請求,那麼不能在處理完一個請求直接銷燬,有可能其餘的請求剛發過來或者還在處理中。爲了不這種狀況,你能夠經過stopSelf(int)來確保關閉的服務就是剛處理完請求的,而不是其餘正在處理的服務,整型參數惟一標識服務實例。

建立綁定服務

詳見下一章節

發送Notifications給用戶

服務一旦運行,能夠經過Toast Notifications和Status Bar Notifications提醒用戶。

在前臺運行服務

在前臺運行的服務必須提供一個狀態欄的notification,來呈現運行狀態,除非服務被中止或者移除,不然notification不會消失。

好比:播放音樂,在狀態欄有個notification來告訴用戶當前播放的歌曲,提供用戶進入音樂播放器的入口

服務須要在前臺運行,須要調用startForground,第一個參數是notification的惟一標示(不能爲0),第一參數就是notification,好比:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

中止在前臺運行,能夠調用stopForeground。

實現生命週期回調

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Note:不須要執行父類的實現。

 

完整的生命週期:onCreate —> onDestroy

活動的生命週期:onStartCommand/onBind —> onDestroy/onUnbind

相關文章
相關標籤/搜索