四大組件之二 -- Service

此章節(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é)束非驮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雏赦,隨后出現(xiàn)的幾起案子劫笙,更是在濱河造成了極大的恐慌芙扎,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件填大,死亡現(xiàn)場離奇詭異戒洼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)允华,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門圈浇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人靴寂,你說我怎么就攤上這事磷蜀。” “怎么了百炬?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵褐隆,是天一觀的道長。 經(jīng)常有香客問我剖踊,道長庶弃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任德澈,我火速辦了婚禮歇攻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梆造。我一直安慰自己掉伏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布澳窑。 她就那樣靜靜地躺著斧散,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摊聋。 梳的紋絲不亂的頭發(fā)上鸡捐,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機(jī)與錄音麻裁,去河邊找鬼箍镜。 笑死,一個胖子當(dāng)著我的面吹牛煎源,可吹牛的內(nèi)容都是我干的色迂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼手销,長吁一口氣:“原來是場噩夢啊……” “哼歇僧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诈悍,失蹤者是張志新(化名)和其女友劉穎祸轮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侥钳,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡适袜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了舷夺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苦酱。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖给猾,靈堂內(nèi)的尸體忽然破棺而出疫萤,到底是詐尸還是另有隱情,我是刑警寧澤耙册,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站毫捣,受9級特大地震影響详拙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔓同,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一饶辙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斑粱,春花似錦弃揽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尚揣,卻和暖如春涌矢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背快骗。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工娜庇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人方篮。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓名秀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親藕溅。 傳聞我的和親對象是個殘疾皇子匕得,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

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

  • [文章內(nèi)容來自Developers] Service是一個可以在后臺執(zhí)行長時間運(yùn)行操作而不提供用戶界面的應(yīng)用組件。...
    岳小川閱讀 865評論 0 7
  • 服務(wù)基本上分為兩種形式 啟動 當(dāng)應(yīng)用組件(如 Activity)通過調(diào)用 startService() 啟動服務(wù)時...
    pifoo閱讀 1,272評論 0 8
  • 前言:本文所寫的是博主的個人見解巾表,如有錯誤或者不恰當(dāng)之處耗跛,歡迎私信博主裕照,加以改正!原文鏈接调塌,demo鏈接 Serv...
    PassersHowe閱讀 1,413評論 0 5
  • 一段時間不用晋南,知識點(diǎn)就會忘,所以整理下一些基本的知識點(diǎn)羔砾,加深下印象负间,便于以后復(fù)習(xí)。這篇說一下Android中四大組...
    朋永閱讀 465評論 0 2
  • 蜜 夜 夜深沉姜凄,蟲鳴不絕耳 幽謐政溃,深邃,淡而遠(yuǎn) 窗前态秧,月光編織成的 白色帽子飄落至石階 透出優(yōu)雅絕倫的質(zhì)感 揀...
    瑞意雋永閱讀 775評論 7 18