四大組件之Service

[文章內容來自Developers]

Service是一個可以在后臺執行長時間運行操作而不提供用戶界面的應用組件。服務可由其他應用組件啟動,而且即使用戶切換到其他應用,服務仍將在后臺繼續運行。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網絡事務、播放音樂,執行文件 I/O 或與內容提供程序交互,而所有這一切均可在后臺進行。
服務基本上分為兩種形式:
啟動
當應用組件(如 Activity)通過調用 startService()啟動服務時,服務即處于“啟動”狀態。一旦啟動,服務即可在后臺無限期運行,即使啟動服務的組件已被銷毀也不受影響。 已啟動的服務通常是執行單一操作,而且不會將結果返回給調用方。例如,它可能通過網絡下載或上傳文件。 操作完成后,服務會自行停止運行。
綁定
當應用組件通過調用 bindService()綁定到服務時,服務即處于“綁定”狀態。綁定服務提供了一個客戶端-服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至是利用進程間通信 (IPC) 跨進程執行這些操作。 僅當與另一個應用組件綁定時,綁定服務才會運行。 多個組件可以同時綁定到該服務,但全部取消綁定后,該服務即會被銷毀。

雖然本文檔是分開概括討論這兩種服務,但是您的服務可以同時以這兩種方式運行,也就是說,它既可以是啟動服務(以無限期運行),也允許綁定。問題只是在于您是否實現了一組回調方法:onStartCommand()(允許組件啟動服務)和 onBind()(允許綁定服務)。
無論應用是處于啟動狀態還是綁定狀態,抑或處于啟動并且綁定狀態,任何應用組件均可像使用 Activity 那樣通過調用 Intent來使用服務(即使此服務來自另一應用)。 不過,您可以通過清單文件將服務聲明為私有服務,并阻止其他應用訪問。

注意:服務在其托管進程的主線程中運行,它既創建自己的線程,也在單獨的進程中運行(除非另行指定)。 這意味著,如果服務將執行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或聯網),則應在服務內創建新線程來完成這項工作。通過使用單獨的線程,可以降低發生“應用無響應”(ANR) 錯誤的風險,而應用的主線程仍可繼續專注于運行用戶與 Activity 之間的交互。

基礎知識


要創建服務,您必須創建 Service的子類(或使用它的一個現有子類)。在實現中,您需要重寫一些回調方法,以處理服務生命周期的某些關鍵方面并提供一種機制將組件綁定到服務(如適用)。 應重寫的最重要的回調方法包括:

onStartCommand()
當另一個組件(如 Activity)通過調用 startService()請求啟動服務時,系統將調用此方法。一旦執行此方法,服務即會啟動并可在后臺無限期運行。 如果您實現此方法,則在服務工作完成后,需要由您通過調用 stopSelf()或 stopService()來停止服務。(如果您只想提供綁定,則無需實現此方法。)

onBind()
當另一個組件想通過調用 bindService()與服務綁定(例如執行 RPC)時,系統將調用此方法。在此方法的實現中,您必須通過返回 IBinder提供一個接口,供客戶端用來與服務進行通信。請務必實現此方法,但如果您并不希望允許綁定,則應返回 null。

onCreate()
首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand()或 onBind()之前)。如果服務已在運行,則不會調用此方法。

onDestroy()
當服務不再使用且將被銷毀時,系統將調用此方法。服務應該實現此方法來清理所有資源,如線程、注冊的偵聽器、接收器等。 這是服務接收的最后一個調用。

如果組件通過調用 startService()啟動服務(這會導致對 onStartCommand()的調用),則服務將一直運行,直到服務使用 stopSelf()自行停止運行,或由其他組件通過調用 stopService()停止它為止。
如果組件是通過調用 bindService()來創建服務(且調用 onStartCommand(),則服務只會在該組件與其綁定時運行。一旦該服務與所有客戶端之間的綁定全部取消,系統便會銷毀它。
僅當內存過低且必須回收系統資源以供具有用戶焦點的 Activity 使用時,Android 系統才會強制停止服務。如果將服務綁定到具有用戶焦點的 Activity,則它不太可能會終止;如果將服務聲明為在前臺運行(稍后討論),則它幾乎永遠不會終止?;蛘?,如果服務已啟動并要長時間運行,則系統會隨著時間的推移降低服務在后臺任務列表中的位置,而服務也將隨之變得非常容易被終止;如果服務是啟動服務,則您必須將其設計為能夠妥善處理系統對它的重啟。 如果系統終止服務,那么一旦資源變得再次可用,系統便會重啟服務(不過這還取決于從 onStartCommand()返回的值,本文稍后會對此加以討論)。

您應使用服務還是線程?
簡單地說,服務是一種即使用戶未與應用交互也可在后臺運行的組件。 因此,您應僅在必要時才創建服務。
如需在主線程外部執行工作,不過只是在用戶正在與應用交互時才有此需要,則應創建新線程而非服務。 例如,如果您只是想在 Activity 運行的同時播放一些音樂,則可在 onCreate()中創建線程,在 onStart()中啟動線程,然后在 onStop()中停止線程。您還可以考慮使用 AsyncTask或 HandlerThread,而非傳統的 Thread類。
請記住,如果您確實要使用服務,則默認情況下,它仍會在應用的主線程中運行,因此,如果服務執行的是密集型或阻止性操作,則您仍應在服務內創建新線程。

在下文中,您將了解如何創建各類服務以及如何從其他應用組件使用服務。

使用清單文件聲明服務
如同 Activity(以及其他組件)一樣,您必須在應用的清單文件中聲明所有服務。
要聲明服務,請添加 <service>元素作為 <application>元素的子元素。例如:

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

您還可將其他屬性包括在 <service>
元素中,以定義一些特性,如啟動服務及其運行所在進程所需的權限。android:name 屬性是唯一必需的屬性,用于指定服務的類名。應用一旦發布,即不應更改此類名,如若不然,可能會存在因依賴顯式 Intent 啟動或綁定服務而破壞代碼的風險(請閱讀博客文章Things That Cannot Change[不能更改的內容])。
為了確保應用的安全性,請始終使用顯式 Intent 啟動或綁定 Service,且不要為服務聲明 Intent 過濾器。 啟動哪個服務存在一定的不確定性,而如果對這種不確定性的考量非常有必要,則可為服務提供 Intent 過濾器并從 Intent中排除相應的組件名稱,但隨后必須使用 setPackage()方法設置 Intent 的軟件包,這樣可以充分消除目標服務的不確定性。
此外,還可以通過添加 android:exported屬性并將其設置為 "false",確保服務僅適用于您的應用。這可以有效阻止其他應用啟動您的服務,即便在使用顯式 Intent 時也如此。

創建啟動服務


啟動服務由另一個組件通過調用 startService()啟動,這會導致調用服務的 onStartCommand()方法。
服務啟動之后,其生命周期即獨立于啟動它的組件,并且可以在后臺無限期地運行,即使啟動服務的組件已被銷毀也不受影響。 因此,服務應通過調用 stopSelf()結束工作來自行停止運行,或者由另一個組件通過調用 stopService()來停止它。
應用組件(如 Activity)可以通過調用 startService()方法并傳遞 Intent對象(指定服務并包含待使用服務的所有數據)來啟動服務。服務通過 onStartCommand()方法接收此 Intent。
例如,假設某 Activity 需要將一些數據保存到在線數據庫中。該 Activity 可以啟動一個協同服務,并通過向 startService()傳遞一個 Intent,為該服務提供要保存的數據。服務通過 onStartCommand()接收 Intent,連接到互聯網并執行數據庫事務。事務完成之后,服務會自行停止運行并隨即被銷毀。

注意:默認情況下,服務與服務聲明所在的應用運行于同一進程,而且運行于該應用的主線程中。 因此,如果服務在用戶與來自同一應用的 Activity 進行交互時執行密集型或阻止性操作,則會降低 Activity 性能。 為了避免影響應用性能,您應在服務內啟動新線程。

從傳統上講,您可以擴展兩個類來創建啟動服務:

Service
這是適用于所有服務的基類。擴展此類時,必須創建一個用于執行所有服務工作的新線程,因為默認情況下,服務將使用應用的主線程,這會降低應用正在運行的所有 Activity 的性能。

IntentService
這是 Service的子類,它使用工作線程逐一處理所有啟動請求。如果您不要求服務同時處理多個請求,這是最好的選擇。 您只需實現 onHandleIntent()方法即可,該方法會接收每個啟動請求的 Intent,使您能夠執行后臺工作。

下文介紹如何使用其中任一個類來實現服務。

擴展 IntentService 類
由于大多數啟動服務都不必同時處理多個請求(實際上,這種多線程情況可能很危險),因此使用 類實現服務也許是最好的選擇。
IntentService執行以下操作:

  • 創建默認的工作線程,用于在應用的主線程外執行傳遞給 onStartCommand() 的所有 Intent。
  • 創建工作隊列,用于將 Intent 逐一傳遞給 onHandleIntent()實現,這樣您就永遠不必擔心多線程問題。
  • 在處理完所有啟動請求后停止服務,因此您永遠不必調用 stopSelf()。
  • 提供 onBind()的默認實現(返回 null)。
  • 提供 onStartCommand()的默認實現,可將 Intent 依次發送到工作隊列和 onHandleIntent()實現。

綜上所述,您只需實現 onHandleIntent()來完成客戶端提供的工作即可。(不過,您還需要為服務提供小型構造函數。)
以下是 IntentService的實現示例:

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.      
try {          
Thread.sleep(5000);      
} catch (InterruptedException e) {          
// Restore interrupt status.          
Thread.currentThread().interrupt();      
}  
}}

您只需要一個構造函數和一個 onHandleIntent()實現即可。
如果您決定還重寫其他回調方法(如 onCreate()、onStartCommand()或 onDestroy()),請確保調用超類實現,以便 IntentService能夠妥善處理工作線程的生命周期。
例如,onStartCommand()必須返回默認實現(即,如何將 Intent 傳遞給 onHandleIntent():

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

除 onHandleIntent()之外,您無需從中調用超類的唯一方法就是 onBind()(僅當服務允許綁定時,才需要實現該方法)。
在下一部分中,您將了解如何在擴展 Service基類時實現同類服務。該基類包含更多代碼,但如需同時處理多個啟動請求,則更適合使用該基類。

擴展服務類

正如上一部分中所述,使用 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.          
try {              
Thread.sleep(5000);          
} catch (InterruptedException e) {              
// Restore interrupt status.              Thread.currentThread().interrupt();          
}          
// 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。相反,除非有掛起 Intent 要啟動服務(在這種情況下,將傳遞這些 Intent ),否則系統會通過空 Intent 調用 onStartCommand()。這適用于不執行命令、但無限期運行并等待作業的媒體播放器(或類似服務)。

START_REDELIVER_INTENT
如果系統在 onStartCommand()返回后終止服務,則會重建服務,并通過傳遞給服務的最后一個 Intent 調用 onStartCommand()。任何掛起 Intent 均依次傳遞。這適用于主動執行應該立即恢復的作業(例如下載文件)的服務。

啟動服務

您可以通過將 Intent(指定要啟動的服務)傳遞給 startService(),從 Activity 或其他應用組件啟動服務。Android 系統調用服務的 onStartCommand()方法,并向其傳遞 Intent。(切勿直接調用 onStartCommand()。)
例如,Activity 可以結合使用顯式 Intent 與 startService(),啟動上文中的示例服務 (HelloService):

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

startService()方法將立即返回,且 Android 系統調用服務的 onStartCommand()方法。如果服務尚未運行,則系統會先調用 onCreate(),然后再調用 onStartCommand()。
如果服務亦未提供綁定,則使用 startService()傳遞的 Intent 是應用組件與服務之間唯一的通信模式。但是,如果您希望服務返回結果,則啟動服務的客戶端可以為廣播創建一個 PendingIntent(使用 getBroadcast()),并通過啟動服務的 Intent傳遞給服務。然后,服務就可以使用廣播傳遞結果。
多個服務啟動請求會導致多次對服務的 onStartCommand() 進行相應的調用。但是,要停止服務,只需一個服務停止請求(使用 stopSelf()或 stopService())即可。

停止服務

啟動服務必須管理自己的生命周期。也就是說,除非系統必須回收內存資源,否則系統不會停止或銷毀服務,而且服務在 onStartCommand()返回后會繼續運行。因此,服務必須通過調用 stopSelf()自行停止運行,或者由另一個組件通過調用 stopService()來停止它。
一旦請求使用 stopSelf()或 stopService()停止服務,系統就會盡快銷毀服務。
但是,如果服務同時處理多個 onStartCommand()請求,則您不應在處理完一個啟動請求之后停止服務,因為您可能已經收到了新的啟動請求(在第一個請求結束時停止服務會終止第二個請求)。為了避免這一問題,您可以使用 stopSelf(int) 確保服務停止請求始終基于最近的啟動請求。也就說,在調用 stopSelf(int)時,傳遞與停止請求的 ID 對應的啟動請求的 ID(傳遞給 onStartCommand()的 startId)。然后,如果在您能夠調用 stopSelf(int)之前服務收到了新的啟動請求,ID 就不匹配,服務也就不會停止。

注意:為了避免浪費系統資源和消耗電池電量,應用必須在工作完成之后停止其服務。 如有必要,其他組件可以通過調用 stopService()來停止服務。即使為服務啟用了綁定,一旦服務收到對 onStartCommand()的調用,您始終仍須親自停止服務。

創建綁定服務


綁定服務允許應用組件通過調用 bindService()與其綁定,以便創建長期連接(通常不允許組件通過調用 startService()來啟動它)。
如需與 Activity 和其他應用組件中的服務進行交互,或者需要通過進程間通信 (IPC) 向其他應用公開某些應用功能,則應創建綁定服務。
要創建綁定服務,必須實現 onBind() 回調方法以返回 IBinder,用于定義與服務通信的接口。然后,其他應用組件可以調用 bindService()來檢索該接口,并開始對服務調用方法。服務只用于與其綁定的應用組件,因此如果沒有組件綁定到服務,則系統會銷毀服務(您不必按通過onStartCommand()啟動的服務那樣來停止綁定服務)。
要創建綁定服務,首先必須定義指定客戶端如何與服務通信的接口。 服務與客戶端之間的這個接口必須是 IBinder的實現,并且服務必須從onBind() 回調方法返回它。一旦客戶端收到 IBinder,即可開始通過該接口與服務進行交互。
多個客戶端可以同時綁定到服務??蛻舳送瓿膳c服務的交互后,會調用 unbindService()取消綁定。一旦沒有客戶端綁定到該服務,系統就會銷毀它。
有多種方法實現綁定服務,其實現比啟動服務更為復雜,因此綁定服務將在有關綁定服務的單獨文檔中專門討論。

向用戶發送通知


一旦運行起來,服務即可使用 Toast 通知或狀態欄通知來通知用戶所發生的事件。
Toast 通知是指出現在當前窗口的表面、片刻隨即消失不見的消息,而狀態欄通知則在狀態欄中隨消息一起提供圖標,用戶可以選擇該圖標來采取操作(例如啟動 Activity)。
通常,當某些后臺工作已經完成(例如文件下載完成)且用戶現在可以對其進行操作時,狀態欄通知是最佳方法。 當用戶從展開視圖中選定通知時,通知即可啟動 Activity(例如查看已下載的文件)。

在前臺運行服務


前臺服務被認為是用戶主動意識到的一種服務,因此在內存不足時,系統也不會考慮將其終止。 前臺服務必須為狀態欄提供通知,放在“正在進行”標題下方,這意味著除非服務停止或從前臺移除,否則不能清除通知。
例如,應該將通過服務播放音樂的音樂播放器設置為在前臺運行,這是因為用戶明確意識到其操作。 狀態欄中的通知可能表示正在播放的歌曲,并允許用戶啟動 Activity 來與音樂播放器進行交互。
要請求讓服務運行于前臺,請調用 startForeground()。此方法采用兩個參數:唯一標識通知的整型數和狀態欄的 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()的整型 ID 不得為 0。

要從前臺移除服務,請調用 stopForeground()。此方法采用一個布爾值,指示是否也移除狀態欄通知。 此方法不會停止服務。 但是,如果您在服務正在前臺運行時將其停止,則通知也會被移除。

管理服務生命周期


服務的生命周期比 Activity 的生命周期要簡單得多。但是,密切關注如何創建和銷毀服務反而更加重要,因為服務可以在用戶沒有意識到的情況下運行于后臺。
服務生命周期(從創建到銷毀)可以遵循兩條不同的路徑:

  • 啟動服務
    該服務在其他組件調用 startService()時創建,然后無限期運行,且必須通過調用 stopSelf()來自行停止運行。此外,其他組件也可以通過調用 stopService()來停止服務。服務停止后,系統會將其銷毀。
  • 綁定服務
    該服務在另一個組件(客戶端)調用 bindService()時創建。然后,客戶端通過 IBinder接口與服務進行通信??蛻舳丝梢酝ㄟ^調用unbindService()關閉連接。多個客戶端可以綁定到相同服務,而且當所有綁定全部取消后,系統即會銷毀該服務。 (服務不必自行停止運行。)

這兩條路徑并非完全獨立。也就是說,您可以綁定到已經使用 startService()啟動的服務。例如,可以通過使用 Intent(標識要播放的音樂)調用 startService()來啟動后臺音樂服務。隨后,可能在用戶需要稍加控制播放器或獲取有關當前播放歌曲的信息時,Activity 可以通過調用 bindService()綁定到服務。在這種情況下,除非所有客戶端均取消綁定,否則 stopService() 或 stopSelf()不會實際停止服務。
實現生命周期回調
與 Activity 類似,服務也擁有生命周期回調方法,您可以實現這些方法來監控服務狀態的變化并適時執行工作。 以下框架服務展示了每種生命周期方法:

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()](https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent))
        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 生命周期回調方法不同,您需要調用這些回調方法的超類實現。

圖 2. 服務生命周期。左圖顯示了使用 startService()所創建的服務的生命周期,右圖顯示了使用 bindService()所創建的服務的生命周期。
通過實現這些方法,您可以監控服務生命周期的兩個嵌套循環:
服務的整個生命周期從調用 onCreate()開始起,到 onDestroy()返回時結束。與 Activity 類似,服務也在 onCreate()中完成初始設置,并在 onDestroy()中釋放所有剩余資源。例如,音樂播放服務可以在 onCreate(中創建用于播放音樂的線程,然后在 onDestroy()中停止該線程。無論服務是通過 startService()還是 bindService()創建,都會為所有服務調用 onCreate()和 onDestroy()方法。

服務的有效生命周期從調用 onStartCommand()或 onBind()方法開始。每種方法均有 Intent對象,該對象分別傳遞到 startService()或 bindService()。對于啟動服務,有效生命周期與整個生命周期同時結束(即便是在 onStartCommand()返回之后,服務仍然處于活動狀態)。對于綁定服務,有效生命周期在 onUnbind()返回時結束。

注:盡管啟動服務是通過調用 stopSelf()或 stopService()來停止,但是該服務并無相應的回調(沒有 onStop()
回調)。因此,除非服務綁定到客戶端,否則在服務停止時,系統會將其銷毀 — onDestroy()是接收到的唯一回調。

圖 2 說明了服務的典型回調方法。盡管該圖分開介紹通過 startService()創建的服務和通過 bindService()創建的服務,但是請記住,不管啟動方式如何,任何服務均有可能允許客戶端與其綁定。因此,最初使用 onStartCommand()(通過客戶端調用 startService()啟動的服務仍可接收對 onBind()的調用(當客戶端調用 bindService()時)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容