詳解Android中BroadCastReceiver組件
BroadcastReceiver也就是“廣播接收者”的意思,它是用來接收來自系統(tǒng)和應(yīng)用中的廣播。
在Android中,Broadcast是一種廣泛運(yùn)用的在應(yīng)用程序之間傳輸信息的機(jī)制。而BroadcastReceiver是對發(fā)送出來的 Broadcast進(jìn)行過濾接受并響應(yīng)的一類組件。
下面將詳細(xì)的闡述如何發(fā)送Broadcast和使用BroadcastReceiver過濾接收的過程:
(1)首先在需要發(fā)送信息的地方,把要發(fā)送的信息和用于過濾的信息(如Action、Category)裝入一個(gè)Intent對象,然后通過調(diào)用 sendOrderBroadcast()或sendStickyBroadcast()方法,把 Intent對象以廣播方式發(fā)送出去。
(2)當(dāng)Intent發(fā)送以后,所有已經(jīng)注冊的BroadcastReceiver會檢查注冊時(shí)的IntentFilter是否與發(fā)送的Intent相匹配,若匹配則就會調(diào)用BroadcastReceiver的onReceive()方法。所以當(dāng)我們定義一個(gè)BroadcastReceiver的時(shí)候,都需要實(shí)現(xiàn)onReceive()方法。
注冊BroadcastReceiver有兩種方式
靜態(tài)注冊:在AndroidManifest.xml中用標(biāo)簽生命注冊,并在標(biāo)簽內(nèi)用標(biāo)簽設(shè)置過濾器。
<receiver android:name="myRecevice"> //繼承BroadcastReceiver,重寫onReceiver方法 <intent-filter> <action android:name="com.lc.test"/> //使用過濾器,接收指定action廣播 </intent-filter> </receiver>
動(dòng)態(tài)注冊: 使用IntentFilter在代碼中動(dòng)態(tài)的注冊一個(gè)廣播
IntentFilter intentFilter = new IntentFilter(); //為BroadcastReceiver指定action,使之用于接收同action的廣播 intentFilter.addAction(String); registerReceiver(BroadcastReceiver,intentFilter);
另外值得注意的是,當(dāng)我們使用動(dòng)態(tài)注冊時(shí)候,當(dāng)這個(gè)Activity或Service被銷毀時(shí)如果沒有解除注冊,系統(tǒng)會報(bào)一個(gè)異常,提示我們是否忘記解除注冊了,所以我們需要在onDestroy()方法中進(jìn)行解除注冊,一般:在onStart中注冊,onStop中取消unregisterReceiver:
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
指定廣播目標(biāo)Action:Intent intent = new Intent(actionString);
并且可通過Intent攜帶消息 :intent.putExtra(“msg”, “hi,我通過廣播發(fā)送消息了”);
發(fā)送廣播消息:Context.sendBroadcast(intent )
其中在動(dòng)態(tài)注冊中可將BroadcastReceiver的繼承類進(jìn)行封裝,添加構(gòu)造函數(shù)和BroadcastReceiver注冊
BroadcastReceiver的案例演示
首先我們創(chuàng)建一個(gè)類MyBroadcastReceiver用于繼承BroadcastReceiver:
這里重寫了一個(gè)方法就是接受廣播的意圖并匹配:
//定義的為:public static final String //ACTION_REGISTER_SUCCESS_FINISH="register.success.finish"; Constants.ACTION_REGISTER_SUCCESS_FINISH.equals(intent.getAction())
這里是常量:定義如下:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && Constants.ACTION_REGISTER_SUCCESS_FINISH.equals(intent.getAction())) {
finish();
}
}
}
(1)接下里我們就通過“動(dòng)態(tài)注冊”的方式使用:
private MyBroadcastReceiver receiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(BmobConstants.ACTION_REGISTER_SUCCESS_FINISH); //添加action
registerReceiver(receiver, filter); //注冊
(2)靜態(tài)注冊的話是現(xiàn)在清單文件中添加:
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="register.success.finish"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
(2-1)我們就可以使用代碼了:
Intent intent = new Intent("register.success.finish");
intent.putExtra("msg", "hello receiver.");
sendBroadcast(intent); //發(fā)送廣播
普通廣播(Normal Broadcast)
普通廣播對于多個(gè)接收者來說是完全異步的,通常每個(gè)接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對于這種廣播,接收者無法終止廣播,即無法阻止其他接收者的接收動(dòng)作。為了驗(yàn)證以上論斷,我們新建三個(gè)BroadcastReceiver,演示一下這個(gè)過程,F(xiàn)irstReceiver、SecondReceiver和ThirdReceiver的代碼如下:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class FirstReceiver extends BroadcastReceiver {
private static final String TAG = "NormalBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "FirstReceiver: " + msg);
}
}
public class SecondReceiver extends BroadcastReceiver {
private static final String TAG = "NormalBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "SecondReceiver: " + msg);
}
}
public class ThirdReceiver extends BroadcastReceiver {
private static final String TAG = "NormalBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "ThirdReceiver: " + msg);
}
}
然后再次點(diǎn)擊發(fā)送按鈕,發(fā)送一條廣播,控制臺打印如下:

看來這三個(gè)接收者都接收到這條廣播了,我們稍微修改一下三個(gè)接收者,在onReceive方法的最后一行添加以下代碼,試圖終止廣播:
abortBroadcast();
再次點(diǎn)擊發(fā)送按鈕,我們會發(fā)現(xiàn),控制臺中三個(gè)接收者仍然都打印了自己的日志,表明接收者并不能終止廣播。
有序廣播(Ordered Broadcast)
有序廣播比較特殊,它每次只發(fā)送到優(yōu)先級較高的接收者那里,然后由優(yōu)先級高的接受者再傳播到優(yōu)先級低的接收者那里,優(yōu)先級高的接收者有能力終止這個(gè)廣播。
為了演示有序廣播的流程,我們修改一下上面三個(gè)接收者的代碼,如下:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class FirstReceiver extends BroadcastReceiver {
private static final String TAG = "OrderedBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "FirstReceiver: " + msg);
Bundle bundle = new Bundle();
bundle.putString("msg", msg + "@FirstReceiver");
setResultExtras(bundle);
}
}
public class SecondReceiver extends BroadcastReceiver {
private static final String TAG = "OrderedBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultExtras(true).getString("msg");
Log.i(TAG, "SecondReceiver: " + msg);
Bundle bundle = new Bundle();
bundle.putString("msg", msg + "@SecondReceiver");
setResultExtras(bundle);
}
}
public class ThirdReceiver extends BroadcastReceiver {
private static final String TAG = "OrderedBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultExtras(true).getString("msg");
Log.i(TAG, "ThirdReceiver: " + msg);
}
}
我們注意到,在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法將一個(gè)Bundle對象設(shè)置為結(jié)果集對象,傳遞到下一個(gè)接收者那里,這樣以來,優(yōu)先級低的接收者可以用getResultExtras獲取到最新的經(jīng)過處理的信息集合。
代碼改完之后,我們需要為三個(gè)接收者注冊廣播地址,我們修改一下AndroidMainfest.xml文件:
<receiver android:name=".FirstReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".SecondReceiver">
<intent-filter android:priority="999">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".ThirdReceiver">
<intent-filter android:priority="998">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
我們看到,現(xiàn)在這三個(gè)接收者的多了一個(gè)android:priority屬性,并且依次減小。這個(gè)屬性的范圍在-1000到1000,數(shù)值越大,優(yōu)先級越高。
現(xiàn)在,我們需要修改一下發(fā)送廣播的代碼,如下:
public void send(View view) {
Intent intent = new Intent("android.intent.action.MY_BROADCAST");
intent.putExtra("msg", "hello receiver.");
sendOrderedBroadcast(intent, "scott.permission.MY_BROADCAST_PERMISSION");
}
注意,使用sendOrderedBroadcast方法發(fā)送有序廣播時(shí),需要一個(gè)權(quán)限參數(shù),如果為null則表示不要求接收者聲明指定的權(quán)限,如果不為null,則表示接收者若要接收此廣播,需聲明指定權(quán)限。這樣做是從安全角度考慮的,例如系統(tǒng)的短信就是有序廣播的形式,一個(gè)應(yīng)用可能是具有攔截垃圾短信的功能,當(dāng)短信到來時(shí)它可以先接受到短信廣播,必要時(shí)終止廣播傳遞,這樣的軟件就必須聲明接收短信的權(quán)限。
所以我們在AndroidMainfest.xml中定義一個(gè)權(quán)限:
<permission android:protectionLevel="normal"
android:name="scott.permission.MY_BROADCAST_PERMISSION" />
然后聲明使用了此權(quán)限:
<uses-permission android:name="scott.permission.MY_BROADCAST_PERMISSION" />
關(guān)于這部分如果有不明白的地方可以參考我之前寫過的一篇文章:Android聲明和使用權(quán)限
然后我們點(diǎn)擊發(fā)送按鈕發(fā)送一條廣播,控制臺打印如下:
我們看到接收是按照順序的,第一個(gè)和第二個(gè)都在結(jié)果集中加入了自己的標(biāo)記,并且向優(yōu)先級低的接收者傳遞下去。
既然是順序傳遞,試著終止這種傳遞,看一看效果如何,我們修改FirstReceiver的代碼,在onReceive的最后一行添加以下代碼:
abortBroadcast();
然后再次運(yùn)行程序,控制臺打印如下:

此次,只有第一個(gè)接收者執(zhí)行了,其它兩個(gè)都沒能執(zhí)行,因?yàn)閺V播被第一個(gè)接收者終止了。
上面就是BroadcastReceiver的介紹,下面我將會舉幾個(gè)常見的例子加深一下大家對廣播的理解和應(yīng)用:
1.開機(jī)啟動(dòng)服務(wù)
我們經(jīng)常會有這樣的應(yīng)用場合,比如消息推送服務(wù),需要實(shí)現(xiàn)開機(jī)啟動(dòng)的功能。要實(shí)現(xiàn)這個(gè)功能,我們就可以訂閱系統(tǒng)“啟動(dòng)完成”這條廣播,接收到這條廣播后我們就可以啟動(dòng)自己的服務(wù)了。我們來看一下BootCompleteReceiver和MsgPushService的具體實(shí)現(xiàn):
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootCompleteReceiver extends BroadcastReceiver {
private static final String TAG = "BootCompleteReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, MsgPushService.class);
context.startService(service);
Log.i(TAG, "Boot Complete. Starting MsgPushService...");
}
}
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MsgPushService extends Service {
private static final String TAG = "MsgPushService";
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate called.");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand called.");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
然后我們需要在AndroidManifest.xml中配置相關(guān)信息:
<!-- 開機(jī)廣播接受者 -->
<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<!-- 注冊開機(jī)廣播地址-->
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- 消息推送服務(wù) -->
<service android:name=".MsgPushService"/>
我們看到BootCompleteReceiver注冊了“android.intent.action.BOOT_COMPLETED”這個(gè)開機(jī)廣播地址,從安全角度考慮,系統(tǒng)要求必須聲明接收開機(jī)啟動(dòng)廣播的權(quán)限,于是我們再聲明使用下面的權(quán)限:
經(jīng)過上面的幾個(gè)步驟之后,我們就完成了開機(jī)啟動(dòng)的功能,將應(yīng)用運(yùn)行在模擬器上,然后重啟模擬器,控制臺打印如下:

如果我們查看已運(yùn)行的服務(wù)就會發(fā)現(xiàn),MsgPushService已經(jīng)運(yùn)行起來了。
2.網(wǎng)絡(luò)狀態(tài)變化
在某些場合,比如用戶瀏覽網(wǎng)絡(luò)信息時(shí),網(wǎng)絡(luò)突然斷開,我們要及時(shí)地提醒用戶網(wǎng)絡(luò)已斷開。要實(shí)現(xiàn)這個(gè)功能,我們可以接收網(wǎng)絡(luò)狀態(tài)改變這樣一條廣播,當(dāng)由連接狀態(tài)變?yōu)閿嚅_狀態(tài)時(shí),系統(tǒng)就會發(fā)送一條廣播,我們接收到之后,再通過網(wǎng)絡(luò)的狀態(tài)做出相應(yīng)的操作。下面就來實(shí)現(xiàn)一下這個(gè)功能:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.widget.Toast;
public class NetworkStateReceiver extends BroadcastReceiver {
private static final String TAG = "NetworkStateReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "network state changed.");
if (!isNetworkAvailable(context)) {
Toast.makeText(context, "network disconnected!", 0).show();
}
}
/**
* 網(wǎng)絡(luò)是否可用
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] info = mgr.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
return false;
}
}
再注冊一下這個(gè)接收者的信息:
<receiver android:name=".NetworkStateReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
因?yàn)樵趇sNetworkAvailable方法中我們使用到了網(wǎng)絡(luò)狀態(tài)相關(guān)的API,所以需要聲明相關(guān)的權(quán)限才行,下面就是對應(yīng)的權(quán)限聲明:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
我們可以測試一下,比如關(guān)閉WiFi,看看有什么效果。
3.電量變化
如果我們閱讀軟件,可能是全屏閱讀,這個(gè)時(shí)候用戶就看不到剩余的電量,我們就可以為他們提供電量的信息。要想做到這一點(diǎn),我們需要接收一條電量變化的廣播,然后獲取百分比信息,這聽上去挺簡單的,我們就來實(shí)現(xiàn)以下:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
import android.util.Log;
public class BatteryChangedReceiver extends BroadcastReceiver {
private static final String TAG = "BatteryChangedReceiver";
@Override
public void onReceive(Context context, Intent intent) {
int currLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); //當(dāng)前電量
int total = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1); //總電量
int percent = currLevel * 100 / total;
Log.i(TAG, "battery: " + percent + "%");
}
}
然后再注冊一下廣播接地址信息就可以了:
<receiver android:name=".BatteryChangedReceiver">
<intent-filter>
<action android:name="android.intent.action.BATTERY_CHANGED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
當(dāng)然,有些時(shí)候我們是要立即獲取電量的,而不是等電量變化的廣播,比如當(dāng)閱讀軟件打開時(shí)立即顯示出電池電量。我們可以按以下方式獲?。?/p>
Intent batteryIntent = getApplicationContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int currLevel = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int total = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
int percent = currLevel * 100 / total;
Log.i("battery", "battery: " + percent + "%");
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
- Android BroadcastReceiver實(shí)現(xiàn)網(wǎng)絡(luò)狀態(tài)實(shí)時(shí)監(jiān)聽
- Android BroadcastReceiver接收收到短信的廣播
- Android運(yùn)用BroadcastReceiver實(shí)現(xiàn)強(qiáng)制下線
- Android BroadcastReceiver廣播注冊方式總結(jié)
- android之BroadcastReceiver應(yīng)用詳解
- 深入Android中BroadcastReceiver的兩種注冊方式(靜態(tài)和動(dòng)態(tài))詳解
- Android BroadcastReceiver常見監(jiān)聽整理
- Android BroadcastReceiver廣播機(jī)制概述
- Android采取BroadcastReceiver方式自動(dòng)獲取驗(yàn)證碼
- Android使用BroadcastReceiver監(jiān)聽網(wǎng)絡(luò)連接狀態(tài)的改變
相關(guān)文章
android startActivityForResult的使用方法介紹
android startActivityForResult的使用方法介紹,需要的朋友可以參考一下2013-05-05
Android中的深度鏈接技術(shù)實(shí)戰(zhàn)
本文主要介紹了Android中的深度鏈接技術(shù)實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Android中DownloadManager實(shí)現(xiàn)文件下載實(shí)例詳解
這篇文章主要介紹了Android中DownloadManager實(shí)現(xiàn)文件下載實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03
詳解Android中Activity運(yùn)行時(shí)屏幕方向與顯示方式
本文主要對如何控制Android中Activity運(yùn)行時(shí)屏幕方向與顯示方式進(jìn)行詳細(xì)全面的實(shí)例講解。具有很好的參考價(jià)值,需要的朋友一起來看下吧2016-12-12
Android中ShapeableImageView使用實(shí)例詳解(告別shape、三方庫)
之前Google推送了文章,Android?Material組件1.2.0里面就有ShapeableImageView,不用像以前再寫shape,下面這篇文章主要給大家介紹了關(guān)于Android中ShapeableImageView使用的相關(guān)資料,需要的朋友可以參考下2022-09-09

