定義
服務就是一個在后臺執(zhí)行長時間操作的應用組件,并且它不會提供用戶界面。
服務分為三種:
-
前臺服務
前臺服務執(zhí)行一些對用戶可見的操作 .例如:音樂播放器。前臺服務必須在狀態(tài)欄顯示一個圖標。即使用戶不操作app了前臺服務也能繼續(xù)運行。 -
后臺服務
后臺服務執(zhí)行一些用戶感知不到的操作。
筆記:如果APP的targetApi在26及以上的時候,當app不在前臺的時候系統(tǒng)會限制后臺服務的執(zhí)行。所以我們應該使用scheduled job替代service。 -
綁定服務
當app的組件通過bindService()方法綁定到一個Service的時候,這個服務就叫綁定服務。綁定服務提供了一個允許組件和服務交互的客戶-服務器接口。綁定服務運行的時長和它綁定的組件是一樣的。多個組件在同一時間可以綁定同一個服務,但當這些組件都解綁的時候,服務就會被銷毀。
注意:服務默認運行在主機進程的主線程上;服務并不會創(chuàng)建自己的線程并且如果用戶不特別指定的話服務不會運行在其他進程上。當我們在服務中做耗時操作時必須新建一個線程去完成工作。
基礎
為了啟動服務,我們必須創(chuàng)建Service的子類。在我們的實現(xiàn)中必須覆蓋幾個重要的方法:
-
onStartCommand()
系統(tǒng)會在其他組件調(diào)用startService方法啟動服務后調(diào)用這個方法。當這個方法執(zhí)行的時候,服務就會啟動并且會無限期運行在后臺。如果調(diào)用這個方法啟動服務必須在服務的工作做完后調(diào)用stopSelf()或stopService()方法結束服務。如果只需要綁定服務則無需覆蓋這個方法。
這個方法有三個整型的返回值,這些返回值描述了當系統(tǒng)殺死這個服務后會怎么繼續(xù)服務:
START_NOT_STICKY
START_STICKY
START_REDELIVER_INTENT -
onBind()
系統(tǒng)會在其他組件通過bindService()綁定到Service的時候調(diào)用這個方法。我們必須在這個方法中返回一個客戶可以用來與Service交互的IBinder對象。這個方法必須被實現(xiàn),然而,當我們不想使用綁定的時候,這個方法應該返回null。 -
onCreate()
這個方法只有在Service被初始化的時候執(zhí)行一次(在onStartCommand()與onBind()之前調(diào)用),如果服務已經(jīng)運行,這個方法不會再被調(diào)用。 -
onDestroy()
系統(tǒng)會在服務不再被使用并且將要被銷毀時調(diào)用這個方法。在這個方法中可以做一些資源清理工作。這是Service接收到的最后一個方法。
注意:為了保證APP是安全的,我們必須使用顯式意圖去啟動Service并且不為Service聲明intent-filter,使用隱式意圖啟動Service是十分不安全的因為我們不確定服務是否一定會回應這個意圖,并且用戶也不知道哪個服務啟動了。從安卓5.0開始,使用隱式意圖啟動Service會拋出一個異常。
筆記:當我們在manifest為service設置android:exported屬性為false的時候就表明這個Service只有本應用的組件可以啟動,其他應用的組件即使使用顯式意圖也啟動不了。
Service和IntentService
-
Service
所有Service的基類。當我們繼承這個類時,我們應該創(chuàng)建一個新的線程用于執(zhí)行service要進行的所有工作。 -
IntentService
Service的子類,內(nèi)部含有一個處理所有請求的工作線程,每次只能接受一個請求。如果我們不需要Service同時處理多個請求的話,最好使用這個類。必須實現(xiàn)onHandleIntent()方法,這個方法用于接受所有請求。
筆記:如果要同時執(zhí)行多個請求的話使用Service而不能使用IntentService,因為IntentService是按隊列方式執(zhí)行請求的,只要前面一個請求阻塞了,后面的請求就都執(zhí)行不了了。
結束Service
通過startService()啟動的服務必須處理他自己的生命周期。系統(tǒng)只會在系統(tǒng)需要回收內(nèi)存并且service在onStartCommand方法返回值后還在運行的情況下才會銷毀它。
綁定服務不需要結束,當所有綁定在它上面的所有組件都解綁了,這個Service就會被銷毀了。
當一個服務先以startService啟動再被綁定的話,調(diào)用stopService()和stopSelf()并不能關閉服務,必須在所有組件都解綁了之后調(diào)用這兩個方法才有效。
生命周期

service_lifecycle.png