Android 四大组件 —— 广播(广播机制解析)
?在網(wǎng)絡(luò)通信中,一個(gè)IP網(wǎng)絡(luò)范圍中最大的IP 地址是被保留作為廣播地址來使用的。比如某個(gè)網(wǎng)絡(luò)的IP 范圍是192.168.0.XXX,子網(wǎng)掩碼是255.255.255.0,那么這個(gè)網(wǎng)絡(luò)的廣播地址就是192.168.0.255。廣播數(shù)據(jù)包會(huì)被發(fā)送到同一網(wǎng)絡(luò)上的所有端口,這樣在該網(wǎng)絡(luò)中的每臺(tái)主機(jī)都將會(huì)收到這條廣播。
??????? 為了方便于進(jìn)行系統(tǒng)級(jí)別的消息通知,Android?也引入了一套類似的廣播消息機(jī)制。相比于我前面舉出的兩個(gè)例子,Android 中的廣播機(jī)制會(huì)顯得更加的靈活,本章就將對(duì)這一機(jī)制的方方面面進(jìn)行詳細(xì)的講解。
?
一、?廣播機(jī)制簡介
??????? 為什么說Android 中的廣播機(jī)制更加靈活呢?這是因?yàn)锳ndroid 中的每個(gè)應(yīng)用程序都可以對(duì)自己感興趣的廣播進(jìn)行注冊(cè),這樣該程序就只會(huì)接收到自己所關(guān)心的廣播內(nèi)容,這些廣播可能是來自于系統(tǒng)的,也可能是來自于其他應(yīng)用程序的。Android 提供了一套完整的API,允許應(yīng)用程序自由地發(fā)送和接收廣播。發(fā)送廣播的方法其實(shí)之前稍微有提到過一下,如果你記性好的話可能還會(huì)有印象,就是借助我們學(xué)過的Intent。而接收廣播的方法則需要引入一個(gè)新的概念,廣播接收器(Broadcast Receiver)。
??????? 廣播接收器的具體用法將會(huì)在下一節(jié)中做介紹,這里我們先來了解一下廣播的類型。Android 中的廣播主要可以分為兩種類型,標(biāo)準(zhǔn)廣播和有序廣播。
?????? 標(biāo)準(zhǔn)廣播(Normal broadcasts)是一種完全異步執(zhí)行的廣播,在廣播發(fā)出之后,所有的廣播接收器幾乎都會(huì)在同一時(shí)刻接收到這條廣播消息,因此它們之間沒有任何先后順序可言。這種廣播的效率會(huì)比較高,但同時(shí)也意味著它是無法被截?cái)嗟摹?biāo)準(zhǔn)廣播的工作流程如下圖:
?
??????有序廣播(Ordered broadcasts)則是一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時(shí)刻只會(huì)有一個(gè)廣播接收器能夠收到這條廣播消息,當(dāng)這個(gè)廣播接收器中的邏輯執(zhí)行完畢后,廣播才會(huì)繼續(xù)傳遞。所以此時(shí)的廣播接收器是有先后順序的,優(yōu)先級(jí)高的廣播接收器就可以先收到廣播消息,并且前面的廣播接收器還可以截?cái)嗾趥鬟f的廣播,這樣后面的廣播接收器就無法收到廣播消息了。有序廣播的工作流程如圖:
?
二、接收系統(tǒng)廣播
???????Android 內(nèi)置了很多系統(tǒng)級(jí)別的廣播,我們可以在應(yīng)用程序中通過監(jiān)聽這些廣播來得到各種系統(tǒng)的狀態(tài)信息。比如手機(jī)開機(jī)完成后會(huì)發(fā)出一條廣播,電池的電量發(fā)生變化會(huì)發(fā)出一條廣播,時(shí)間或時(shí)區(qū)發(fā)生改變也會(huì)發(fā)出一條廣播等等。如果想要接收到這些廣播,就需要使用廣播接收器,下面我們就來看一下它的具體用法。
1、 動(dòng)態(tài)注冊(cè)監(jiān)聽網(wǎng)絡(luò)變化
???????廣播接收器可以自由地對(duì)自己感興趣的廣播進(jìn)行注冊(cè),這樣當(dāng)有相應(yīng)的廣播發(fā)出時(shí),廣播接收器就能夠收到該廣播,并在內(nèi)部處理相應(yīng)的邏輯。注冊(cè)廣播的方式一般有兩種,在代碼中注冊(cè)和在AndroidManifest.xml 中注冊(cè),其中前者也被稱為動(dòng)態(tài)注冊(cè),后者也被稱為靜態(tài)注冊(cè)。
?????? 那么該如何創(chuàng)建一個(gè)廣播接收器呢?其實(shí)只需要新建一個(gè)類,讓它繼承自BroadcastReceiver,并重寫父類的onReceive()方法就行了。這樣當(dāng)有廣播到來時(shí),onReceive()方法就會(huì)得到執(zhí)行,具體的邏輯就可以在這個(gè)方法中處理。
?????? 那我們就先通過動(dòng)態(tài)注冊(cè)的方式編寫一個(gè)能夠監(jiān)聽網(wǎng)絡(luò)變化的程序,借此學(xué)習(xí)一下廣播接收器的基本用法吧。新建一個(gè)BroadcastTest 項(xiàng)目,然后修改MainActivity 中的代碼,其中重要的代碼如下所示,該部分在onCreate 方法中實(shí)現(xiàn)
[java]?view plaincopy 第一步:這里先創(chuàng)建一個(gè)IntentFilter 實(shí)例,并在其addAction 中添加我們要監(jiān)聽的廣播,這里是"time”,靜態(tài)注冊(cè)則把這一步在AndroidManifest.xml?中完成;
第二步:創(chuàng)建了一個(gè)MyBroadCast 實(shí)例,然后調(diào)用registerReceiver?方法進(jìn)行注冊(cè),將MyBroadCast 實(shí)例和IntentFilter 實(shí)例都傳播出去;
這樣,mybroadcast 就會(huì)收到所有值為"time" 的廣播,實(shí)現(xiàn)監(jiān)聽功能。
當(dāng)然,這里我們新建一個(gè)類繼承自BroadcastReceiver ,并重寫 onReceive() 方法:
[java]?view plaincopy通過這個(gè)廣播,我們也可以利用Intent 的方法,實(shí)現(xiàn)傳送數(shù)據(jù)的功能,并對(duì)其進(jìn)行處理。
?
2、靜態(tài)注冊(cè)實(shí)現(xiàn)開機(jī)啟動(dòng)
?????? 動(dòng)態(tài)注冊(cè)的廣播接收器可以自由地控制注冊(cè)與注銷,在靈活性方面有很大的優(yōu)勢,但是它也存在著一個(gè)缺點(diǎn),即必須要在程序啟動(dòng)之后才能接收到廣播,因?yàn)樽?cè)的邏輯是寫在onCreate()方法中的。那么有沒有什么辦法可以讓程序在未啟動(dòng)的情況下就能接收到廣播呢?這就需要使用靜態(tài)注冊(cè)的方式了。
??????我們準(zhǔn)備讓程序接收一條開機(jī)廣播,當(dāng)收到這條廣播時(shí)就可以在onReceive()方法里執(zhí)行相應(yīng)的邏輯,從而實(shí)現(xiàn)開機(jī)啟動(dòng)的功能。新建一個(gè)MyReceiver繼承自
BroadcastReceiver,代碼如下所示:
可以看到,這里不再使用內(nèi)部類的方式來定義廣播接收器,因?yàn)樯院笪覀冃枰贏ndroidManifest.xml 中將這個(gè)廣播接收器的類名注冊(cè)進(jìn)去。在onReceive()方法中,還是簡單地使用Toast 彈出一段提示信息。
然后修改AndroidManifest.xml 文件,代碼如下所示:
[java]?view plaincopy?????? 終于,<application>標(biāo)簽內(nèi)出現(xiàn)了一個(gè)新的標(biāo)簽<receiver>,所有靜態(tài)注冊(cè)的廣播接收器都是在這里進(jìn)行注冊(cè)的。它的用法其實(shí)和<activity>標(biāo)簽非常相似,首先通過android:name來指定具體注冊(cè)哪一個(gè)廣播接收器,然后在<intent-filter>標(biāo)簽里加入想要接收的廣播就行了,由于Android 系統(tǒng)啟動(dòng)完成后會(huì)發(fā)出一條值為BroadCast的廣播,因此我們?cè)谶@里添加了相應(yīng)的action。
??????另外,監(jiān)聽系統(tǒng)開機(jī)廣播也是需要聲明權(quán)限的,可以看到,我們使用<uses-permission>標(biāo)簽又加入了一條android.permission.RECEIVE_BOOT_COMPLETED 權(quán)限。
?
三、發(fā)送自定義廣播
???????廣播主要分為兩種類型,標(biāo)準(zhǔn)廣播和有序廣播,在本節(jié)中我們就將通過實(shí)踐的方式來看下這兩種廣播具體的區(qū)別:
1、發(fā)送標(biāo)準(zhǔn)廣播
??????我們來修改來修改activity_main.xml 中的代碼,通過按鈕來發(fā)送廣播
[java]?view plaincopy這里在布局文件中定義了一個(gè)按鈕,用于作為發(fā)送廣播的觸發(fā)點(diǎn)。然后修改MainActivity中的代碼,如下所示:
[java]?view plaincopy可以看到,我們?cè)诎粹o的點(diǎn)擊事件里面加入了發(fā)送自定義廣播的邏輯。首先構(gòu)建出了一個(gè)Intent 對(duì)象,并把要發(fā)送的廣播的值傳入,然后調(diào)用了Context 的sendBroadcast()方法將廣播發(fā)送出去,這樣所有監(jiān)聽BroadCast 條廣播的廣播接收器就會(huì)收到消息。此時(shí)發(fā)出去的廣播就是一條標(biāo)準(zhǔn)廣播。
注意:由于廣播是使用Intent 進(jìn)行傳遞的,因此你還可以在Intent 中攜帶一些數(shù)據(jù)傳遞給廣播接收器。
?
2、發(fā)送有序廣播
?????? 廣播是一種可以跨進(jìn)程的通信方式,這一點(diǎn)從前面接收系統(tǒng)廣播的時(shí)候就可以看出來了。因此在我們應(yīng)用程序內(nèi)發(fā)出的廣播,其他的應(yīng)用程序應(yīng)該也是可以收到的。
??????有序廣播和標(biāo)準(zhǔn)廣播的區(qū)別之一是,我們發(fā)送廣播時(shí),調(diào)用的是sendOrderedBroadcast 方法:
[java]?view plaincopy其中sendOrderedBroadcast()方法接收兩個(gè)參數(shù),第一個(gè)參數(shù)仍然是Intent,第二個(gè)參數(shù)是一個(gè)與權(quán)限相關(guān)的字符串,這里傳入null 就行了。
???????? 廣播接收器是有先后順序的,而且前面的廣播接收器還可以將廣播截?cái)?#xff0c;以阻止其繼續(xù)傳播。那么該如何設(shè)定廣播接收器的先后順序呢?當(dāng)然是在注冊(cè)的時(shí)候進(jìn)行設(shè)定的了,修改AndroidManifest.xml 中的代碼,如下所示:
[java]?view plaincopy????? 我們通過android:priority 屬性給廣播接收器設(shè)置了優(yōu)先級(jí),優(yōu)先級(jí)比較高的廣播接收器就可以先收到廣播。這里將MyBroadcastReceiver 的優(yōu)先級(jí)設(shè)成了100,以保證它一定會(huì)在AnotherBroadcastReceiver 之前收到廣播。
????? 既然已經(jīng)獲得了接收廣播的優(yōu)先權(quán),那么MyBroadcastReceiver 就可以選擇是否允許廣播繼續(xù)傳遞了。修改MyBroadcastReceiver 中的代碼,如下所示:
[java]?view plaincopy ???? 如果在onReceive()方法中調(diào)用了abortBroadcast()方法,就表示將這條廣播截?cái)?#xff0c;后面的廣播接收器將無法再接收到這條廣播?,F(xiàn)在重新運(yùn)行程序,并點(diǎn)擊一下Send Broadcast 按鈕,你會(huì)發(fā)現(xiàn), 只有MyBroadcastReceiver 中的Toast 信息能夠彈出, 說明這條廣播經(jīng)過MyBroadcastReceiver 之后確實(shí)是終止傳遞了。
?????下面我們用一個(gè)實(shí)例——計(jì)時(shí)器,將前面學(xué)到的活動(dòng)、服務(wù)、廣播綜合在一起進(jìn)行學(xué)習(xí)整合,程序?qū)崿F(xiàn)的功能很簡單,就是在前臺(tái)實(shí)現(xiàn)計(jì)時(shí)的功能,并能暫停計(jì)時(shí),且繼續(xù)計(jì)時(shí)時(shí),數(shù)字會(huì)接上暫停前數(shù)據(jù)繼續(xù)跳轉(zhuǎn),實(shí)例圖如下:
具體代碼如下:
1、MainActivty 端
???? 主要實(shí)現(xiàn)廣播的動(dòng)態(tài)注冊(cè),廣播的發(fā)送與接收,開啟服務(wù)與停止服務(wù)的功能,具體代碼如下:
[java]?view plaincopy?
2、MySevice 端
?????? 具體實(shí)現(xiàn)計(jì)時(shí)服務(wù),與廣播的接受與發(fā)送,具體代碼如下:
[java]?view plaincopy?
3、AndroidManiTest 端就不寫了,該注冊(cè)的注冊(cè)就可以了;
?
附:在活動(dòng)中使用Toast
??????? Toast 是Android 系統(tǒng)提供的一種非常好的提醒方式,在程序中可以使用它將一些短小的信息通知給用戶,這些信息會(huì)在一段時(shí)間后自動(dòng)消失,并且不會(huì)占用任何屏幕空間,我們現(xiàn)在就嘗試一下如何在活動(dòng)中使用Toast。
??????? 首先需要定義一個(gè)彈出Toast 的觸發(fā)點(diǎn),正好界面上有個(gè)按鈕,那我們就讓點(diǎn)擊這個(gè)按鈕的時(shí)候彈出一個(gè)Toast 吧。在onCreate()方法中添加代碼:
[java]?view plaincopy?????? 在活動(dòng)中,可以通過findViewById()方法獲取到在布局文件中定義的元素,這里我們傳入R.id.button_1,來得到按鈕的實(shí)例,這個(gè)值是剛才在first_layout.xml 中通過android:id 屬性指定的。findViewById()方法返回的是一個(gè)View 對(duì)象,我們需要向下轉(zhuǎn)型將它轉(zhuǎn)成Button對(duì)象。得到了按鈕的實(shí)例之后,我們通過調(diào)用setOnClickListener()方法為按鈕注冊(cè)一個(gè)監(jiān)聽器,點(diǎn)擊按鈕時(shí)就會(huì)執(zhí)行監(jiān)聽器中的onClick()方法。因此,彈出Toast 的功能當(dāng)然是要在onClick()方法中編寫了。
????? Toast 的用法非常簡單,通過靜態(tài)方法makeText()創(chuàng)建出一個(gè)Toast 對(duì)象,然后調(diào)用show()將Toast 顯示出來就可以了。這里需要注意的是,makeText()方法需要傳入三個(gè)參數(shù)。第一個(gè)參數(shù)是Context,也就是Toast 要求的上下文,由于活動(dòng)本身就是一個(gè)Context 對(duì)象,因此這里直接傳入FirstActivity.this即可。第二個(gè)參數(shù)是Toast顯示的文本內(nèi)容,第三個(gè)參數(shù)是Toast顯示的時(shí)長,有兩個(gè)內(nèi)置常量可以選擇Toast.LENGTH_SHORT 和Toast.LENGTH_LONG。
總結(jié)
以上是生活随笔為你收集整理的Android 四大组件 —— 广播(广播机制解析)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql alter table 速度
- 下一篇: Android 基础 —— 活动的生存周