此章節(jié)參考Android官網(wǎng)內(nèi)容而編寫幽纷,如有遺漏疚俱,后面會慢慢補(bǔ)上劝术。
一、Service是什么呆奕。
Service是一個可以在后臺執(zhí)行長時間運(yùn)行操作而不提供用戶界面的應(yīng)用組件养晋。服務(wù)可由其他應(yīng)用組件啟動,而且即使用戶切換到其他應(yīng)用梁钾,服務(wù)仍將在后臺繼續(xù)運(yùn)行绳泉。 此外,組件可以綁定到服務(wù)姆泻,以與之進(jìn)行交互零酪,甚至是執(zhí)行進(jìn)程間通信 (IPC)。
例如拇勃,服務(wù)可以處理網(wǎng)絡(luò)事務(wù)四苇、播放音樂,執(zhí)行文件 I/O 或與內(nèi)容提供程序交互方咆,而所有這一切均可在后臺進(jìn)行月腋。
服務(wù)分為兩種形式:
啟動:當(dāng)應(yīng)用組件(如 Activity)通過調(diào)用startService()啟動服務(wù)時,服務(wù)即處于“啟動”狀態(tài)峻呛。一旦啟動,服務(wù)即可在后臺無限期運(yùn)行辜窑,即使啟動服務(wù)的組件已被銷毀也不受影響钩述。 已啟動的服務(wù)通常是執(zhí)行單一操作,而且不會將結(jié)果返回給調(diào)用方穆碎。例如牙勘,它可能通過網(wǎng)絡(luò)下載或上傳文件。 操作完成后,服務(wù)會自行停止運(yùn)行方面。
綁定:當(dāng)應(yīng)用組件通過調(diào)用bindService()綁定到服務(wù)時放钦,服務(wù)即處于“綁定”狀態(tài)。綁定服務(wù)提供了一個客戶端-服務(wù)器接口恭金,允許組件與服務(wù)進(jìn)行交互操禀、發(fā)送請求、獲取結(jié)果横腿,甚至是利用進(jìn)程間通信 (IPC) 跨進(jìn)程執(zhí)行這些操作颓屑。 僅當(dāng)與另一個應(yīng)用組件綁定時,綁定服務(wù)才會運(yùn)行耿焊。 多個組件可以同時綁定到該服務(wù)揪惦,但全部取消綁定后,該服務(wù)即會被銷毀罗侯。
您的服務(wù)可以同時以這兩種方式運(yùn)行器腋,也就是說,它既可以是啟動服務(wù)(以無限期運(yùn)行)钩杰,也允許綁定纫塌。問題只是在于您是否實(shí)現(xiàn)了一組回調(diào)方法:onStartCommand()(允許組件啟動服務(wù))和onBind()(允許綁定服務(wù))。
二榜苫、創(chuàng)建Service护戳。
要創(chuàng)建服務(wù),您必須創(chuàng)建Service的子類(或使用它的一個現(xiàn)有子類)垂睬。在實(shí)現(xiàn)中媳荒,您需要重寫一些回調(diào)方法,以處理服務(wù)生命周期的某些關(guān)鍵方面并提供一種機(jī)制將組件綁定到服務(wù)(如適用)驹饺。 應(yīng)重寫的最重要的回調(diào)方法包括:
onStartCommand():當(dāng)另一個組件(如 Activity)通過調(diào)用startService()請求啟動服務(wù)時钳枕,系統(tǒng)將調(diào)用此方法。一旦執(zhí)行此方法赏壹,服務(wù)即會啟動并可在后臺無限期運(yùn)行鱼炒。 如果您實(shí)現(xiàn)此方法,則在服務(wù)工作完成后蝌借,需要由您通過調(diào)用stopSelf()或stopService()來停止服務(wù)昔瞧。(如果您只想提供綁定,則無需實(shí)現(xiàn)此方法菩佑。)
onBind():當(dāng)另一個組件想通過調(diào)用bindService()與服務(wù)綁定(例如執(zhí)行 RPC)時自晰,系統(tǒng)將調(diào)用此方法。在此方法的實(shí)現(xiàn)中稍坯,您必須通過返回IBinder提供一個接口酬荞,供客戶端用來與服務(wù)進(jìn)行通信搓劫。請務(wù)必實(shí)現(xiàn)此方法,但如果您并不希望允許綁定混巧,則應(yīng)返回 null枪向。
onCreate():首次創(chuàng)建服務(wù)時,系統(tǒng)將調(diào)用此方法來執(zhí)行一次性設(shè)置程序(在調(diào)用onStartCommand()或onBind()之前)咧党。如果服務(wù)已在運(yùn)行秘蛔,則不會調(diào)用此方法。
onDestory():當(dāng)服務(wù)不再使用且將被銷毀時凿傅,系統(tǒng)將調(diào)用此方法缠犀。服務(wù)應(yīng)該實(shí)現(xiàn)此方法來清理所有資源,如線程聪舒、注冊的偵聽器辨液、接收器等。 這是服務(wù)接收的最后一個調(diào)用箱残。
如果組件通過調(diào)用startService()啟動服務(wù)(這會導(dǎo)致對onStartCommand()的調(diào)用)滔迈,則服務(wù)將一直運(yùn)行,直到服務(wù)使用stopSelf()自行停止運(yùn)行被辑,或由其他組件通過調(diào)用stopService()停止它為止燎悍。
如果組件是通過調(diào)用bindService()來創(chuàng)建服務(wù)(且未調(diào)用onStartcommand(),則服務(wù)只會在該組件與其綁定時運(yùn)行盼理。一旦該服務(wù)與所有客戶端之間的綁定全部取消谈山,系統(tǒng)便會銷毀它。
使用清單文件聲明服務(wù):
要聲明服務(wù)宏怔,請?zhí)砑?lt;service>元素作為<application>元素的子元素奏路。
<service ? ? ?description="string resource"
android:directBootAware=["true"|"false"]
android:enabled=["true"|"false"]
android:exported=["true"|"false"]
android:icon="drawable resource"
android:isolatedProcess=["true"|"false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" ? >
</service>
android:name屬性是唯一必需的屬性,用于指定服務(wù)的類名臊诊。應(yīng)用一旦發(fā)布鸽粉,即不應(yīng)更改此類名,如若不然抓艳,可能會存在因依賴顯式 Intent 啟動或綁定服務(wù)而破壞代碼的風(fēng)險(xiǎn).
為了確保應(yīng)用的安全性触机,請始終使用顯式 Intent 啟動或綁定Service,且不要為服務(wù)聲明 Intent 過濾器玷或。
啟動服務(wù):
啟動服務(wù)由另一個組件通過調(diào)用startService()啟動儡首,這會導(dǎo)致調(diào)用服務(wù)的onStartCommand()方法。
服務(wù)啟動之后偏友,其生命周期即獨(dú)立于啟動它的組件蔬胯,并且可以在后臺無限期地運(yùn)行,即使啟動服務(wù)的組件已被銷毀也不受影響约谈。 因此笔宿,服務(wù)應(yīng)通過調(diào)用stopSelf()結(jié)束工作來自行停止運(yùn)行,或者由另一個組件通過調(diào)用stopService()來停止它棱诱。
應(yīng)用組件(如 Activity)可以通過調(diào)用startService()方法并傳遞Intent對象(指定服務(wù)并包含待使用服務(wù)的所有數(shù)據(jù))來啟動服務(wù)泼橘。服務(wù)通過onStartCommand()方法接收此Intent。
例如迈勋,假設(shè)某 Activity 需要將一些數(shù)據(jù)保存到在線數(shù)據(jù)庫中炬灭。該 Activity 可以啟動一個協(xié)同服務(wù),并通過向startService()傳遞一個 Intent靡菇,為該服務(wù)提供要保存的數(shù)據(jù)重归。服務(wù)通過onStartCommand()接收 Intent,連接到互聯(lián)網(wǎng)并執(zhí)行數(shù)據(jù)庫事務(wù)厦凤。事務(wù)完成之后鼻吮,服務(wù)會自行停止運(yùn)行并隨即被銷毀。
您可以擴(kuò)展兩個類來創(chuàng)建啟動服務(wù):
Service?
這是適用于所有服務(wù)的基類较鼓。擴(kuò)展此類時椎木,必須創(chuàng)建一個用于執(zhí)行所有服務(wù)工作的新線程,因?yàn)槟J(rèn)情況下博烂,服務(wù)將使用應(yīng)用的主線程香椎,這會降低應(yīng)用正在運(yùn)行的所有 Activity 的性能。
IntentService
這是Service的子類禽篱,它使用工作線程逐一處理所有啟動請求畜伐。如果您不要求服務(wù)同時處理多個請求,這是最好的選擇躺率。 您只需實(shí)現(xiàn)onHandleIntent()方法即可玛界,該方法會接收每個啟動請求的 Intent,使您能夠執(zhí)行后臺工作肥照。
例如脚仔,Activity 可以結(jié)合使用顯式 Intent 與startService(),啟動上文中的示例服務(wù) (HelloService):
Intentintent=newIntent(this,HelloService.class);
startService(intent);
startService()方法將立即返回舆绎,且 Android 系統(tǒng)調(diào)用服務(wù)的onStartCommand()方法鲤脏。如果服務(wù)尚未運(yùn)行,則系統(tǒng)會先調(diào)用onCreate()吕朵,然后再調(diào)用onStartCommand()猎醇。
如果服務(wù)亦未提供綁定,則使用startService()傳遞的 Intent 是應(yīng)用組件與服務(wù)之間唯一的通信模式努溃。但是硫嘶,如果您希望服務(wù)返回結(jié)果,則啟動服務(wù)的客戶端可以為廣播創(chuàng)建一個PendingIntent(使用getBroadcast())梧税,并通過啟動服務(wù)的Intent傳遞給服務(wù)沦疾。然后称近,服務(wù)就可以使用廣播傳遞結(jié)果。
多個服務(wù)啟動請求會導(dǎo)致多次對服務(wù)的onStartCommand()進(jìn)行相應(yīng)的調(diào)用哮塞。但是刨秆,要停止服務(wù),只需一個服務(wù)停止請求(使用stopSelf()或stopService())即可忆畅。
停止服務(wù):
啟動服務(wù)必須管理自己的生命周期衡未。也就是說,除非系統(tǒng)必須回收內(nèi)存資源家凯,否則系統(tǒng)不會停止或銷毀服務(wù)缓醋,而且服務(wù)在onStartCommand()返回后會繼續(xù)運(yùn)行。因此绊诲,服務(wù)必須通過調(diào)用stopSelf()自行停止運(yùn)行送粱,或者由另一個組件通過調(diào)用stopService()來停止它。
一旦請求使用stopSelf()或stopService()停止服務(wù)掂之,系統(tǒng)就會盡快銷毀服務(wù)葫督。
但是,如果服務(wù)同時處理多個onStartCommand()請求板惑,則您不應(yīng)在處理完一個啟動請求之后停止服務(wù)橄镜,因?yàn)槟赡芤呀?jīng)收到了新的啟動請求(在第一個請求結(jié)束時停止服務(wù)會終止第二個請求)。為了避免這一問題冯乘,您可以使用stopSelf(int)確保服務(wù)停止請求始終基于最近的啟動請求洽胶。也就說,在調(diào)用stopSelf(int)時裆馒,傳遞與停止請求的 ID 對應(yīng)的啟動請求的 ID(傳遞給onStartCommand()的startId)姊氓。然后,如果在您能夠調(diào)用stopSelf(int)之前服務(wù)收到了新的啟動請求喷好,ID 就不匹配翔横,服務(wù)也就不會停止。
創(chuàng)建綁定服務(wù):
綁定服務(wù)允許應(yīng)用組件通過調(diào)用bindService()與其綁定梗搅,以便創(chuàng)建長期連接(通常不允許組件通過調(diào)用startService()來啟動它)禾唁。
如需與 Activity 和其他應(yīng)用組件中的服務(wù)進(jìn)行交互,或者需要通過進(jìn)程間通信 (IPC) 向其他應(yīng)用公開某些應(yīng)用功能无切,則應(yīng)創(chuàng)建綁定服務(wù)荡短。
要創(chuàng)建綁定服務(wù),必須實(shí)現(xiàn)onBind()回調(diào)方法以返回IBinder哆键,用于定義與服務(wù)通信的接口掘托。然后,其他應(yīng)用組件可以調(diào)用bindService()來檢索該接口籍嘹,并開始對服務(wù)調(diào)用方法闪盔。服務(wù)只用于與其綁定的應(yīng)用組件弯院,因此如果沒有組件綁定到服務(wù),則系統(tǒng)會銷毀服務(wù)(您不必按通過onStartCommand()啟動的服務(wù)那樣來停止綁定服務(wù))泪掀。
要創(chuàng)建綁定服務(wù)抽兆,首先必須定義指定客戶端如何與服務(wù)通信的接口。 服務(wù)與客戶端之間的這個接口必須是IBinder的實(shí)現(xiàn)族淮,并且服務(wù)必須從onBind()回調(diào)方法返回它。一旦客戶端收到IBinder凭涂,即可開始通過該接口與服務(wù)進(jìn)行交互祝辣。
多個客戶端可以同時綁定到服務(wù)∏杏停客戶端完成與服務(wù)的交互后蝙斜,會調(diào)用unbindService()取消綁定。一旦沒有客戶端綁定到該服務(wù)澎胡,系統(tǒng)就會銷毀它孕荠。
實(shí)現(xiàn)生命周期回調(diào)
左圖顯示了使用startService()所創(chuàng)建的服務(wù)的生命周期,右圖顯示了使用bindService()所創(chuàng)建的服務(wù)的生命周期攻谁。
通過實(shí)現(xiàn)這些方法稚伍,您可以監(jiān)控服務(wù)生命周期的兩個嵌套循環(huán):
整個生命周期:服務(wù)的整個生命周期從調(diào)用onCreate()開始起,到onDestroy()返回時結(jié)束戚宦。與 Activity 類似个曙,服務(wù)也在onCreate()中完成初始設(shè)置,并在onDestroy()中釋放所有剩余資源受楼。例如垦搬,音樂播放服務(wù)可以在onCreate()中創(chuàng)建用于播放音樂的線程,然后在onDestroy()中停止該線程艳汽。
無論服務(wù)是通過startService()還是bindService()創(chuàng)建猴贰,都會為所有服務(wù)調(diào)用onCreate()和onDestroy()方法。
有效生命周期:服務(wù)的有效生命周期從調(diào)用onStartCommand()或onBind()方法開始河狐。每種方法均有 {Intent對象米绕,該對象分別傳遞到startService()或bindService()。
對于啟動服務(wù)馋艺,有效生命周期與整個生命周期同時結(jié)束(即便是在onStartCommand()返回之后义郑,服務(wù)仍然處于活動狀態(tài))。對于綁定服務(wù)丈钙,有效生命周期在onUnbind()返回時結(jié)束非驮。