- 《Android Service基礎(chǔ)》
- 《Android Service回調(diào)和配置》
- 《Android Service aidl使用及進(jìn)階》
- 《Android Service更多知識(shí)》
- 《Android 中的 IntentService 類詳解》
- 《Android Service aidl分析》
- 《Android Service 流程分析》
Service 生命周期方法回調(diào)
創(chuàng)建服務(wù)嗅榕,必須創(chuàng)建 Service 的子類(或使用它的一個(gè)現(xiàn)有子類)。可以重寫一些回調(diào)方法,從而處理服務(wù)生命周期的某些關(guān)鍵方面,主要的回調(diào)方法有 onCreate()
、onBind()
、onRebind()
、onStartCommand()
、onStart()
、onUnbind()
蹦掐、onDestroy()
社裆。
onCreate()
首次創(chuàng)建服務(wù)時(shí),系統(tǒng)會(huì)(在調(diào)用 onStartCommand()
或 onBind()
之前)調(diào)用此方法來執(zhí)行一次性設(shè)置程序。如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法。
onBind()
當(dāng)另一個(gè)組件想要與服務(wù)綁定時(shí),系統(tǒng)會(huì)通過調(diào)用 bindService()
來調(diào)用此方法庆杜。在此方法的實(shí)現(xiàn)中,必須通過返回 IBinder 提供一個(gè)接口钢猛,以供客戶端用來與服務(wù)進(jìn)行通信壶愤。但是,如果并不希望服務(wù)允許綁定垄开,則應(yīng)返回 null锻梳。
onRebind()
服務(wù)未被銷毀荆永,再次綁定時(shí)回調(diào)骂删。前提是 onUnbind()
方法返回true(如果服務(wù)已啟動(dòng)并接受綁定撬统,則當(dāng)系統(tǒng)調(diào)用 onUnbind()
方法時(shí)罚屋,如果想在客戶端下一次綁定到服務(wù)時(shí)接收 onRebind()
調(diào)用,則可選擇返回 true)焊切。onRebind()
返回空值,但客戶端仍在其 onServiceConnected()
回調(diào)中接收 IBinder掌呜。
onStartCommand()
當(dāng)另一個(gè)組件(如 Activity)請(qǐng)求啟動(dòng)服務(wù)時(shí)兑宇,系統(tǒng)會(huì)通過調(diào)用 startService()
來調(diào)用此方法再登。執(zhí)行此方法時(shí)缠俺,服務(wù)即會(huì)啟動(dòng)并可在后臺(tái)無限期運(yùn)行盒使。如果實(shí)現(xiàn)此方法蔓纠,則在服務(wù)工作完成后懈叹,需負(fù)責(zé)通過調(diào)用 stopSelf()
或 stopService()
來停止服務(wù)列赎。(如果只想提供綁定嚷狞,則無需實(shí)現(xiàn)此方法)只酥。
onStart()
該方法已過時(shí),使用 onStartCommand()
回調(diào)即可蜒秤。
onUnbind()
當(dāng)所有客戶端都和服務(wù)解除綁定時(shí)調(diào)用蚤假。解除綁定方法 context.unbindService()
冬竟。
onDestroy()
當(dāng)不再使用服務(wù)且準(zhǔn)備將其銷毀時(shí),系統(tǒng)會(huì)調(diào)用此方法笑诅。服務(wù)應(yīng)通過實(shí)現(xiàn)此方法來清理資源妇多,如線程、注冊(cè)的監(jiān)聽器饶氏、接收器等谣蠢。這是服務(wù)接收的最后一個(gè)調(diào)用挤忙。
Service 生命周期流程圖
服務(wù)生命周期圖
左圖顯示使用 startService() 創(chuàng)建的服務(wù)的生命周期,右圖顯示使用 bindService() 創(chuàng)建的服務(wù)的生命周期
- 服務(wù)的整個(gè)生命周期貫穿調(diào)用
onCreate()
和返回onDestroy()
之間的這段時(shí)間谈喳。與 Activity 類似册烈,服務(wù)也在onCreate()
中完成初始設(shè)置,并在onDestroy()
中釋放所有剩余資源婿禽。 - 服務(wù)的活動(dòng)生命周期從調(diào)用
onStartCommand()
或onBind()
開始赏僧。每種方法均會(huì)獲得 Intent 對(duì)象,該對(duì)象由startService()
或bindService()
方法傳遞扭倾。 - 對(duì)于啟動(dòng)服務(wù)淀零,活動(dòng)生命周期與整個(gè)生命周期會(huì)同時(shí)結(jié)束(即便是在
onStartCommand()
返回之后,服務(wù)仍然處于活動(dòng)狀態(tài))膛壹。對(duì)于綁定服務(wù)窑滞,活動(dòng)生命周期會(huì)在onUnbind()
返回時(shí)結(jié)束。 - 盡管可以通過調(diào)用
stopSelf()
或stopService()
來停止綁定服務(wù)恢筝,但該服務(wù)并沒有相應(yīng)的回調(diào)(如 onStop() 回調(diào))哀卫。除非服務(wù)綁定到客戶端(解綁回調(diào)onUnbind()
),否則在服務(wù)停止時(shí)撬槽,系統(tǒng)會(huì)將其銷毀(onDestroy()
是接收到的唯一回調(diào))此改。
已啟動(dòng)且允許綁定的服務(wù)的生命周期
-
onRebind()
方法會(huì)回調(diào)的前提是:服務(wù)未被銷毀,再次綁定時(shí)回調(diào)侄柔,并且onUnbind()
方法返回true共啃。 -
onRebind()
返回空值占调,但客戶端仍會(huì)回調(diào)ServiceConnection
的onServiceConnected()
方法,接收IBinder移剪。
Service 部分相關(guān)方法詳細(xì)說明
onStartCommand()
當(dāng)另一個(gè)組件(如 Activity)請(qǐng)求啟動(dòng)服務(wù)時(shí)究珊,系統(tǒng)會(huì)通過調(diào)用 startService()
來調(diào)用此方法。
參數(shù):
- Intent intent:調(diào)用
stopService(Intent name)
方法傳遞的 Intent 對(duì)象纵苛,組件可以通過Intent傳遞參數(shù)給Service剿涮,如果之后服務(wù)重新啟動(dòng),可能為null攻人,具體是否需要有數(shù)據(jù)取试,需要根據(jù)該方法的返回值確定。 - int flags:其他附加數(shù)據(jù)怀吻。
- int startId:表示要啟動(dòng)的特定請(qǐng)求的唯一整數(shù)瞬浓。一般與
stopSelfResult(int)
一起使用。
返回值:
一般來說蓬坡,主要有三類返回值
-
START_STICKY:如果系統(tǒng)在
onStartCommand()
返回后終止服務(wù)猿棉,則其會(huì)重建服務(wù)并調(diào)用onStartCommand()
,但不會(huì)重新傳遞最后一個(gè) Intent屑咳。如果還有掛起 Intent 要啟動(dòng)服務(wù)萨赁,系統(tǒng)會(huì)傳遞這些 Intent;否則系統(tǒng)會(huì)調(diào)用包含空 Intent 的 onStartCommand()乔宿。此常量適用于不執(zhí)行命令位迂、但無限期運(yùn)行并等待作業(yè)的媒體播放器(或類似服務(wù))访雪。 - START_STICKY_COMPATIBILITY:START_STICKY 的兼容版本详瑞。
-
START_NOT_STICKY:如果系統(tǒng)在
onStartCommand()
返回后終止服務(wù),除非有待傳遞的掛起的 Intent臣缀,否則系統(tǒng)不會(huì)重建服務(wù)坝橡。 -
START_REDELIVER_INTENT:如果系統(tǒng)在
onStartCommand()
返回后終止服務(wù),則其會(huì)重建服務(wù)精置,并通過傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用onStartCommand()
计寇。所有掛起 Intent 均依次傳遞。此常量適用于主動(dòng)執(zhí)行應(yīng)立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)脂倦。
bindService()
用于綁定服務(wù)的方法
參數(shù):
- Intent service:意圖番宁,標(biāo)識(shí)要連接的服務(wù)。(注意:如果使用 Intent 來綁定到 Service赖阻,請(qǐng)務(wù)必使用顯式 Intent 來確保應(yīng)用的安全性蝶押。使用隱式 Intent 啟動(dòng)服務(wù)存在安全隱患,因?yàn)闊o法確定哪些服務(wù)會(huì)響應(yīng)該 Intent火欧,并且用戶無法看到哪些服務(wù)已啟動(dòng)棋电。從 Android 5.0(API 級(jí)別 21)開始茎截,如果使用隱式 Intent 調(diào)用 bindService(),則系統(tǒng)會(huì)拋出異常赶盔。)
- ServiceConnection conn:
ServiceConnection
對(duì)象企锌,在在服務(wù)啟動(dòng)和斷開連接時(shí)接收信息,不能為null - int flags:指示綁定選項(xiàng)的標(biāo)記于未。如要?jiǎng)?chuàng)建尚未處于活動(dòng)狀態(tài)的服務(wù)撕攒,此參數(shù)應(yīng)為
BIND_AUTO_CREATE
(常用)。其他可能的值為BIND_DEBUG_UNBIND
(主要用于調(diào)試)沉眶、BIND_NOT_FOREGROUND
等打却,或者 0(表示無此參數(shù))。 - 實(shí)現(xiàn)
ServiceConnection
必須重寫兩個(gè)回調(diào)方法:-
onServiceConnected()
:系統(tǒng)會(huì)調(diào)用該方法谎倔,進(jìn)而傳遞服務(wù)的onBind()
方法所返回的IBinder
-
onServiceDisconnected()
:當(dāng)與服務(wù)的連接意外中斷(例如服務(wù)崩潰或被終止)時(shí)柳击,Android 系統(tǒng)會(huì)調(diào)用該方法。當(dāng)客戶端取消綁定時(shí)片习,系統(tǒng)不會(huì)調(diào)用該方法捌肴。
-
onUnbind()
當(dāng)所有客戶端都和服務(wù)解除綁定時(shí)調(diào)用。如果返回true藕咏,當(dāng)服務(wù)未銷毀并重新調(diào)用 bindService()
時(shí)回調(diào) onRebind()
和 ServiceConnection
的 onServiceConnected()
方法状知;否則,只會(huì)回調(diào) ServiceConnection
的 onServiceConnected()
方法孽查。
startForeground()
/ stopForeground()
startForeground()
:讓服務(wù)運(yùn)行在前臺(tái)饥悴,參數(shù)1:通知標(biāo)識(shí)(不能為 0)參數(shù)2:用于狀態(tài)欄的 Notification
stopForeground()
:移出前臺(tái)運(yùn)行的服務(wù),參數(shù)表示是否需同時(shí)移除狀態(tài)欄通知盲再。此方法并不會(huì)停止服務(wù)西设。但是,如果在服務(wù)運(yùn)行于前臺(tái)時(shí)將其停止答朋,則通知也會(huì)隨之移除贷揽。
startForegroundService()
在Android 8.0 以上系統(tǒng)不允許后臺(tái)應(yīng)用創(chuàng)建后臺(tái)服務(wù)。 因此引入了一種全新的方法梦碗,即通過 Context.startForegroundService() 方法在前臺(tái)啟動(dòng)新服務(wù)禽绪,通過調(diào)用該方法,在系統(tǒng)創(chuàng)建服務(wù)后洪规,應(yīng)用有五秒的時(shí)間來調(diào)用該服務(wù)的 startForeground() 方法以顯示新服務(wù)的用戶可見通知印屁,如果應(yīng)用在此時(shí)間限制內(nèi)未調(diào)用 startForeground(),則系統(tǒng)將停止服務(wù)并聲明此應(yīng)用為 ANR斩例。
清單文件中 Service 配置
語法
<service android:description="string resource"
android:directBootAware=["true" | "false"]
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:foregroundServiceType=["connectedDevice" | "dataSync" |
"location" | "mediaPlayback" | "mediaProjection" |
"phoneCall"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</service>
具體說明
android:description
向用戶描述服務(wù)的字符串雄人。應(yīng)將此標(biāo)簽設(shè)置為對(duì)字符串資源的引用,以便可以像對(duì)界面中的其他字符串那樣對(duì)其進(jìn)行本地化樱拴。
android:directBootAware
服務(wù)是否支持直接啟動(dòng)柠衍,即其是否可以在用戶解鎖設(shè)備之前運(yùn)行洋满。默認(rèn)值為 "false"。在直接啟動(dòng)期間珍坊,應(yīng)用中的服務(wù)僅可訪問存儲(chǔ)在設(shè)備保護(hù)存儲(chǔ)區(qū)的數(shù)據(jù)牺勾。
android:enabled
系統(tǒng)是否可實(shí)例化服務(wù) —“true”表示可以,“false”表示不可以阵漏。默認(rèn)值為“true”驻民。
<application> 元素?fù)碛凶约旱?enabled 屬性,該屬性適用于所有應(yīng)用組件履怯,包括服務(wù)回还。只有在 <application> 和 <service> 屬性都為“true”(因?yàn)樗鼈兌寄J(rèn)使用該值)時(shí),系統(tǒng)才能啟用服務(wù)叹洲。任何一項(xiàng)為“false”都會(huì)造成服務(wù)停用柠硕,從而使系統(tǒng)無法將其實(shí)例化。
android:exported
其他應(yīng)用的組件是否能調(diào)用服務(wù)或與之交互 —“true”表示可以运提,“false”表示不可以蝗柔。當(dāng)該值為“false”時(shí),只有同一個(gè)應(yīng)用或具有相同用戶 ID 的應(yīng)用的組件可以啟動(dòng)服務(wù)或綁定到服務(wù)民泵。
默認(rèn)值取決于服務(wù)是否包含 Intent 過濾器癣丧。沒有任何過濾器意味著服務(wù)只能通過指定其確切的類名稱進(jìn)行調(diào)用。這意味著服務(wù)專供應(yīng)用內(nèi)部使用(因?yàn)槠渌麘?yīng)用不知曉其類名稱)栈妆。因此胁编,在這種情況下,默認(rèn)值為“false”鳞尔。另一方面嬉橙,至少存在一個(gè)過濾器意味著服務(wù)專供外部使用,因此默認(rèn)值為“true”铅檩。此屬性并非是唯一限制向其他應(yīng)用披露服務(wù)的方式憎夷。還可使用權(quán)限來限制哪些外部實(shí)體可以與服務(wù)交互莽鸿。
android:foregroundServiceType
闡明服務(wù)是滿足特定用例要求的前臺(tái)服務(wù)昧旨。例如,"location" 類型的前臺(tái)服務(wù)表示應(yīng)用正在獲取設(shè)備的當(dāng)前位置祥得,目的通常是繼續(xù)用戶發(fā)起的操作兔沃,且該操作與設(shè)備位置相關(guān)〖都埃可以將多個(gè)前臺(tái)服務(wù)類型分配給特定服務(wù)乒疏。
android:icon
表示服務(wù)的圖標(biāo)。必須將該屬性設(shè)置為對(duì)包含圖像定義的可繪制資源的引用饮焦。如果未設(shè)置該屬性怕吴,則轉(zhuǎn)而使用為應(yīng)用整體指定的圖標(biāo)窍侧。
android:isolatedProcess
如果設(shè)置為 true,則此服務(wù)將在與系統(tǒng)其余部分隔離的特殊進(jìn)程下運(yùn)行转绷。此服務(wù)自身沒有權(quán)限伟件,只能通過 Service API 與其進(jìn)行通信(綁定和啟動(dòng))。
android:label
可向用戶顯示的服務(wù)名稱议经。如果未設(shè)置該屬性斧账,則轉(zhuǎn)而使用為應(yīng)用整體設(shè)置的標(biāo)簽。
android:name
實(shí)現(xiàn)服務(wù)的 Service 子類的名稱煞肾。此名稱應(yīng)為完全限定類名稱(例如“com.example.project.RoomService”)咧织。一旦發(fā)布應(yīng)用,即不應(yīng)更改該名稱(除非設(shè)置了 android:exported="false")籍救。沒有默認(rèn)值习绢。必須指定該名稱。
android:permission
實(shí)體啟動(dòng)服務(wù)或綁定到服務(wù)所必需的權(quán)限的名稱蝙昙。如果 startService()毯炮、bindService() 或 stopService() 的調(diào)用者尚未獲得此權(quán)限,該方法將不起作用耸黑,且系統(tǒng)不會(huì)將 Intent 對(duì)象傳送給服務(wù)桃煎。如果未設(shè)置該屬性,則對(duì)服務(wù)應(yīng)用由 <application> 元素的 permission 屬性所設(shè)置的權(quán)限大刊。如果二者均未設(shè)置为迈,則服務(wù)不受權(quán)限保護(hù)。
android:process
將運(yùn)行服務(wù)的進(jìn)程的名稱缺菌。正常情況下葫辐,應(yīng)用的所有組件都會(huì)在為應(yīng)用創(chuàng)建的默認(rèn)進(jìn)程中運(yùn)行。該名稱與應(yīng)用軟件包的名稱相同伴郁。<application> 元素的 process 屬性可為所有組件設(shè)置不同的默認(rèn)進(jìn)程名稱耿战。不過,組件可以使用自己的 process 屬性替換默認(rèn)值焊傅,可以將應(yīng)用散布到多個(gè)進(jìn)程中剂陡。
如果為此屬性分配的名稱以冒號(hào)(“:”)開頭,則系統(tǒng)會(huì)在需要時(shí)創(chuàng)建應(yīng)用專用的新進(jìn)程狐胎,并且服務(wù)會(huì)在該進(jìn)程中運(yùn)行鸭栖。如果進(jìn)程名稱以小寫字符開頭,則服務(wù)將在使用該名稱的全局進(jìn)程中運(yùn)行握巢,前提是它擁有相應(yīng)的權(quán)限晕鹊。如此一來,不同應(yīng)用中的組件便可共享進(jìn)程,從而減少資源使用溅话。