目錄
- 什么是廣播
- 如何使用廣播
- 注冊廣播的方式
- 廣播的類型
- 不同注冊方式的廣播接收器回調(diào)
- 不同Android API版本中廣播機(jī)制相關(guān)API重要變遷
一.什么是廣播
作為Android 4大組件之一魄衅,壓力山大雕擂。
系統(tǒng)或者本應(yīng)用程序通過發(fā)送廣播的形式告訴其他app現(xiàn)在系統(tǒng)或者本app的狀態(tài)
這種方式稱為廣播的發(fā)送
比如:老村長拿個(gè)喇叭喊話,誰家羊丟了哼御?(發(fā)送廣播的人),所有村名都聽到了(其他單獨(dú)的app)
二.如何使用廣播
廣播的三要素
- 發(fā)送廣播
- 接受廣播
- 處理廣播
下面一一分析
如何使用廣播
public class MainActivity extends AppCompatActivity {
private TestBroadCast broadCast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//發(fā)送廣播
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.模擬發(fā)送廣播 (一般寫的都是action條件,不用組件名)
//自定義action條件
//在任何app,只要接收器的條件是allens都可以接收數(shù)據(jù)
Intent intent = new Intent("allens");
intent.putExtra("data", "測試發(fā)送廣播...");
//核心方法
sendBroadcast(intent);
}
});
//動(dòng)態(tài)注冊廣播
findViewById(R.id.register).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 第一個(gè)參數(shù):自定義接收器的實(shí)例化對象
* 第二個(gè)參數(shù):構(gòu)建IntentFliter條件
*/
IntentFilter filter = new IntentFilter();
//添加的action條件,匹配頻道使用
filter.addAction("allens");
//設(shè)置優(yōu)先級
filter.setPriority(Integer.MAX_VALUE);
broadCast = new TestBroadCast();
registerReceiver(broadCast, filter);
}
});
//取消注冊
findViewById(R.id.unregister).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (broadCast != null) {
unregisterReceiver(broadCast);
broadCast = null;
}
}
});
}
}
public class TestBroadCast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String value = intent.getStringExtra("data");
Log.e("TAG","data--->" + value);
}
}
三.注冊廣播的方式
動(dòng)態(tài)注冊
在上面的例子中 可以看到 我們使用代碼動(dòng)態(tài)注冊了廣播逗余,也動(dòng)態(tài)的取消注冊廣播说榆,這是一中方式喉誊,當(dāng)然還有其他的方式靜態(tài)注冊
在manifest
中配置
<receiver
android:name=".broadcast.TestBroadCast"
android:enabled="false"
android:exported="true"
android:icon="@drawable/ic_launcher_background"
android:label="@string/app_name"
android:permission="@string/app_name"
android:process="@string/app_name">
<intent-filter android:priority="2000">
<action android:name="allens" />
</intent-filter>
</receiver>
參數(shù)解釋
參數(shù) | 說明 |
---|---|
intent-filter | 過濾器,篩選廣播條件 |
android:name | 這里的name 要和我們發(fā)送廣播的action 相同羔挡,不然收不到廣播 |
android:priority | 2000到-2000 ,通過priority設(shè)置優(yōu)先級 |
android:enabled | true (默認(rèn)的是true)設(shè)置為true廣播接收器才能夠被啟用洁奈,false該廣播接收器會被禁止實(shí)例化(不能使用) |
android:exported | 是否能夠接收來自應(yīng)用程序外部的消息 |
android:icon | 定義一個(gè)代表廣播接收器的圖標(biāo) |
android:label | 這個(gè)屬性給廣播接收器設(shè)定一個(gè)用戶可讀的懂的文本標(biāo)簽 |
android:name | 這個(gè)屬性值要用廣播接收器的實(shí)現(xiàn)類的類名來設(shè)置 |
android:permission | 把消息發(fā)送給該廣播接收器的廣播器所必須要有的權(quán)限 |
android:process | 這個(gè)屬性用于設(shè)置該廣播接收器應(yīng)該運(yùn)行在那個(gè)進(jìn)程中的進(jìn)程名 |
當(dāng)然這些屬性,也不用全寫上绞灼,更具實(shí)際情況睬魂,
對比
類型 | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|
靜態(tài)注冊 | 常駐廣播,不受生命周期影響 | 耗電镀赌,占內(nèi)存 |
動(dòng)態(tài)注冊 | 靈活氯哮, | 必須跟隨組件的生命周期,及時(shí)釋放資源 |
so 繼續(xù)
四. 廣播的類型
普通廣播(Normal Broadcast)
系統(tǒng)廣播(System Broadcast)
有序廣播(Ordered Broadcast)
粘性廣播(Sticky Broadcast)
App應(yīng)用內(nèi)廣播(Local Broadcast)
1.普通廣播
定義:開發(fā)者自己定義的intent,像上面我們使用的就是普通廣播
Intent intent = new Intent();
//對應(yīng)BroadcastReceiver中intentFilter的action
intent.setAction("自定義的action");
//發(fā)送廣播
sendBroadcast(intent);
<receiver
//此廣播接收者類是開發(fā)者自定義的BroadcastReceiver
android:name=".BroadcastReceiver" >
<intent-filter>
<action android:name="自定義的action" />
</intent-filter>
</receiver>
總結(jié)
1.順序是無序的
2.需要在intent-filter
自定義action
3.如果發(fā)送廣播時(shí)有相應(yīng)的權(quán)限要求良姆,BroadCastReceiver如果想要接收此廣播肠虽,也需要有相應(yīng)的權(quán)限
2.系統(tǒng)廣播
Android系統(tǒng)中內(nèi)置了多個(gè)系統(tǒng)廣播,只要涉及到手機(jī)的基本操作玛追,基本上都會發(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ā)出
3.有序廣播
有序廣播的有序廣播中的“有序”是針對廣播接收者而言的益老,指的是發(fā)送出去的廣播被BroadcastReceiver按照先后循序接收彪蓬。有序廣播的定義過程與普通廣播無異只是其的主要發(fā)送方式變?yōu)?/p>
sendOrderedBroadcast(intent);
特點(diǎn)
1.按照Priority屬性值從大-小排序;
2.Priority屬性相同者捺萌,動(dòng)態(tài)注冊的廣播優(yōu)先档冬;
3.先接收的BroadcastReceiver可以對此有序廣播進(jìn)行截?cái)啵购竺娴腂roadcastReceiver不再接收到此廣播,也可以對廣播進(jìn)行修改捣郊,使后面的BroadcastReceiver接收到廣播后解析得到錯(cuò)誤的參數(shù)值。當(dāng)然慈参,一般情況下呛牲,不建議對有序廣播進(jìn)行此類操作,尤其是針對系統(tǒng)中的有序廣播
4.粘性廣播
定義:廣播的信息內(nèi)容系統(tǒng)會存放一段時(shí)間,任何時(shí)間內(nèi)app都可以獲取數(shù)據(jù)
sendStickyBroadCast
由于在Android5.0 & API 21中已經(jīng)失效驮配,相應(yīng)的還有粘性有序廣播,所以不建議使用娘扩,在這里也不作過多的總結(jié)。
5.App應(yīng)用內(nèi)廣播
由前文闡述可知壮锻,Android中的廣播可以跨進(jìn)程甚至跨App直接通信琐旁,且注冊是exported
對于有intent-filter
的情況下默認(rèn)值是true
,由此將可能出現(xiàn)安全隱患如下
1 .其他App可能會針對性的發(fā)出與當(dāng)前App intent-filter
相匹配的廣播猜绣,由此導(dǎo)致當(dāng)前App不斷接收到廣播并處理
2.其他App可以注冊與當(dāng)前App一致的intent-filter
用于接收廣播灰殴,獲取廣播具體信息
常見改進(jìn)方式
1.對于同一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)
指定在怀估,這樣此廣播將只會發(fā)送到此包中的App內(nèi)與之相匹配的有效廣播接收器中狮鸭。
說了那么多,所以才有了App應(yīng)用內(nèi)廣播,其特點(diǎn)如下
1.安全性更高多搀;
2.更加高效
如何使用呢歧蕉?
//注冊應(yīng)用內(nèi)廣播接收器
//步驟1:實(shí)例化BroadcastReceiver子類 & IntentFilter mBroadcastReceiver
mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
//步驟2:實(shí)例化LocalBroadcastManager的實(shí)例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步驟3:設(shè)置接收廣播的類型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步驟4:調(diào)用LocalBroadcastManager單一實(shí)例的registerReceiver()方法進(jìn)行動(dòng)態(tài)注冊
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注冊應(yīng)用內(nèi)廣播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
//發(fā)送應(yīng)用內(nèi)廣播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);
五. 不同注冊方式的廣播接收器回調(diào)onReceive(context, intent)中的context具體類型
類型 | context具體類型 |
---|---|
靜態(tài)注冊的ContextReceiver | ReceiverRestricted Context |
全局廣播的動(dòng)態(tài)注冊的ContextReceiver | Activity Context |
通過LocalBroadcastManager動(dòng)態(tài)注冊的ContextReceiver | Application Context |
注意:對于
LocalBroadcastManager
方式發(fā)送的應(yīng)用內(nèi)廣播,只能通過LocalBroadcastManager
動(dòng)態(tài)注冊的ContextReceiver
才有可能接收到(靜態(tài)注冊或其他方式動(dòng)態(tài)注冊的ContextReceiver
是接收不到的)
六. 不同Android API版本中廣播機(jī)制相關(guān)API重要變遷
Android 3.1開始
- 自Android3.1開始,靜態(tài)注冊的廣播接收器康铭,app已經(jīng)退出廊谓,有相應(yīng)的廣播發(fā)出,接收不到
原因:自Android3.1開始麻削,系統(tǒng)本身則增加了對所有app當(dāng)前是否處于運(yùn)行狀態(tài)的跟蹤蒸痹。在發(fā)送廣播時(shí),不管是什么廣播類型呛哟,系統(tǒng)默認(rèn)直接增加了值為FLAG_EXCLUDE_STOPPED_PACKAGES
的flag叠荠,導(dǎo)致即使是靜態(tài)注冊的廣播接收器,對于其所在進(jìn)程已經(jīng)退出的app扫责,同樣無法接收到廣播
Android 3.1開始系統(tǒng)在Intent與廣播相關(guān)的flag增加了參數(shù)榛鼎,分別是
FLAG_INCLUDE_STOPPED_PACKAGES
:包含已經(jīng)停止的包(停止:即包所在的進(jìn)程已經(jīng)退出)FLAG_EXCLUDE_STOPPED_PACKAGES
:不包含已經(jīng)停止的包
android 5.0開始
- Android5.0/API level 21開始粘滯廣播和有序粘滯廣播過期,以后不再建議使用;
android 7.0開始
- 徹底沒有靜態(tài)注冊的方式啦者娱,哈哈 為了省電
寫在最后
關(guān)于7.0 以上的廣播方案抡笼,會在后面慢慢補(bǔ)充,實(shí)話說啊黄鳍,這東西真的好好看推姻,抽個(gè)空靜下心好好研究一下,這些細(xì)節(jié)上的事情框沟,都是平時(shí)開發(fā)時(shí)候的坑啊藏古。。忍燥。拧晕。