4.2.0 Android四大組件之- Service概述

服務(wù)基本上分為兩種形式

  1. 啟動(dòng)

當(dāng)應(yīng)用組件(如 Activity)通過(guò)調(diào)用 startService() 啟動(dòng)服務(wù)時(shí),服務(wù)即處于“啟動(dòng)”狀態(tài)。

  1. 綁定

當(dāng)應(yīng)用組件通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int)) 綁定服務(wù)時(shí),服務(wù)即處于“綁定”狀態(tài)。
綁定服務(wù)提供了一個(gè)客戶端-服務(wù)器接口,允許組件與服務(wù)進(jìn)行交互、發(fā)送請(qǐng)求、獲取結(jié)果,甚至是利用進(jìn)程間通信 (IPC) 跨進(jìn)程執(zhí)行這些操作;僅當(dāng)與另一個(gè)應(yīng)用組件綁定時(shí),綁定服務(wù)才會(huì)運(yùn)行。

應(yīng)重寫的最重要的回調(diào)方法包括:

  1. [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))

啟動(dòng)服務(wù)startService() -> 重寫 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int)) 一旦執(zhí)行此方法,服務(wù)即會(huì)啟動(dòng)并可在后臺(tái)無(wú)限期運(yùn)行。 如果已實(shí)現(xiàn)此方法,則在服務(wù)工作完成后,需要通過(guò)調(diào)用 stopSelf()
stopService()來(lái)停止服務(wù)。(如果您只想提供綁定,則無(wú)需實(shí)現(xiàn)此方法。)

  1. onBind()

綁定服務(wù) [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int)),系統(tǒng)將調(diào)用此方法onBind()。在此方法的實(shí)現(xiàn)中,必須通過(guò)返回 IBinder提供一個(gè)接口,供客戶端用來(lái)與服務(wù)進(jìn)行通信。請(qǐng)務(wù)必實(shí)現(xiàn)此方法,但如果并不希望允許綁定,則應(yīng)返回 null。

  1. onCreate()

首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序(在調(diào)用 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))
onBind()
之前)。如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法。

  1. onDestroy()

當(dāng)服務(wù)不再使用且將被銷毀時(shí),系統(tǒng)將調(diào)用此方法。服務(wù)應(yīng)該實(shí)現(xiàn)此方法來(lái)清理所有資源,如線程、注冊(cè)的偵聽(tīng)器、接收器等。 這是服務(wù)接收的最后一個(gè)調(diào)用。

如果組件通過(guò)調(diào)用 startService()啟動(dòng)服務(wù)(這會(huì)導(dǎo)致對(duì) [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))的調(diào)用),則服務(wù)將一直運(yùn)行,直到服務(wù)使用 stopSelf()自行停止運(yùn)行,或由其他組件通過(guò)調(diào)用 stopService()停止它為止。

如果組件是通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))來(lái)創(chuàng)建服務(wù)(且調(diào)用 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))),則服務(wù)只會(huì)在該組件與其綁定時(shí)運(yùn)行。一旦該服務(wù)與所有客戶端之間的綁定全部取消,系統(tǒng)便會(huì)銷毀它。

為了確保應(yīng)用的安全性,**請(qǐng)始終使用顯式 Intent 啟動(dòng)或綁定 Service
**,且不要為服務(wù)聲明 Intent 過(guò)濾器。

創(chuàng)建啟動(dòng)服務(wù)


從傳統(tǒng)上講,可以擴(kuò)展Service , IntentService兩個(gè)類

1. Service

這是適用于所有服務(wù)的基類。擴(kuò)展此類時(shí),必須創(chuàng)建一個(gè)用于執(zhí)行所有服務(wù)工作的新線程,因?yàn)槟J(rèn)情況下,服務(wù)將使用應(yīng)用的主線程,這會(huì)降低應(yīng)用正在運(yùn)行的所有 Activity 的性能。
擴(kuò)展 Service類來(lái)創(chuàng)建啟動(dòng)服務(wù) :

該基類包含更多代碼,但如需同時(shí)處理多個(gè)啟動(dòng)請(qǐng)求,則更適合使用該基類;
使用 IntentService顯著簡(jiǎn)化了啟動(dòng)服務(wù)的實(shí)現(xiàn)。但是,若要求服務(wù)執(zhí)行多線程(而不是通過(guò)工作隊(duì)列處理啟動(dòng)請(qǐng)求),則可擴(kuò)展 Service類來(lái)處理每個(gè) Intent。
為了便于比較,以下提供了 Service 類實(shí)現(xiàn)的代碼示例,該類執(zhí)行的工作與使用 IntentService的示例完全相同。
也就是說(shuō),對(duì)于每個(gè)啟動(dòng)請(qǐng)求,它均使用工作線程執(zhí)行作業(yè),且每次僅處理一個(gè)請(qǐng)求。

以下是使用 Service類的代碼示例:

public class HelloService extends Service {
    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            long endTime = System.currentTimeMillis() + 5 * 1000;
            while (System.currentTimeMillis() < endTime) {
                synchronized (this) {
                    try {
                        wait(endTime - System.currentTimeMillis());
                    } catch (Exception e) {
                    }
                }
            }
            stopSelf(msg.arg1);
        }
    }

    @Override
    public void onCreate() {
        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();
        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();

        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        mServiceHandler.sendMessage(msg);
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
    }
}```


###2. [IntentService](http://developer.android.com/reference/android/app/IntentService.html)
這是 [Service](http://developer.android.com/reference/android/app/Service.html)的子類,它使用工作線程逐一處理所有啟動(dòng)請(qǐng)求。如果您不要求服務(wù)同時(shí)處理多個(gè)請(qǐng)求,這是最好的選擇。 您只需實(shí)現(xiàn) [onHandleIntent()](http://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent))方法即可,該方法會(huì)接收每個(gè)啟動(dòng)請(qǐng)求的 Intent,使您能夠執(zhí)行后臺(tái)工作。
擴(kuò)展[IntentService](http://developer.android.com/reference/android/app/IntentService.html)創(chuàng)建啟動(dòng)服務(wù),執(zhí)行以下操作: 
> - 創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))的所有 Intent。
 - 創(chuàng)建工作隊(duì)列,用于將一個(gè) Intent 逐一傳遞給 [onHandleIntent()](http://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent))實(shí)現(xiàn),這樣您就永遠(yuǎn)不必?fù)?dān)心多線程問(wèn)題。
 - 在處理完所有啟動(dòng)請(qǐng)求后停止服務(wù),因此您永遠(yuǎn)不必調(diào)用 [stopSelf()](http://developer.android.com/reference/android/app/Service.html#stopSelf())。
 - 提供 [onBind()](http://developer.android.com/reference/android/app/IntentService.html#onBind(android.content.Intent))的默認(rèn)實(shí)現(xiàn)(返回 null)。
 - 提供 [onStartCommand()](http://developer.android.com/reference/android/app/IntentService.html#onStartCommand(android.content.Intent, int, int))的默認(rèn)實(shí)現(xiàn),可將 Intent 依次發(fā)送到工作隊(duì)列和 [onHandleIntent()](http://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent))實(shí)現(xiàn)。
 --- 
綜上所述 :
只需實(shí)現(xiàn) [onHandleIntent()](http://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent))來(lái)完成客戶端提供的工作即可。(不過(guò),您還需要為服務(wù)提供小型構(gòu)造函數(shù)。)

以下是 [IntentService](http://developer.android.com/reference/android/app/IntentService.html)的實(shí)現(xiàn)示例:
```java
public class HelloIntentService extends IntentService {
      public HelloIntentService() {
          super("HelloIntentService");
      }
      @Override
      protected void onHandleIntent(Intent intent) {
          long endTime = System.currentTimeMillis() + 5 * 1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
      }
}

-- 您只需要一個(gè)構(gòu)造函數(shù)和一個(gè) onHandleIntent()實(shí)現(xiàn)即可。
如果您決定還重寫其他回調(diào)方法(如 onCreate()、[onStartCommand()](http://developer.android.com/reference/android/app/IntentService.html#onStartCommand(android.content.Intent, int, int))或 onDestroy()),請(qǐng)確保調(diào)用超類實(shí)現(xiàn),以便 IntentService能夠妥善處理工作線程的生命周期。
例如,[onStartCommand()](http://developer.android.com/reference/android/app/IntentService.html#onStartCommand(android.content.Intent, int, int))必須返回默認(rèn)實(shí)現(xiàn)(即,如何將 Intent 傳遞給 onHandleIntent()):

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
      return super.onStartCommand(intent,flags,startId);
}

onHandleIntent()之外,您無(wú)需從中調(diào)用超類的唯一方法就是 onBind()
(僅當(dāng)服務(wù)允許綁定時(shí),才需要實(shí)現(xiàn)該方法)。

啟動(dòng)服務(wù)

可以通過(guò)將 [Intent](http://developer.android.com/reference/android/content/Intent.html)(指定要啟動(dòng)的服務(wù))傳遞給 startService(),從 Activity 或其他應(yīng)用組件啟動(dòng)服務(wù)。Android 系統(tǒng)調(diào)用服務(wù)的 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))
方法,并向其傳遞 Intent。(切勿直接調(diào)用[onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))。)
例如,Activity 可以結(jié)合使用顯式 Intent 與 startService()
,啟動(dòng)上文中的示例服務(wù) (HelloSevice):

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

startService()方法將立即返回,且 Android 系統(tǒng)調(diào)用服務(wù)的 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))方法。如果服務(wù)尚未運(yùn)行,則系統(tǒng)會(huì)先調(diào)用 onCreate(),然后再調(diào)用 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))。

如果服務(wù)亦未提供綁定,則使用 startService()傳遞的 Intent 是應(yīng)用組件與服務(wù)之間唯一的通信模式。但是,如果您希望服務(wù)返回結(jié)果,則啟動(dòng)服務(wù)的客戶端可以為廣播創(chuàng)建一個(gè) PendingIntent(使用[getBroadcast()](http://developer.android.com/reference/android/app/PendingIntent.html#getBroadcast(android.content.Context, int, android.content.Intent, int))),并通過(guò)啟動(dòng)服務(wù)的 Intent傳遞給服務(wù)。然后,服務(wù)就可以使用廣播傳遞結(jié)果。

多個(gè)服務(wù)啟動(dòng)請(qǐng)求會(huì)導(dǎo)致多次對(duì)服務(wù)的 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))進(jìn)行相應(yīng)的調(diào)用。但是,要停止服務(wù),只需一個(gè)服務(wù)停止請(qǐng)求(使用 stopSelf()stopService())即可。

停止服務(wù)

啟動(dòng)服務(wù)必須管理自己的生命周期。也就是說(shuō),除非系統(tǒng)必須回收內(nèi)存資源,否則系統(tǒng)不會(huì)停止或銷毀服務(wù),而且服務(wù)在 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))返回后會(huì)繼續(xù)運(yùn)行。因此,服務(wù)必須通過(guò)調(diào)用 stopSelf()
自行停止運(yùn)行,或者由另一個(gè)組件通過(guò)調(diào)用 stopService()來(lái)停止它。

一旦請(qǐng)求使用 stopSelf()stopService()停止服務(wù),系統(tǒng)就會(huì)盡快銷毀服務(wù)。

但是,如果服務(wù)同時(shí)處理多個(gè) [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))請(qǐng)求,則您不應(yīng)在處理完一個(gè)啟動(dòng)請(qǐng)求之后停止服務(wù),因?yàn)槟赡芤呀?jīng)收到了新的啟動(dòng)請(qǐng)求(在第一個(gè)請(qǐng)求結(jié)束時(shí)停止服務(wù)會(huì)終止第二個(gè)請(qǐng)求)。為了避免這一問(wèn)題,您可以使用 stopSelf(int)確保服務(wù)停止請(qǐng)求始終基于最近的啟動(dòng)請(qǐng)求。也就說(shuō),在調(diào)用 stopSelf(int)時(shí),傳遞與停止請(qǐng)求的 ID 對(duì)應(yīng)的啟動(dòng)請(qǐng)求的 ID(傳遞給 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))的 startId) 。然后,如果在您能夠調(diào)用stopSelf(int)之前服務(wù)收到了新的啟動(dòng)請(qǐng)求, ID 就不匹配,服務(wù)也就不會(huì)停止。

注意:為了避免浪費(fèi)系統(tǒng)資源和消耗電池電量,應(yīng)用必須在工作完成之后停止其服務(wù)。 如有必要,其他組件可以通過(guò)調(diào)用 stopService()來(lái)停止服務(wù)。即使為服務(wù)啟用了綁定,一旦服務(wù)收到對(duì) [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))的調(diào)用,您始終仍須親自停止服務(wù)。

創(chuàng)建綁定服務(wù)


綁定服務(wù)允許應(yīng)用組件通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))與其綁定,以便創(chuàng)建長(zhǎng)期連接(通常不允許組件通過(guò)調(diào)用startService()來(lái)啟動(dòng)它)。

如需與 Activity 和其他應(yīng)用組件中的服務(wù)進(jìn)行交互,或者需要通過(guò)進(jìn)程間通信 (IPC) 向其他應(yīng)用公開(kāi)某些應(yīng)用功能,則應(yīng)創(chuàng)建綁定服務(wù)。

要?jiǎng)?chuàng)建綁定服務(wù),必須實(shí)現(xiàn) onBind()回調(diào)方法以返回 IBinder,用于定義與服務(wù)通信的接口。然后,其他應(yīng)用組件可以調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))來(lái)檢索該接口,并開(kāi)始對(duì)服務(wù)調(diào)用方法。服務(wù)只用于與其綁定的應(yīng)用組件,因此如果沒(méi)有組件綁定到服務(wù),則系統(tǒng)會(huì)銷毀服務(wù)(您不必按通過(guò) [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))
啟動(dòng)的服務(wù)那樣來(lái)停止綁定服務(wù))。

要?jiǎng)?chuàng)建綁定服務(wù),首先必須定義指定客戶端如何與服務(wù)通信的接口。 服務(wù)與客戶端之間的這個(gè)接口必須是IBinder的實(shí)現(xiàn),并且服務(wù)必須從 onBind()回調(diào)方法返回它。一旦客戶端收到 IBinder
,即可開(kāi)始通過(guò)該接口與服務(wù)進(jìn)行交互。

多個(gè)客戶端可以同時(shí)綁定到服務(wù)。客戶端完成與服務(wù)的交互后,會(huì)調(diào)用 unbindService()
取消綁定。一旦沒(méi)有客戶端綁定到該服務(wù),系統(tǒng)就會(huì)銷毀它。

有多種方法實(shí)現(xiàn)綁定服務(wù),其實(shí)現(xiàn)比啟動(dòng)服務(wù)更為復(fù)雜,因此綁定服務(wù)將在有關(guān)綁定服務(wù)的單獨(dú)文檔中專門討論。

向用戶發(fā)送通知


一旦運(yùn)行起來(lái),服務(wù)即可使用 Toast 通知狀態(tài)欄通知來(lái)通知用戶所發(fā)生的事件。

Toast 通知是指出現(xiàn)在當(dāng)前窗口的表面、片刻隨即消失不見(jiàn)的消息,而狀態(tài)欄通知?jiǎng)t在狀態(tài)欄提供內(nèi)含消息的圖標(biāo),用戶可以選擇該圖標(biāo)來(lái)采取操作(例如啟動(dòng) Activity)。

通常,當(dāng)某些后臺(tái)工作已經(jīng)完成(例如文件下載完成)且用戶現(xiàn)在可以對(duì)其進(jìn)行操作時(shí),狀態(tài)欄通知是最佳方法。 當(dāng)用戶從展開(kāi)視圖中選定通知時(shí),通知即可啟動(dòng) Activity(例如查看已下載的文件)。

如需了解詳細(xì)信息,請(qǐng)參閱 Toast 通知狀態(tài)欄通知開(kāi)發(fā)者指南。

在前臺(tái)運(yùn)行服務(wù)


前臺(tái)服務(wù)被認(rèn)為是用戶主動(dòng)意識(shí)到的一種服務(wù),因此在內(nèi)存不足時(shí),系統(tǒng)也不會(huì)考慮將其終止。 前臺(tái)服務(wù)必須為狀態(tài)欄提供通知,狀態(tài)欄位于“正在進(jìn)行”標(biāo)題下方,這意味著除非服務(wù)停止或從前臺(tái)刪除,否則不能清除通知。

例如,應(yīng)該將從服務(wù)播放音樂(lè)的音樂(lè)播放器設(shè)置為在前臺(tái)運(yùn)行,這是因?yàn)橛脩裘鞔_意識(shí)到其操作。 狀態(tài)欄中的通知可能表示正在播放的歌曲,并允許用戶啟動(dòng) Activity 來(lái)與音樂(lè)播放器進(jìn)行交互。

要請(qǐng)求讓服務(wù)運(yùn)行于前臺(tái),請(qǐng)調(diào)用 [startForeground()](http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification))。此方法取兩個(gè)參數(shù):唯一標(biāo)識(shí)通知的整型數(shù)和狀態(tài)欄的 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);

注意:提供給 [startForeground()](http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification))的整型 ID 不得為 0

要從前臺(tái)刪除服務(wù),請(qǐng)調(diào)用 stopForeground()。此方法取一個(gè)布爾值,指示是否也刪除狀態(tài)欄通知。 此方法絕對(duì)不會(huì)停止服務(wù)。
但是,如果您在服務(wù)正在前臺(tái)運(yùn)行時(shí)將其停止,則通知也會(huì)被刪除。
如需了解有關(guān)通知的詳細(xì)信息,請(qǐng)參閱創(chuàng)建狀態(tài)欄通知

管理服務(wù)生命周期


服務(wù)的生命周期比 Activity 的生命周期要簡(jiǎn)單得多。但是,密切關(guān)注如何創(chuàng)建和銷毀服務(wù)反而更加重要,因?yàn)榉?wù)可以在用戶沒(méi)有意識(shí)到的情況下運(yùn)行于后臺(tái)。

服務(wù)生命周期(從創(chuàng)建到銷毀)可以遵循兩條不同的路徑:

  • 啟動(dòng)服務(wù)
    該服務(wù)在其他組件調(diào)用 startService()時(shí)創(chuàng)建,然后無(wú)限期運(yùn)行,且必須通過(guò)調(diào)用 stopSelf()來(lái)自行停止運(yùn)行。此外,其他組件也可以通過(guò)調(diào)用 stopService()來(lái)停止服務(wù)。服務(wù)停止后,系統(tǒng)會(huì)將其銷毀。

  • 綁定服務(wù)
    該服務(wù)在另一個(gè)組件(客戶端)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))時(shí)創(chuàng)建。然后,客戶端通過(guò) IBinder接口與服務(wù)進(jìn)行通信。客戶端可以通過(guò)調(diào)用 unbindService()關(guān)閉連接。多個(gè)客戶端可以綁定到相同服務(wù),而且當(dāng)所有綁定全部取消后,系統(tǒng)即會(huì)銷毀該服務(wù)。 (服務(wù)不必自行停止運(yùn)行。)

這兩條路徑并非完全獨(dú)立。也就是說(shuō),您可以綁定到已經(jīng)使用 startService()啟動(dòng)的服務(wù)。例如,可以通過(guò)使用 Intent(標(biāo)識(shí)要播放的音樂(lè))調(diào)用 startService()來(lái)啟動(dòng)后臺(tái)音樂(lè)服務(wù)。隨后,可能在用戶需要稍加控制播放器或獲取有關(guān)當(dāng)前播放歌曲的信息時(shí),Activity 可以通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)。在這種情況下,除非所有客戶端均取消綁定,否則 stopService()stopSelf()不會(huì)真正停止服務(wù)。

實(shí)現(xiàn)生命周期回調(diào)

與 Activity 類似,服務(wù)也擁有生命周期回調(diào)方法,您可以實(shí)現(xiàn)這些方法來(lái)監(jiān)控服務(wù)狀態(tài)的變化并適時(shí)執(zhí)行工作。 以下框架服務(wù)展示了每種生命周期方法:

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
    }
}

注:與 Activity 生命周期回調(diào)方法不同,您不需要調(diào)用這些回調(diào)方法的超類實(shí)現(xiàn)。

Service生命周期

服務(wù)生命周期左圖顯示了使用 startService()所創(chuàng)建的服務(wù)的生命周期,右圖顯示了使用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))所創(chuàng)建的服務(wù)的生命周期。

通過(guò)實(shí)現(xiàn)這些方法,您可以監(jiān)控服務(wù)生命周期的兩個(gè)嵌套循環(huán):

注:盡管啟動(dòng)服務(wù)是通過(guò)調(diào)用 stopSelf()stopService()來(lái)停止,但是該服務(wù)并無(wú)相應(yīng)的回調(diào)(沒(méi)有onStop()回調(diào))。因此,除非服務(wù)綁定到客戶端,否則在服務(wù)停止時(shí),系統(tǒng)會(huì)將其銷毀—onDestroy()是接收到的唯一回調(diào)。

上圖說(shuō)明了服務(wù)的典型回調(diào)方法。盡管該圖分開(kāi)介紹通過(guò) startService()創(chuàng)建的服務(wù)和通過(guò)[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))創(chuàng)建的服務(wù),但是請(qǐng)記住,不管啟動(dòng)方式如何,任何服務(wù)均有可能允許客戶端與其綁定。因此,最初用 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))(通過(guò)客戶端調(diào)用 startService())啟動(dòng)的服務(wù)仍可接收對(duì) onBind()的調(diào)用(當(dāng)客戶端調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))時(shí))。

如需了解有關(guān)創(chuàng)建提供綁定的服務(wù)的詳細(xì)信息,請(qǐng)參閱綁定服務(wù)文檔,該文檔的管理綁定服務(wù)的生命周期部分提供了有關(guān) onRebind()回調(diào)方法的更多信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • [文章內(nèi)容來(lái)自Developers] Service是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不提供用戶界面的應(yīng)用組件。...
    岳小川閱讀 886評(píng)論 0 7
  • 前言:本文所寫的是博主的個(gè)人見(jiàn)解,如有錯(cuò)誤或者不恰當(dāng)之處,歡迎私信博主,加以改正!原文鏈接,demo鏈接 Serv...
    PassersHowe閱讀 1,446評(píng)論 0 5
  • 一段時(shí)間不用,知識(shí)點(diǎn)就會(huì)忘,所以整理下一些基本的知識(shí)點(diǎn),加深下印象,便于以后復(fù)習(xí)。這篇說(shuō)一下Android中四大組...
    朋永閱讀 502評(píng)論 0 2
  • 此章節(jié)參考Android官網(wǎng)內(nèi)容而編寫,如有遺漏,后面會(huì)慢慢補(bǔ)上。 一、Service是什么。 Service是一...
    __帝華閱讀 153評(píng)論 0 0
  • 戰(zhàn)狼確實(shí)火了,票房瘋長(zhǎng),影評(píng)如潮。今天我們也趁著這股熱量,來(lái)蹭下流量,感受下盛夏時(shí)節(jié)的這團(tuán)火! 讓我們一同回憶電影...
    照山閱讀 3,050評(píng)論 0 5