Broadcast(廣播)是一種廣泛應(yīng)用在應(yīng)用程序之間傳輸信息的機(jī)制,而B(niǎo)roadcastReceiver(廣播接收器)則是用于接收來(lái)自系統(tǒng)和應(yīng)用的廣播對(duì)并對(duì)其進(jìn)行響應(yīng)的組件。Android提供了一套完整的API,允許應(yīng)用程序自由地發(fā)送和接收廣播,其中又用到可以傳遞信息的Intent。那么本篇將介紹以下四種類型廣播的發(fā)送和接收方法:
- 普通廣播
- 有序廣播
- 本地廣播
- 粘性廣播
1.普通廣播
普通廣播是一種完全異步執(zhí)行的廣播,在廣播發(fā)出之后,所有的廣播接收器幾乎都會(huì)在同一時(shí)刻接收到這條廣播消息,因此它們接收的先后是隨機(jī)的。另外,接收器不能截?cái)嗥胀◤V播。標(biāo)準(zhǔn)廣播的工作流程如圖所示:
(1)接收系統(tǒng)廣播
想要接收一個(gè)廣播,就要有能接收這個(gè)廣播的接收器。下圖展示了如何實(shí)現(xiàn)一個(gè)BroadcastReceiver的全過(guò)程:
可以看到,具體用法是:
第一步:自定義接收器類并繼承BroadcastReceiver,然后具體實(shí)現(xiàn)onReceive()方法。幾點(diǎn)注意:BroadcastReceiver生命周期只有十秒左右,因此在onReceive()不要做一些耗時(shí)的操作,應(yīng)該發(fā)送給service,由service來(lái)完成;還有onReceive()不要開(kāi)啟子線程。
第二步:對(duì)廣播接收器進(jìn)行注冊(cè)。有兩種注冊(cè)方法:一種在活動(dòng)里通過(guò)代碼動(dòng)態(tài)注冊(cè),另一種在配置文件里靜態(tài)注冊(cè)。其實(shí)仔細(xì)觀察,兩種方式都是完成了對(duì)接收器以及它能接收的廣播值這兩個(gè)值的定義。這兩種注冊(cè)方法一個(gè)區(qū)別是:動(dòng)態(tài)注冊(cè)的接收器必須要在程序啟動(dòng)之后才能接收到廣播,而靜態(tài)注冊(cè)的接收器即便程序未啟動(dòng)也能接收到廣播,比如想接收到手機(jī)開(kāi)機(jī)完成后系統(tǒng)發(fā)出的廣播就只能用靜態(tài)注冊(cè)了。
舉個(gè)例子,當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí),系統(tǒng)會(huì)發(fā)出一條值為android.net.conn.CONNECTIVITY_CHANGE的廣播,假設(shè)已經(jīng)準(zhǔn)備好了接收器MyReceiver,如果選擇動(dòng)態(tài)注冊(cè),方法是修改MainActivity:
private IntentFilter intentFilter;
private MyReceiver myReceiver;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
myReceiver = new MyReceiver();
registerReceiver(myReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);
}
也可以靜態(tài)注冊(cè),在配置文件添加:
<receiver android:name=".MyReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
最后別忘了查詢系統(tǒng)的網(wǎng)絡(luò)狀態(tài)需要聲明權(quán)限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
現(xiàn)在只要網(wǎng)絡(luò)狀態(tài)發(fā)生變化,MyReceiver就會(huì)接收到這條廣播并執(zhí)行onReceive()里具體的任務(wù)了。
(2)發(fā)送自定義廣播
我們自定義的接收器不僅可以接收Android內(nèi)置的各種系統(tǒng)級(jí)別的廣播,也可以接收我們自定義的廣播。那么就來(lái)學(xué)習(xí)如何發(fā)送一個(gè)自定義廣播,看看接收器的接收情況吧!
發(fā)送一個(gè)自定義的普通廣播方法非常簡(jiǎn)單,利用Intent把要發(fā)送的廣播的值傳入,再調(diào)用了Context的sendBroadcast()方法將廣播發(fā)送出去,這樣所有監(jiān)聽(tīng)該廣播的接收器就會(huì)收到消息。
Intent intent = new Intent("com.example.minmin.MY_BROADCAST");//指明要發(fā)送的廣播值
sendBroadcast(intent);
還是通過(guò)一個(gè)具體例子學(xué)習(xí)一下,先定義一個(gè)廣播接收器,這里讓它收到廣播后彈出一個(gè)提示:
靜態(tài)注冊(cè)該接收器,定義它能接收一 條值為com.example.minmin.MY_BROADCAST的廣播,一會(huì)兒就發(fā)這樣的一條廣播。
準(zhǔn)備MainActvity的布局,這里就一個(gè)按鈕用來(lái)發(fā)送廣播。
在這個(gè)按鈕的點(diǎn)擊事件完成發(fā)送一條值為com.example.minmin.MY_BROADCAST的廣播。
運(yùn)行程序,發(fā)送自定義廣播,接收器收到了!
2.有序廣播
有序廣播是一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時(shí)刻只會(huì)有一個(gè)廣播接收器能夠收到這條廣播消息,當(dāng)這個(gè)廣播接收器中的邏輯執(zhí)行完畢后,廣播才會(huì)繼續(xù)傳遞,所以此時(shí)的廣播接收器是有先后順序的,且優(yōu)先級(jí)(priority)高的廣播接收器會(huì)先收到廣播消息。有序廣播可以被接收器截?cái)嗍沟煤竺娴慕邮掌鳠o(wú)法收到它。有序廣播的工作流程如圖所示:
發(fā)送一個(gè)有序廣播和普通廣播的方法有細(xì)微的區(qū)別,只需要將sendBroadcast()方法改成sendOrderedBroadcast()方法, 它接收兩個(gè)參數(shù),第一個(gè)參數(shù)仍是Intent,第二個(gè)參數(shù)是一個(gè)與權(quán)限相關(guān)的字符串,這里傳入 null就行。代碼見(jiàn)下:
Intent intent = new Intent("com.example.minmin.MY_BROADCAST");//指明要發(fā)送的廣播值
sendOrderBroadcast(intent,null);
此時(shí)廣播接收器是有先后順序的,而且前面的廣播接收器還可以將廣播截?cái)?,以阻止其繼續(xù)傳播。為了說(shuō)明這個(gè)情況,再自定義一個(gè)廣播器看看吧!
這里AnotherReceiver接受廣播后也彈出一個(gè)提醒,就用最后的“!!”來(lái)區(qū)分吧。
那如何讓AnotherReceiver先接收到值為com.example.minmin.MY_BROADCAST的廣播呢?只要在注冊(cè)的時(shí)候設(shè)定它的優(yōu)先級(jí)android:priority為100,數(shù)值越大優(yōu)先級(jí)就越高,現(xiàn)在就能保證它一定會(huì)在MyReceiver之前收到廣播。
修改MainActivity中代碼:
運(yùn)行程序,會(huì)先彈出AnotherReceiver中的提示,之后才MyReceiver:
如果在AnotherReceiver的onReceive()方法中調(diào)用了abortBroadcast()方法,表示將這條廣播截?cái)?,后面的廣播接收器將無(wú)法再接收到這條廣播。現(xiàn)在重新運(yùn)行程序,并點(diǎn)擊一下按鈕,然后會(huì)發(fā)現(xiàn),只有AnotherReceiver中的Toast信息彈出,說(shuō)明這條廣播經(jīng)過(guò)AnotherReceiver之后確實(shí)是終止傳遞了。
3.本地廣播
前面學(xué)到的的廣播都屬于系統(tǒng)全局廣播,即發(fā)出的廣播可被其他應(yīng)用程序接收到,且我們也可接收到其他任何應(yīng)用程序發(fā)送的廣播。為了能夠簡(jiǎn)單地解決全局廣播可能帶來(lái)的安全性問(wèn)題,Android引入了一套本地廣播機(jī)制,使用這個(gè)機(jī)制發(fā)出的廣播只能夠在應(yīng)用程序的內(nèi)部進(jìn)行傳遞,并且廣播接收器也只能接收本應(yīng)用程序發(fā)出的廣播。
實(shí)現(xiàn)本地廣播的發(fā)送和接收也很簡(jiǎn)單,主要使用了一個(gè)LocalBroadcastManager來(lái)對(duì)廣播進(jìn)行管理,并提供了相應(yīng)的發(fā)送廣播和注冊(cè)廣播接收器的方法。
首先通過(guò)LocalBroadcastManager.getInstance(this)方法獲取一個(gè)LocalBroadcastManager實(shí)例,然后用LocalBroadcastManager提供的registerReceiver()和unregisterReceiver()方法來(lái)動(dòng)態(tài)注冊(cè)和取消接收器以及sendBroadcast()方法發(fā)送本地廣播。是不是非常熟悉?看了下圖展示的代碼你會(huì)更清楚:
這基本上就和我們前面所學(xué)的動(dòng)態(tài)注冊(cè)廣播接收器以及發(fā)送廣播的代碼是一樣的!非常好理解。運(yùn)行之后點(diǎn)擊按鈕也能看到MyReceiver的Toast提示了!
注意一點(diǎn),本地廣播是無(wú)法通過(guò)靜態(tài)注冊(cè)的方式來(lái)接收的,因?yàn)殪o態(tài)注冊(cè)主要就是為了讓程序在未啟動(dòng)的情況下也能收到廣播,而發(fā)送本地廣播時(shí),應(yīng)用程序肯定已經(jīng)啟動(dòng)了,也完全不需要使用靜態(tài)注冊(cè)的功能。
4.粘性廣播
通過(guò)Context.sendStickyBroadcast()方法可發(fā)送粘性(sticky)廣播,這種廣播會(huì)一直滯留,當(dāng)有匹配該廣播的接收器被注冊(cè)后,該接收器就會(huì)收到此條廣播。注意,發(fā)送粘性廣播還需要BROADCAST_STICKY權(quán)限:
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
sendStickyBroadcast()只保留最后一條廣播,并且一直保留下去,這樣即使已經(jīng)有廣播接收器處理了該廣播,一旦又有匹配的廣播接收器被注冊(cè),該粘性廣播仍會(huì)被接收。如果只想處理一遍該廣播,可通過(guò)removeStickyBroadcast()方法來(lái)實(shí)現(xiàn)。接收粘性廣播的過(guò)程和普通廣播是一樣的,就不多介紹了。
有關(guān)廣播接收者的內(nèi)容就到這里~
>最終篇內(nèi)容:組件篇之Service