寫給Android App開發(fā)人員看的Android底層知識(shí)(6)

?(十一)BroadcastReceiver

?BroadcastReceiver评姨,也就是廣播,簡稱Receiver萤晴。

?很多App開發(fā)人員表示吐句,從來沒用過Receiver。其實(shí)吧店读,對(duì)于音樂播放類App嗦枢,用Service和Receiver還是蠻多的,如果你用過QQ音樂屯断,App退到后臺(tái)文虏,音樂照樣播放不會(huì)停止,這就是你寫的Service在后臺(tái)起作用裹纳。

?在前臺(tái)的Activity择葡,點(diǎn)擊停止按鈕,就會(huì)給后臺(tái)Service發(fā)送一個(gè)Receiver剃氧,通知它停止播放音樂敏储;點(diǎn)擊播放按鈕,仍然是發(fā)送這個(gè)Receiver朋鞍,只是攜帶的值變了已添,所以Service收到請(qǐng)求后播放音樂妥箕。

?反過來,后臺(tái)Service播放每播放完一首音樂更舞,接下來準(zhǔn)備播放下一首音樂的時(shí)候畦幢,就會(huì)給前臺(tái)Activity發(fā)Receiver,讓Activity顯示下一首音樂的名稱缆蝉。

?所以音樂播放器的原理宇葱,就是一個(gè)前后臺(tái)Activity和Service互相發(fā)送和接收Receiver的過程。

?Receiver分靜態(tài)廣播和動(dòng)態(tài)廣播兩種刊头。

?在Manifest中聲明的Receiver黍瞧,是靜態(tài)廣播:

在程序中手動(dòng)寫注冊(cè)代碼的,是動(dòng)態(tài)廣播:

?二者具有相同的功能原杂,只是寫法不同印颤。既然如此,我們就可以把所有靜態(tài)廣播穿肄,都改為動(dòng)態(tài)廣播年局,這就省的在Manifest文件中聲明了,避免了AMS檢查咸产。接下來你想到什么矢否?對(duì),Receiver的插件化解決方案锐朴,就是這個(gè)思路兴喂。

? 接下來我們看Receiver是怎么和AMS打交道的,分為兩部分焚志,一是注冊(cè)衣迷,二是發(fā)送廣播。

?你只有注冊(cè)了這個(gè)廣播酱酬,發(fā)送這個(gè)廣播時(shí)壶谒,才能通知到你,執(zhí)行onReceive方法膳沽。

?我們就拿音樂播放器來舉例汗菜,在Activity注冊(cè)Receiver,在Service發(fā)送廣播挑社。Service播放下一首音樂時(shí)陨界,會(huì)通知Activity修改當(dāng)前正在播放的音樂名稱。

?注冊(cè)過程如下所示:

  1. 1)在Activity中痛阻,注冊(cè)Receiver菌瘪,并通知AMS。

?這里Activity使用了Context提供的registerReceiver方法,然后通過AMN/AMP俏扩,把一個(gè)receiver傳給AMS糜工。

?在創(chuàng)建這個(gè)Receiver對(duì)象的時(shí)候,需要為receiver指定IntentFilter录淡,這個(gè)filter就是Receiver的身份證捌木,用來描述receiver。

?在Context的registerReceiver方法中嫉戚,它會(huì)使用PMS獲取到包的信息刨裆,也就是LoadedApk對(duì)象。

?就是這個(gè)LoadedApk對(duì)象彬檀,它的getReceiverDispatcher方法崔拥,將Receiver封裝成一個(gè)實(shí)現(xiàn)了IIntentReceiver接口的Binder對(duì)象。

?我們就是將這個(gè)Binder對(duì)象和filter傳遞給AMS凤覆。

?只傳遞Receiver給AMS是不夠的,當(dāng)發(fā)送廣播時(shí)拆魏,AMS不知道該發(fā)給誰岸㈣搿?所以Activity所在的進(jìn)程還要把自身對(duì)象也發(fā)送給AMS渤刃。

? 2)AMS收到消息后拥峦,就會(huì)把上面這些信息,存在一個(gè)列表中卖子,這個(gè)列表中保存了所有的Receiver略号。

?注意了,這里忙活半天洋闽,都是在注冊(cè)動(dòng)態(tài)receiver玄柠。

?靜態(tài)receiver什么時(shí)候注冊(cè)到AMS的呢?是在App安裝的時(shí)候诫舅。PMS會(huì)解析Manifest中的四大組件信息羽利,把其中的receiver存起來。

?動(dòng)態(tài)receiver和靜態(tài)receiver分別存在AMS不同的變量中刊懈,在發(fā)送廣播的時(shí)候这弧,會(huì)把兩種receiver合并到一起,然后以此發(fā)送虚汛。其中動(dòng)態(tài)的排在靜態(tài)的前面匾浪,所以動(dòng)態(tài)receiver永遠(yuǎn)優(yōu)先于靜態(tài)receiver收到消息。

?此外卷哩,Android系統(tǒng)每次啟動(dòng)的時(shí)候蛋辈,也會(huì)把靜態(tài)廣播接收者注冊(cè)到AMS。因?yàn)锳ndroid系統(tǒng)每次啟動(dòng)時(shí)殉疼,都會(huì)重新安裝所有的apk梯浪,詳細(xì)流程捌年,我們會(huì)在后面PMS的相關(guān)章節(jié)看到。

?- - - - - - - - - - - - - - - 華麗的分界線------------------------

?發(fā)送廣播的流程如下:

?1)在Service中挂洛,通過AMM/AMP礼预,發(fā)送廣播給AMS,廣播中攜帶著Filter虏劲。

?2)AMS收到這個(gè)廣播后托酸,在receiver列表中,根據(jù)filter找到對(duì)應(yīng)的receiver柒巫,可能是多個(gè)励堡,把它們都放到一個(gè)廣播隊(duì)列中。最后向AMS的消息隊(duì)列發(fā)送一個(gè)消息堡掏。

?當(dāng)消息隊(duì)列中的這個(gè)消息被處理時(shí)应结,AMS就從廣播隊(duì)列中找到合適的receiver,向廣播接收者所在的進(jìn)程發(fā)送廣播泉唁。

?3)receiver所在的進(jìn)程收到廣播鹅龄,并沒有把廣播直接發(fā)給receiver,而是將廣播封裝成一個(gè)消息亭畜,發(fā)送到主線程的消息隊(duì)列中扮休,當(dāng)這個(gè)消息被處理時(shí),才會(huì)把這個(gè)消息中的廣播發(fā)送給receiver拴鸵。

?我們下面通過圖玷坠,仔細(xì)看一下這3個(gè)階段:

?第1步,Service發(fā)送廣播給AMS

?發(fā)送廣播劲藐,是通過Intent這個(gè)參數(shù)八堡,攜帶了Filter,從而告訴AMS瘩燥,什么樣的receiver能接受這個(gè)廣播秕重。

?第2步,AMS接收廣播厉膀,發(fā)送廣播溶耘。

?接收廣播和發(fā)送廣播是不同步的。AMS每接收到一個(gè)廣播服鹅,就把它扔到廣播發(fā)送隊(duì)列中凳兵,至于發(fā)送是否成功,它就不管了企软。

?因?yàn)閞eceiver分為無序receiver和有序receiver庐扫,所以廣播發(fā)送隊(duì)列也分為兩個(gè),分別發(fā)送這兩種廣播。

?AMS發(fā)送廣播給客戶端形庭,這又是一個(gè)跨進(jìn)程通信铅辞,還是通過ATP,把消息發(fā)給APT萨醒。因?yàn)橐獋鬟fReceiver這個(gè)對(duì)象斟珊,所以它也是一個(gè)Binder對(duì)象,才可以傳過去富纸。我們前面說過囤踩,在把Receiver注冊(cè)到AMS的時(shí)候,會(huì)把Receiver封裝為一個(gè)IIntentReceiver接口的Binder對(duì)象晓褪。那么接下來堵漱,AMS就是把這個(gè)IIntentReceiver接口對(duì)象傳回來。

?第3步涣仿,App處理廣播

?這個(gè)流程描述如下:

?1)消息從AMS傳到客戶端勤庐,把AMS中的IIntentReceiver接口對(duì)象轉(zhuǎn)為InnerReceiver對(duì)象,這就是receiver好港,這是一個(gè)AIDL跨進(jìn)程通信埃元。

v2)然后在ReceiverDispatcher中封裝一個(gè)Args對(duì)象(這是一個(gè)Runnable對(duì)象,要實(shí)現(xiàn)run方法)媚狰,包括廣播接收者所需要的所有信息,交給ActivtyThread來發(fā)送

?3)接下來要走的路就是我們所熟悉的了阔拳,ActivtyThread把Args消息扔到H這個(gè)Hanlder中崭孤,向主線程消息隊(duì)列發(fā)送消息。等到執(zhí)行Args消息的時(shí)候糊肠,自然是執(zhí)行Args的run方法辨宠。

?4)在Args的run方法中,實(shí)例化一個(gè)Receiver對(duì)象货裹,調(diào)用它的onReceiver方法嗤形。

?5)最后,在Args的run方法中弧圆,隨著Receiver的onReceiver方法調(diào)用結(jié)束赋兵,會(huì)通過AMN/AMP發(fā)送一個(gè)消息個(gè)AMS,告訴AMS搔预,廣播發(fā)送成功了霹期。AMS得到通知后,就發(fā)送廣播給下一個(gè)Receiver拯田。

?注意:InnerReceiver是IIntentReceiver的stub历造,是Binder對(duì)象的接收端。

?廣播的種類

?Android廣播按發(fā)送方式分類有三種:無序廣播、有序廣播(OrderedBroadcast)和粘性廣播(StickyBroadcast)吭产。

?1)無序廣播是最普通的廣播侣监。

?2)有序廣播區(qū)別于無序廣播,就在于它可以指定優(yōu)先級(jí)臣淤。

這兩種receiver存在AMS不同的變量中橄霉,可以認(rèn)為是兩個(gè)receiver集合,發(fā)送不同類別的廣播荒典。

?3)粘性廣播是無序廣播的一種酪劫。

?粘性廣播,我們平常見的不多寺董,但我說一個(gè)場景你就明白了覆糟,那就是電池電量。當(dāng)電量小于20%的時(shí)候遮咖,就會(huì)提示用戶滩字。

?而獲取電池的電量信息,就是通過廣播來實(shí)現(xiàn)的御吞。

?但是一般的廣播麦箍,發(fā)完就完了。我們需要有這樣一種廣播陶珠,發(fā)出后挟裂,還能一直存在,未來的注冊(cè)者也能收到這個(gè)廣播揍诽,這種廣播就是粘性廣播诀蓉。

?由于動(dòng)態(tài)receiver只能在Activity的onCreate()方法調(diào)用時(shí)才能注冊(cè)再接收廣播,所以當(dāng)程序沒有運(yùn)行就不能接受到廣播暑脆;但是靜態(tài)注冊(cè)的則不依賴于程序是否處于運(yùn)行狀態(tài)渠啤。

?至此,關(guān)于廣播的所有概念添吗,就全都介紹完了沥曹,就連我都比較驚訝的是,我居然沒貼什么代碼碟联。希望上述這兩千多字妓美,能引導(dǎo)App開發(fā)人員進(jìn)入一個(gè)神奇的世界。

?下一篇文章鲤孵,我們?nèi)タ纯碈ontentProvider部脚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市裤纹,隨后出現(xiàn)的幾起案子委刘,更是在濱河造成了極大的恐慌丧没,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锡移,死亡現(xiàn)場離奇詭異呕童,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)淆珊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門夺饲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人施符,你說我怎么就攤上這事往声。” “怎么了戳吝?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵浩销,是天一觀的道長。 經(jīng)常有香客問我听哭,道長慢洋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任陆盘,我火速辦了婚禮普筹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘隘马。我一直安慰自己太防,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布酸员。 她就那樣靜靜地躺著杏头,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沸呐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天呢燥,我揣著相機(jī)與錄音崭添,去河邊找鬼。 笑死叛氨,一個(gè)胖子當(dāng)著我的面吹牛呼渣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播寞埠,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼屁置,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了仁连?” 一聲冷哼從身側(cè)響起蓝角,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤阱穗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后使鹅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揪阶,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年患朱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鲁僚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裁厅,死狀恐怖冰沙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情执虹,我是刑警寧澤拓挥,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站声畏,受9級(jí)特大地震影響撞叽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜插龄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一愿棋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧均牢,春花似錦糠雨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垮庐,卻和暖如春松邪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哨查。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工逗抑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寒亥。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓邮府,卻偏偏與公主長得像,于是被迫代替她去往敵國和親溉奕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褂傀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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