自我提升(基礎(chǔ)技術(shù)篇)——消息傳遞模塊(廣播,intent片择,handler)廣播篇

前言:或許有人會(huì)疑問潜的,為什么要把這三兄弟,寫在一起字管,因?yàn)椋簭V播啰挪,intent,handler都是Android自己的消息傳遞機(jī)制

廣播機(jī)制

概述

Android廣播分為兩個(gè)方面:廣播發(fā)送者廣播接收者嘲叔,通常情況下亡呵,BroadcastReceiver指的就是廣播接收者(廣播接收器)。廣播作為Android組件間的通信方式硫戈,可以使用的場景如下:

1.同一app內(nèi)部的同一組件內(nèi)的消息通信(單個(gè)或多個(gè)線程之間)锰什;

2.同一app內(nèi)部的不同組件之間的消息通信(單個(gè)進(jìn)程);

3.同一app具有多個(gè)進(jìn)程的不同組件之間的消息通信

4.不同app之間的組件之間消息通信歇由;

5.Android系統(tǒng)在特定情況下與App之間的消息通信卵牍。比如果港,網(wǎng)絡(luò)斷開與連接

從實(shí)現(xiàn)原理看上沦泌,Android中的廣播使用了觀察者模式,基于消息的發(fā)布/訂閱事件模型辛掠。因此谢谦,從實(shí)現(xiàn)的角度來看,Android中的廣播將廣播的發(fā)送者接受者極大程度上解耦萝衩,使得系統(tǒng)能夠方便集成回挽,更易擴(kuò)展。具體實(shí)現(xiàn)流程要點(diǎn)粗略概括如下:

1.廣播接收者BroadcastReceiver通過Binder機(jī)制AMS(Activity Manager Service)進(jìn)行注冊(cè)猩谊;(binder機(jī)制和AMS千劈,這里不介紹径荔,后面再詳細(xì)講)

2.廣播發(fā)送者通過binder機(jī)制向AMS發(fā)送廣播驮樊;

3.AMS查找符合相應(yīng)條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發(fā)送到BroadcastReceiver(一般情況下是Activity)相應(yīng)的消息循環(huán)隊(duì)列中魄缚;(這里同樣不講暗甥,消息隊(duì)列喜滨,后面再說)

4.消息循環(huán)執(zhí)行拿到此廣播,回調(diào)BroadcastReceiver中的onReceive()方法撤防。

對(duì)于不同的廣播類型虽风,以及不同的BroadcastReceiver注冊(cè)方式,具體實(shí)現(xiàn)上會(huì)有不同寄月。但總體流程大致如上辜膝。

廣播發(fā)送者和廣播接收者分別屬于觀察者模式中的消息發(fā)布和訂閱兩端,AMS屬于中間的處理中心漾肮。廣播發(fā)送者和廣播接收者的執(zhí)行是異步的厂抖,發(fā)出去的廣播不會(huì)關(guān)心有無接收者接收,也不確定接收者到底是何時(shí)才能接收到初橘。EventBus和Rxjava就和這個(gè)比較相似验游。

在上文說列舉的廣播機(jī)制具體可以使用的場景中,現(xiàn)分析實(shí)際應(yīng)用中的適用性

第一種情形:同一app內(nèi)部的同一組件內(nèi)的消息通信(單個(gè)或多個(gè)線程之間)保檐,實(shí)際應(yīng)用中肯定是不會(huì)用到廣播機(jī)制的(雖然可以用)耕蝉,無論是使用擴(kuò)展變量作用域、基于接口的回調(diào)還是Handler-post/Handler-Message等方式夜只,都可以直接處理此類問題垒在,若適用廣播機(jī)制,顯然有些“殺雞牛刀”的感覺扔亥,會(huì)顯太“重”场躯;

第二種情形:同一app內(nèi)部的不同組件之間的消息通信(單個(gè)進(jìn)程)谈为,對(duì)于此類需求,在有些教復(fù)雜的情況下單純的依靠基于接口的回調(diào)等方式不好處理踢关,此時(shí)可以直接使用EventBus等伞鲫,相對(duì)而言,EventBus由于是針對(duì)統(tǒng)一進(jìn)程签舞,用于處理此類需求非常適合秕脓,且輕松解耦。

第三儒搭、四吠架、五情形:個(gè)人暫時(shí)找不出多好的例子。

BroadcastReceiver(廣播接收)

主要講怎么用:

自定義BroadcastReceiver:


自定義廣播接收器需要繼承基類BroadcastReceivre搂鲫,并實(shí)現(xiàn)抽象方法onReceive(context, intent)方法傍药。廣播接收器接收到相應(yīng)廣播后,會(huì)自動(dòng)回到onReceive(..)方法魂仍。默認(rèn)情況下拐辽,廣播接收器也是運(yùn)行在UI線程,因此蓄诽,onReceive方法中不能執(zhí)行太耗時(shí)的操作薛训。否則將因此ANR。一般情況下仑氛,根據(jù)實(shí)際業(yè)務(wù)需求乙埃,onReceive方法中都會(huì)涉及到與其他組件之間的交互,如發(fā)送Notification锯岖、啟動(dòng)service等介袜。

下面代碼片段是一個(gè)簡單的廣播接收器的自定義:

BroadcastReceiver注冊(cè):

BroadcastReceiver總體上可以分為兩種注冊(cè)類型:靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè)。

靜態(tài)注冊(cè):


其中出吹,intent-filter由于指定此廣播接收器將用于接收特定的廣播類型遇伞。本示例中給出的是用于接收網(wǎng)絡(luò)狀態(tài)改變或開啟啟動(dòng)時(shí)系統(tǒng)自身所發(fā)出的廣播。當(dāng)此App首次啟動(dòng)時(shí)捶牢,系統(tǒng)會(huì)自動(dòng)實(shí)例化MyBroadcastReceiver鸠珠,并注冊(cè)到系統(tǒng)中。

動(dòng)態(tài)注冊(cè)

動(dòng)態(tài)注冊(cè)時(shí)秋麸,無須在AndroidManifest中注冊(cè)組件渐排。直接在代碼中通過調(diào)用Context的registerReceiver函數(shù),可以在程序中動(dòng)態(tài)注冊(cè)BroadcastReceiver灸蟆。registerReceiver的定義形式如下:


注:Android中所有與觀察者模式有關(guān)的設(shè)計(jì)中驯耻,一旦涉及到register,必定在相應(yīng)的時(shí)機(jī)需要unregister。因此可缚,上例在onDestroy()回到中需要unregisterReceiver(mBroadcastReceiver)霎迫。

廣播發(fā)送及廣播類型:

廣播發(fā)送

經(jīng)常說”發(fā)送廣播“和”接收“,表面上看廣播作為Android廣播機(jī)制中的實(shí)體帘靡,實(shí)際上這一實(shí)體本身是并不是以所謂的”廣播“對(duì)象存在的知给,而是以”意圖“(Intent)去表示。定義廣播的定義過程测柠,實(shí)際就是相應(yīng)廣播”意圖“的定義過程炼鞠,然后通過廣播發(fā)送者將此”意圖“發(fā)送出去缘滥。被相應(yīng)的BroadcastReceiver接收后將會(huì)回調(diào)onReceive()函數(shù)轰胁。

下段代碼片段顯示的是一個(gè)普通廣播的定義過程,并發(fā)送出去朝扼。其中setAction(..)對(duì)應(yīng)于BroadcastReceiver中的intentFilter中的action赃阀。

Intent intent = new Intent();

?intent.setAction(BROADCAST_ACTION);

?intent.putExtra("name", "hello");

?sendBroadcast(intent);

廣播類型

Normal Broadcast:普通廣播

System Broadcast: 系統(tǒng)廣播

Ordered broadcast:有序廣播

Sticky Broadcast:粘性廣播(在 android 5.0/api 21中deprecated,不再推薦使用,相應(yīng)的還有粘性有序廣播擎颖,同樣已經(jīng)deprecated)

Local Broadcast:App應(yīng)用內(nèi)廣播

各種類型的發(fā)送方式及其特點(diǎn)

Normal Broadcast:普通廣播

此處將普通廣播界定為:開發(fā)者自己定義的intent榛斯,以context.sendBroadcast(intent, ...)形式。具體可以使用的方法有:

sendBroadcast(intent)

sendBroadcast(intent, receiverPermission)

sendBroadcastAsUser(intent, userHandler)

sendBroadcastAsUser(intent, userHandler ,receiverPermission)搂捧。

普通廣播會(huì)被注冊(cè)了的相應(yīng)的intent-filter匹配接收驮俗,且順序是無序的。如果發(fā)送廣播時(shí)有相應(yīng)的權(quán)限要求允跑,BroadCastReceiver如果想要接收此廣播王凑,也需要有相應(yīng)的權(quán)限。(通常情況下聋丝,就用的第一種索烹,通過傳一個(gè)intent來實(shí)現(xiàn)消息傳遞)

System Broadcast: 系統(tǒng)廣播

Android系統(tǒng)中內(nèi)置了多個(gè)系統(tǒng)廣播,只要涉及到手機(jī)的基本操作弱睦,基本上都會(huì)發(fā)出相應(yīng)的系統(tǒng)廣播百姓。如:開啟啟動(dòng),網(wǎng)絡(luò)狀態(tài)改變况木,拍照垒拢,屏幕關(guān)閉與開啟,點(diǎn)亮不足等等火惊。每個(gè)系統(tǒng)廣播都具有特定的intent-filter求类,其中主要包括具體的action,系統(tǒng)廣播發(fā)出后矗晃,將被相應(yīng)的BroadcastReceiver接收仑嗅。系統(tǒng)廣播在系統(tǒng)內(nèi)部當(dāng)特定事件發(fā)生時(shí),有系統(tǒng)自動(dòng)發(fā)出。

Ordered broadcast:有序廣播

有序廣播的有序廣播中的“有序”是針對(duì)廣播接收者而言的仓技,指的是發(fā)送出去的廣播被BroadcastReceiver按照先后循序接收鸵贬。有序廣播的定義過程與普通廣播無異,只是其的主要發(fā)送方式變?yōu)椋簊endOrderedBroadcast(intent, receiverPermission, ...)脖捻。

1.多個(gè)當(dāng)前已經(jīng)注冊(cè)且有效的BroadcastReceiver接收有序廣播時(shí)阔逼,是按照先后順序接收的,先后順序判定標(biāo)準(zhǔn)遵循為:將當(dāng)前系統(tǒng)中所有有效的動(dòng)態(tài)注冊(cè)和靜態(tài)注冊(cè)的BroadcastReceiver按照priority屬性值從大到小排序地沮,對(duì)于具有相同的priority的動(dòng)態(tài)廣播和靜態(tài)廣播嗜浮,動(dòng)態(tài)廣播會(huì)排在前面。

2.先接收的BroadcastReceiver可以對(duì)此有序廣播進(jìn)行截?cái)嗄σ桑购竺娴腂roadcastReceiver不再接收到此廣播危融,也可以對(duì)廣播進(jìn)行修改,使后面的BroadcastReceiver接收到廣播后解析得到錯(cuò)誤的參數(shù)值雷袋。當(dāng)然吉殃,一般情況下,不建議對(duì)有序廣播進(jìn)行此類操作楷怒,尤其是針對(duì)系統(tǒng)中的有序廣播蛋勺。

Sticky Broadcast:粘性廣播(在 android 5.0/api 21中deprecated,不再推薦使用,相應(yīng)的還有粘性有序廣播鸠删,同樣已經(jīng)deprecated)抱完。

不再多做總結(jié)。

Local Broadcast:App應(yīng)用內(nèi)廣播(此處的App應(yīng)用以App應(yīng)用進(jìn)程為界)

由前文闡述可知刃泡,Android中的廣播可以跨進(jìn)程甚至跨App直接通信巧娱,且注冊(cè)是exported對(duì)于有intent-filter的情況下默認(rèn)值是true,由此將可能出現(xiàn)安全隱患如下:

1.其他App可能會(huì)針對(duì)性的發(fā)出與當(dāng)前App intent-filter相匹配的廣播捅僵,由此導(dǎo)致當(dāng)前App不斷接收到廣播并處理家卖;

2.其他App可以注冊(cè)與當(dāng)前App一致的intent-filter用于接收廣播,獲取廣播具體信息庙楚。

無論哪種情形上荡,這些安全隱患都確實(shí)是存在的。由此馒闷,最常見的增加安全性的方案是:

1.對(duì)于同一App內(nèi)部發(fā)送和接收廣播酪捡,將exported屬性人為設(shè)置成false,使得非本App內(nèi)部發(fā)出的此廣播不被接收纳账;

2.在廣播發(fā)送和接收時(shí)逛薇,都增加上相應(yīng)的permission,用于權(quán)限驗(yàn)證疏虫;

3.發(fā)送廣播時(shí)永罚,指定特定廣播接收器所在的包名啤呼,具體是通過intent.setPackage(packageName)指定在,這樣此廣播將只會(huì)發(fā)送到此包中的App內(nèi)與之相匹配的有效廣播接收器中呢袱。

當(dāng)然官扣,以上這些問題,其實(shí)羞福,遇到的情況并不多惕蹄,不過安全起見,寫上吧治专。當(dāng)然卖陵,懶一點(diǎn),也可以不寫张峰。

App應(yīng)用內(nèi)廣播可以理解成一種局部廣播的形式泪蔫,廣播的發(fā)送者和接收者都同屬于一個(gè)App。實(shí)際的業(yè)務(wù)需求中挟炬,App應(yīng)用內(nèi)廣播確實(shí)可能需要用到鸥滨。同時(shí),之所以使用應(yīng)用內(nèi)廣播時(shí)谤祖,而不是使用全局廣播的形式,更多的考慮到的是Android廣播機(jī)制中的安全性問題老速。

相比于全局廣播粥喜,App應(yīng)用內(nèi)廣播優(yōu)勢(shì)體現(xiàn)在:

1.安全性更高;

2.更加高效橘券。

為此额湘,Android v4兼容包中給出了封裝好的LocalBroadcastManager類,用于統(tǒng)一處理App應(yīng)用內(nèi)的廣播問題旁舰,使用方式上與通常的全局廣播幾乎相同锋华,只是注冊(cè)/取消注冊(cè)廣播接收器和發(fā)送廣播時(shí)將主調(diào)context變成了LocalBroadcastManager的單一實(shí)例。

//registerReceiver(mBroadcastReceiver, intentFilter);

//注冊(cè)應(yīng)用內(nèi)廣播接收器

localBroadcastManager = LocalBroadcastManager.getInstance(this);

localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

//unregisterReceiver(mBroadcastReceiver);

//取消注冊(cè)應(yīng)用內(nèi)廣播接收器

localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

Intent intent =new Intent();

intent.setAction(BROADCAST_ACTION);

intent.putExtra("name", "helllo");

//sendBroadcast(intent);

//發(fā)送應(yīng)用內(nèi)廣播

localBroadcastManager.sendBroadcast(intent);

不同注冊(cè)方式的廣播接收器回調(diào)onReceive(context, intent)中的context具體類型

對(duì)于靜態(tài)注冊(cè)的ContextReceiver箭窜,回調(diào)onReceive(context, intent)中的context具體指的是ReceiverRestrictedContext毯焕;

對(duì)于全局廣播的動(dòng)態(tài)注冊(cè)的ContextReceiver,回調(diào)onReceive(context, intent)中的context具體指的是Activity Context磺樱;

對(duì)于通過LocalBroadcastManager動(dòng)態(tài)注冊(cè)的ContextReceiver纳猫,回調(diào)onReceive(context, intent)中的context具體指的是Application Context。

注:對(duì)于LocalBroadcastManager方式發(fā)送的應(yīng)用內(nèi)廣播竹捉,只能通過LocalBroadcastManager動(dòng)態(tài)注冊(cè)的ContextReceiver才有可能接收到(靜態(tài)注冊(cè)或其他方式動(dòng)態(tài)注冊(cè)的ContextReceiver是接收不到的)芜辕。

ok,廣播块差,就介紹這么多侵续,如果還有什么疑問倔丈,自行百度,筆者状蜗,就不多解釋了乃沙。

本來想把intent和hadler都寫一起的,后來發(fā)現(xiàn)诗舰,篇幅太長了警儒,所以,就分隔到下一篇了眶根。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蜀铲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子属百,更是在濱河造成了極大的恐慌记劝,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件族扰,死亡現(xiàn)場離奇詭異厌丑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)渔呵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門怒竿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扩氢,你說我怎么就攤上這事耕驰。” “怎么了录豺?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵朦肘,是天一觀的道長。 經(jīng)常有香客問我双饥,道長媒抠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任咏花,我火速辦了婚禮趴生,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迟螺。我一直安慰自己冲秽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布矩父。 她就那樣靜靜地躺著锉桑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪窍株。 梳的紋絲不亂的頭發(fā)上民轴,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天攻柠,我揣著相機(jī)與錄音,去河邊找鬼后裸。 笑死瑰钮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的微驶。 我是一名探鬼主播浪谴,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼因苹!你這毒婦竟也來了苟耻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤扶檐,失蹤者是張志新(化名)和其女友劉穎凶杖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體款筑,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡智蝠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奈梳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杈湾。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖颈嚼,靈堂內(nèi)的尸體忽然破棺而出毛秘,到底是詐尸還是另有隱情,我是刑警寧澤阻课,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站艰匙,受9級(jí)特大地震影響限煞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜员凝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一署驻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧健霹,春花似錦旺上、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞳别,卻和暖如春征候,著一層夾襖步出監(jiān)牢的瞬間杭攻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工疤坝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兆解,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓跑揉,卻偏偏與公主長得像锅睛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子历谍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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