Android的四大組件之Service

一.基礎知識

Service概述:

Service是Android系統(tǒng)中的四大組件之一挥下,主要有兩個應用場景:后臺運行和跨進程訪問歉备。Service可以在后臺執(zhí)行長時間運行操作而不提供用戶界面,除非系統(tǒng)必須回收內(nèi)存資源,否則系統(tǒng)不會停止或銷毀服務。服務可由其他應用組件啟動,而且即使用戶切換到其他應用制跟,服務仍將在后臺繼續(xù)運行。此外酱虎,組件可以綁定到服務雨膨,以與之進行交互,甚至是執(zhí)行進程間通信(IPC)需要注意的是读串,Service是在主線程里執(zhí)行操作的聊记,可能會因為執(zhí)行耗時操作而導致ANR

Service可以分為三種形式:

啟動

當應用組件通過調(diào)用startService()啟動服務時,服務即處于“啟動”狀態(tài)恢暖。一旦啟動排监,服務即可在后臺無期限運行,即使啟動服務的組件已被銷毀也不受影響杰捂。已啟動的服務通常是執(zhí)行單一操作舆床,而且不會將結果返回給調(diào)用方

綁定

當應用組件通過調(diào)用bindService()綁定到服務時,服務即處于“綁定”狀態(tài)嫁佳。綁定服務提供了一個客戶端-服務端的接口峭弟,運行組件與服務進行交互,甚至是利用進程間通信(IPC)跨進程執(zhí)行這些操作脱拼。多個組件可以同時綁定服務瞒瘸,服務指揮在組件與其綁定時運行,一旦該服務與所有組件的綁定取消熄浓,系統(tǒng)便會銷毀它情臭。

啟動且綁定

既通過startService()啟動了服務,也進行了綁定赌蔑。此時需要同時實現(xiàn)以下回調(diào)方法:onstartCommand()onBind()俯在。系統(tǒng)不會在所有客戶端都取消綁定時銷毀服務。為此娃惯,必須通過調(diào)用stopSelf()stopService()顯式停止服務跷乐。

無論應用是出于啟動狀態(tài)還是綁定狀態(tài),或者出于啟動且綁定狀態(tài)趾浅,任何應用組件均可使用Activity那樣通過Intent來使用服務(及時此服務來自另一應用)愕提,也可以通過清單文件將服務聲明未私有服務馒稍,阻止其他應用訪問

二.Service生命周期

要使用服務,必須繼承Service浅侨,在子類重寫某些回調(diào)方法纽谒,用來處理服務生命周期的某些關鍵方面并提供一種機制將組件綁定到服務

onStartCommand()

當組件通過startService()請求啟動服務時,系統(tǒng)將調(diào)用此方法如输。一旦執(zhí)行此方法鼓黔,服務即會啟動并可在后臺無限期運行。在指定任務完成后不见,通過stopSelf()stopService()來停止服務澳化。

onBind()

當一個組件想通過bindService()與服務綁定時,系統(tǒng)將調(diào)用此方法稳吮。在此方法中缎谷,必須通過返回IBinder提供一個接口,供客戶端來與服務進行通信

onCreate()

首次創(chuàng)建服務時盖高,系統(tǒng)將調(diào)用此方法來執(zhí)行初始化操作(在調(diào)用onStartCommand()onBind()之前)慎陵。如果在啟動或綁定之前Service已在運行,則不會調(diào)用此方法

onDestroy()

當服務不再使用且被銷毀時喻奥,系統(tǒng)將調(diào)用此方法席纽,這是服務接收的最后一個調(diào)用,在此方法應清理占用的資源

僅當內(nèi)存過低必須回收系統(tǒng)資源以供前臺Activity使用時撞蚕,系統(tǒng)才會強制停止服務如果將服務聲明為在前臺運行润梯,則它幾乎永遠不會終止∩茫或者纺铭,如果服務已啟動并要長時間運行,則系統(tǒng)會隨著時間的推移降低服務在后臺任務列表中的位置刀疙,而服務也將隨之變得非常容易被終止舶赔。如果服務是啟動服務,則必須將其設計為能夠妥善處理系統(tǒng)對它的重啟谦秧。 如果系統(tǒng)終止服務竟纳,那么一旦資源變得再次可用,系統(tǒng)便會重啟服務(這還取決于 onStartCommand() 的返回值)

三.啟動Service的兩種方式

如同其他組件一樣疚鲤,想要使用Service锥累,必須在清單文件中對其進行聲明聲明方式是添加service元素作為 < application >

元素的子元素,例如:

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:supportsRtl="true"

android:theme="@style/AppTheme">

StartService啟動服務

通過調(diào)用startService()啟動,服務啟動之后集歇,其生命周期即獨立于啟動它的組件桶略,并且可以在后臺無限期地運行,即使啟動服務的組件已被銷毀也不受影響。因此际歼,服務應通過調(diào)用 stopSelf() 來自行停止運行惶翻,或者由另一個組件調(diào)用stopService()來停止

可以通過擴展兩個類來創(chuàng)建啟動服務:

Service

這是所有服務的父類。擴展此類時蹬挺,如果要執(zhí)行耗時操作维贺,必須創(chuàng)建一個用于執(zhí)行操作的新線程它掂,因為默認情況下服務將運行于UI線程

IntentService

這是Service的子類巴帮,它使用工作線程逐一處理所有啟動請求。如果應用不需要同時處理多個請求虐秋,這是最好的選擇榕茧。IntentService只需實現(xiàn)構造函數(shù)與onHandleIntent()方法即可,onHandleIntent()方法會接收每個啟動請求的 Intent客给。

1.繼承Service

onCreate()方法只會在初始時調(diào)用一次用押,onStartCommand(Intent

intent, int flags, int

startId)方法會在每次點擊時都被調(diào)用,點擊“停止音樂”按鈕靶剑,onDestroy()方法會被調(diào)用

當中蜻拨,每次回調(diào)onStartCommand()方法時,參數(shù)“startId”的值都是遞增的桩引,startId用于唯一標識每次對Service發(fā)起的處理請求

如果服務同時處理多個onStartCommand()請求缎讼,則不應在處理完一個啟動請求之后立即銷毀服務,因為此時可能已經(jīng)收到了新的啟動請求坑匠,在第一個請求結束時停止服務會導致第二個請求被終止血崭。為了避免這一問題,可以使用stopSelf(int)確保服務停止請求始終基于最新一次的啟動請求厘灼。也就是說夹纫,如果調(diào)用stopSelf(int)方法的參數(shù)值與onStartCommand()接受到的最新的startId值不相符的話,stopSelf()方法就會失效设凹,從而避免終止尚未處理的請求

如果服務沒有提供綁定舰讹,則使用startService()傳遞的 Intent 是應用組件與服務之間唯一的通信模式。如果希望服務返回結果闪朱,則啟動服務的客戶端可以為廣播創(chuàng)建一個 PendingIntent (使用getBroadcast())月匣,并通過啟動服務的 Intent 傳遞給服務。然后监透,服務就可以使用廣播傳遞結果

當中桶错,onStartCommand()方法必須返回一個整數(shù),用于描述系統(tǒng)應該如何應對服務被殺死的情況胀蛮,返回值必須是以下常量之一:

START_NOT_STICKY

如果系統(tǒng)在 onStartCommand() 返回后終止服務院刁,則除非有掛起 Intent 要傳遞,否則系統(tǒng)不會重建服務粪狼。這是最安全的選項退腥,可以避免在不必要時以及應用能夠輕松重啟所有未完成的作業(yè)時運行服務

START_STICKY

如果系統(tǒng)在 onStartCommand() 返回后終止服務任岸,則會重建服務并調(diào)用 onStartCommand(),但不會重新傳遞最后一個 Intent狡刘。相反享潜,除非有掛起 Intent 要啟動服務(在這種情況下,將傳遞這些 Intent )嗅蔬,否則系統(tǒng)會通過空 Intent 調(diào)用 onStartCommand()剑按。這適用于不執(zhí)行命令、但無限期運行并等待作業(yè)的媒體播放器(或類似服務)

START_REDELIVER_INTENT

如果系統(tǒng)在 onStartCommand() 返回后終止服務澜术,則會重建服務艺蝴,并通過傳遞給服務的最后一個 Intent 調(diào)用 onStartCommand()。任何掛起 Intent 均依次傳遞鸟废。這適用于主動執(zhí)行應該立即恢復的作業(yè)(例如下載文件)的服務

2.繼承IntentSerice

由于大多數(shù)啟動服務都不必同時處理多個請求猜敢,因此使用 IntentService 類實現(xiàn)服務也許是最好的選擇

IntentService 執(zhí)行以下操作:

創(chuàng)建默認的工作線程,用于在應用的主線程外執(zhí)行傳遞給 onStartCommand() 的所有 Intent

創(chuàng)建工作隊列盒延,用于將 Intent 逐一傳遞給 onHandleIntent() 實現(xiàn)缩擂,這樣就不必擔心多線程問題

在處理完所有啟動請求后停止服務,因此不必自己調(diào)用 stopSelf()方法

提供 onBind() 的默認實現(xiàn)(返回 null)

提供 onStartCommand() 的默認實現(xiàn)添寺,可將 Intent 依次發(fā)送到工作隊列和 onHandleIntent()

因此胯盯,只需實現(xiàn)構造函數(shù)與 onHandleIntent() 方法即可

BindService綁定服務

應用組件(客戶端)通過調(diào)用 bindService() 綁定到服務,綁定是異步的畦贸,系統(tǒng)隨后調(diào)用服務的

onBind() 方法陨闹,該方法返回用于與服務交互的 IBinder。要接收 IBinder薄坏,客戶端必須提供一個 ServiceConnection

實例用于監(jiān)控與服務的連接趋厉,并將其傳遞給 bindService()。當 Android

系統(tǒng)創(chuàng)建了客戶端與服務之間的連接時胶坠,會回調(diào)ServiceConnection對象的onServiceConnected()方法君账,向客戶端傳遞用來與服務通信的

IBinder

多個客戶端可同時連接到一個服務。不過沈善,只有在第一個客戶端綁定時乡数,系統(tǒng)才會調(diào)用服務的 onBind()

方法來檢索 IBinder。系統(tǒng)隨后無需再次調(diào)用 onBind()闻牡,便可將同一 IBinder

傳遞至其他綁定的客戶端净赴。當所有客戶端都取消了與服務的綁定后,系統(tǒng)會將服務銷毀(除非 startService() 也啟動了該服務)

另外罩润,只有 Activity玖翅、服務和內(nèi)容提供者可以綁定到服務,無法從廣播接收器綁定到服務

可以通過以下三種方法定義IBinder接口:

擴展 Binder 類

如果服務是供本應用專用,并且運行在與客戶端相同的進程中金度,則應通過擴展 Binder 類并從 onBind() 返回它的一個實例來創(chuàng)建接口应媚。客戶端收到 Binder 后猜极,可利用它直接訪問 Service 中可用的公共方法

使用 Messenger

如需讓接口跨不同的進程工作中姜,則可使用 Messenger 為服務創(chuàng)建接口。服務可以這種方式定義對應于不同類型 Message 對象的 Handler跟伏。此 Handler 是 Messenger 的基礎丢胚,后者隨后可與客戶端分享一個 IBinder,從而讓客戶端能利用 Message 對象向服務發(fā)送命令酬姆。此外嗜桌,客戶端還可定義自有 Messenger奥溺,以便服務回傳消息辞色。這是執(zhí)行進程間通信 (IPC) 的最簡單方法,因為 Messenger 會在單一線程中創(chuàng)建包含所有請求的隊列浮定,這樣就不必對服務進行線程安全設計

使用 AIDL

AIDL(Android 接口定義語言)執(zhí)行所有將對象分解成原語的工作相满,操作系統(tǒng)可以識別這些原語并將它們編組到各進程中,以執(zhí)行 IPC桦卒。 之前采用 Messenger 的方法實際上是以 AIDL 作為其底層結構立美。 如上所述,Messenger 會在單一線程中創(chuàng)建包含所有客戶端請求的隊列方灾,以便服務一次接收一個請求建蹄。 不過,如果想讓服務同時處理多個請求裕偿,則可直接使用 AIDL洞慎。 在此情況下,服務必須具備多線程處理能力嘿棘,并采用線程安全式設計劲腿。如需直接使用 AIDL,必須創(chuàng)建一個定義編程接口的 .aidl 文件鸟妙。Android SDK 工具利用該文件生成一個實現(xiàn)接口并處理 IPC 的抽象類焦人,隨后可在服務內(nèi)對其進行擴展

在前臺運行Service

前臺服務被認為是用戶主動意識到的一種服務,因此在內(nèi)存不足時重父,系統(tǒng)也不會考慮將其終止花椭。 前臺服務必須在狀態(tài)欄提供通知,放在“正在進行”標題下方房午,這意味著除非服務停止或從前臺移除矿辽,否則不能清除通知

要請求讓服務運行于前臺,要調(diào)用

startForeground()方法,兩個參數(shù)分別是:唯一標識通知的int類型整數(shù)和Notification對象

NotificationCompat.Builder mBuilder =? newNotificationCompat.Builder(this);

?mBuilder.setSmallIcon(R.drawable.bird);

?mBuilder.setContentTitle("這是標題吧~葉應是葉");

?mBuilder.setContentText("http://blog.csdn.net/new_one_object");

?startForeground(1, mBuilder.build());

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗦锐,一起剝皮案震驚了整個濱河市嫌松,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奕污,老刑警劉巖萎羔,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碳默,居然都是意外死亡贾陷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門嘱根,熙熙樓的掌柜王于貴愁眉苦臉地迎上來髓废,“玉大人,你說我怎么就攤上這事该抒』藕椋” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵凑保,是天一觀的道長冈爹。 經(jīng)常有香客問我,道長欧引,這世上最難降的妖魔是什么频伤? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮芝此,結果婚禮上憋肖,老公的妹妹穿的比我還像新娘。我一直安慰自己婚苹,他們只是感情好岸更,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著租副,像睡著了一般坐慰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上用僧,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天结胀,我揣著相機與錄音,去河邊找鬼责循。 笑死糟港,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的院仿。 我是一名探鬼主播秸抚,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼速和,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了剥汤?” 一聲冷哼從身側響起颠放,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吭敢,沒想到半個月后碰凶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡鹿驼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年欲低,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畜晰。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡砾莱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凄鼻,到底是詐尸還是另有隱情腊瑟,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布野宜,位于F島的核電站扫步,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匈子。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一闯袒、第九天 我趴在偏房一處隱蔽的房頂上張望虎敦。 院中可真熱鬧,春花似錦政敢、人聲如沸其徙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唾那。三九已至,卻和暖如春褪尝,著一層夾襖步出監(jiān)牢的瞬間闹获,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工河哑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留避诽,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓璃谨,卻偏偏與公主長得像沙庐,于是被迫代替她去往敵國和親鲤妥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

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

  • 服務基本上分為兩種形式 啟動 當應用組件(如 Activity)通過調(diào)用 startService() 啟動服務時...
    pifoo閱讀 1,272評論 0 8
  • [文章內(nèi)容來自Developers] Service是一個可以在后臺執(zhí)行長時間運行操作而不提供用戶界面的應用組件拱雏。...
    岳小川閱讀 865評論 0 7
  • 2.1 Activity 2.1.1 Activity的生命周期全面分析 典型情況下的生命周期:在用戶參與的情況下...
    AndroidMaster閱讀 3,040評論 0 8
  • 【Android Service】 Service 簡介(★★★) 很多情況下棉安,一些與用戶很少需要產(chǎn)生交互的應用程...
    Rtia閱讀 3,154評論 1 21
  • 傅盛在認知升級三部曲中提到認知升級中存在兩個誤區(qū): 1.以為自己知道,遠遠不如以為自己不知道 2.以為自己認為重要...
    鄧文達閱讀 466評論 0 0