BoradcastReceiver
BroadcastReceiver的簡(jiǎn)介
BroadcastReceiver翻譯為廣播接收者,Broadcast是一種廣泛運(yùn)用在應(yīng)用程序之間的傳輸信息的機(jī)制,簡(jiǎn)單的可以理解為傳統(tǒng)意義上的電臺(tái)廣播稻爬,通俗一點(diǎn)蒿秦,發(fā)布失物招領(lǐng)
廣播機(jī)制是一個(gè)典型的發(fā)布—訂閱模式粉渠,也就是我們所說(shuō)的觀察者模式菱涤。廣播最大的特點(diǎn)就是發(fā)送方并不關(guān)心接收方是否接到數(shù)據(jù)绸栅,也不關(guān)心接收方是如何處理數(shù)據(jù)的海诲,通過(guò)這樣的形式來(lái)達(dá)到接繁莹、收雙方的完全解耦合
普通廣播(自定義廣播)
普通廣播是完全異步的,通過(guò)Context的sendBroadcast()方法來(lái)發(fā)送特幔,消息傳遞效率比較高咨演,但所有receivers(接收器)的執(zhí)行順序不確定。缺點(diǎn)是:接收者不能將處理結(jié)果傳遞給下一個(gè)接收者蚯斯,并且無(wú)法終止廣播Intent的傳播薄风,直到?jīng)]有與之匹配的廣播接收器為止饵较。下面以自定義的普通廣播進(jìn)行演示
- 創(chuàng)建廣播
創(chuàng)建廣播非常簡(jiǎn)單,只要繼承BroadcastReceiver并實(shí)現(xiàn)onReceive()方法
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiver", Toast.LENGTH_LONG).show();
}
}
- 注冊(cè)廣播
BroadcastReceiver是四大組件之一遭赂,所以毫不疑問(wèn)需要注冊(cè)循诉,BroadcastReceiver的注冊(cè)有兩種方法:
- 通過(guò)manifests配置
- 通過(guò)代碼動(dòng)態(tài)配置
靜態(tài)注冊(cè)是系統(tǒng)級(jí)注冊(cè),只要安裝了應(yīng)用撇他,無(wú)需打開(kāi)茄猫,就能接受到廣播,原生系統(tǒng)可以通過(guò)這個(gè)方法相互喚醒困肩。但是國(guó)產(chǎn)ROM無(wú)法做到這一點(diǎn)
方法一:通過(guò)manifests配置
<receiver android:name=".BroadcastReceiver.MyBroadcastReceiver">
<intent-filter>
<action android:name="com.handsome.hensen" />
</intent-filter>
</receiver>
這里需要加入intent-filter的action中的name屬性划纽,表示我們監(jiān)聽(tīng)的內(nèi)容。當(dāng)有廣播發(fā)送時(shí)锌畸,需要判斷該廣播是否和我們監(jiān)聽(tīng)的內(nèi)容一致勇劣,如果一致則接收
方法二:通過(guò)代碼動(dòng)態(tài)配置
//創(chuàng)建廣播
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
//注冊(cè)廣播
registerReceiver(receiver, new IntentFilter("com.qinqin"));
- 反注冊(cè)廣播
BroadcastReceiver必須遵循生到死的周期,如果你是使用動(dòng)態(tài)注冊(cè)廣播的則需要在Activity的onDestroy的時(shí)候反注冊(cè)廣播
- 發(fā)送廣播
這里我們以一個(gè)按鈕來(lái)發(fā)送廣播潭枣,通過(guò)sendBroadcast()方法發(fā)送我們的創(chuàng)建的Intent自定義廣播
final Intent intent = new Intent();
//廣播內(nèi)容
intent.setAction("com.qinqin");
bt_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendBroadcast(intent);
}
});
- 運(yùn)行代碼
運(yùn)行程序后比默,我們點(diǎn)擊發(fā)送廣播。
有序廣播
有序廣播通過(guò)Context.sendOrderedBroadcast()來(lái)發(fā)送盆犁,所有的廣播接收器優(yōu)先級(jí)依次執(zhí)行命咐,廣播接收器的優(yōu)先級(jí)通過(guò)receiver的intent-filter中的Android:priority屬性來(lái)設(shè)置,數(shù)值越大優(yōu)先級(jí)越高蚣抗。
當(dāng)廣播接收器接收到廣播后侈百,可以使用setResult()函數(shù)來(lái)結(jié)果傳給下一個(gè)廣播接收器接收,然后通過(guò)getResult()函數(shù)來(lái)取得上個(gè)廣播接收器接收返回的結(jié)果翰铡。當(dāng)廣播接收器接收到廣播后钝域,也可以用abortBroadcast()函數(shù)來(lái)讓系統(tǒng)攔截下來(lái)該廣播,并將該廣播丟棄锭魔,使該廣播不再傳送到別的廣播接收器接收例证。
- 創(chuàng)建廣播
我們創(chuàng)建一個(gè)類,存放三個(gè)有優(yōu)先級(jí)的廣播接收者迷捧,并在最高級(jí)廣播中傳遞結(jié)果到下一個(gè)廣播
public class PriorityBroadcastReceiver {
public static class HighPriority extends BroadcastReceiver {
//高級(jí)廣播接收者
@Override
public void onReceive(Context context, Intent intent) {
Log.e("receive", "High");
//傳遞結(jié)果到下一個(gè)廣播接收器
int code = 0;
String data = "hello";
Bundle bundle = null;
setResult(code, data, bundle);
}
}
public static class MidPriority extends BroadcastReceiver {
//中級(jí)廣播接收者
@Override
public void onReceive(Context context, Intent intent) {
Log.e("receive", "Mid");
//獲取上一個(gè)廣播接收器結(jié)果
int code = getResultCode();
String data = getResultData();
Log.e("receive", "獲取到上一個(gè)廣播接收器結(jié)果:" + "code=" + code + "data=" + data);
}
}
public static class LowPriority extends BroadcastReceiver {
//低級(jí)廣播接收者
@Override
public void onReceive(Context context, Intent intent) {
Log.e("receive", "Low");
}
}
}
- 注冊(cè)廣播
這里的注冊(cè)方式和普通廣播是一樣的织咧,這里的區(qū)別在于priority屬性,確定了他們之間的優(yōu)先級(jí)
<receiver android:name=".PriorityBroadcastReceiver$HighPriority">
<intent-filter android:priority="3000">
<action android:name="com.qinqin" />
</intent-filter>
</receiver>
<receiver android:name=".PriorityBroadcastReceiver$MidPriority">
<intent-filter android:priority="2000">
<action android:name="com.qinqin" />
</intent-filter>
</receiver>
<receiver android:name=".PriorityBroadcastReceiver$LowPriority">
<intent-filter android:priority="1000">
<action android:name="com.qinqin" />
</intent-filter>
</receiver>
要注意的是:BroadcastReceiver類名與內(nèi)部類的名字之間用$符號(hào)隔開(kāi)漠秋,否則會(huì)報(bào)錯(cuò)
- 發(fā)送廣播
和之前的不一樣的地方笙蒙,這里是使用sendOrderedBroadcast()發(fā)送有序廣播
final Intent intent = new Intent();
intent.setAction("com.qinqin");
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendOrderedBroadcast(intent,null);
}
});
要注意的是:這里需要發(fā)送的是有序廣播,否則在接收者中通過(guò)setResult()和getResult()方法會(huì)報(bào)錯(cuò)庆锦,因?yàn)橹挥杏行驈V播才能傳遞結(jié)果
- 運(yùn)行代碼
運(yùn)行程序后捅位,我們點(diǎn)擊發(fā)送廣播。我們以Log信息來(lái)驗(yàn)證發(fā)出的廣播被我們準(zhǔn)確的接收,數(shù)據(jù)被我們準(zhǔn)確的傳遞
02-27 02:44:24.707 7195-7195/com.example.user.a2017_2_27 E/receive: High
02-27 02:44:24.729 7195-7195/com.example.user.a2017_2_27 E/receive: Mid
02-27 02:44:24.729 7195-7195/com.example.user.a2017_2_27 E/receive: 獲取到上一個(gè)廣播接收器結(jié)果:code=0data=hello
02-27 02:44:24.730 7195-7195/com.example.user.a2017_2_27 E/receive: Low
攔截廣播
上面我們提到過(guò)有序廣播中可以攔截廣播艇搀,那么我們?cè)谏厦娉绦虻幕A(chǔ)上修改代碼尿扯,在HighPriority接收器中加上攔截廣播
- 創(chuàng)建廣播
通過(guò)在BroadcastReceiver中,執(zhí)行abortBroadcast()方法焰雕,廣播就不會(huì)繼續(xù)往下傳遞了
public static class HighPriority extends BroadcastReceiver {
//高級(jí)廣播接收者
@Override
public void onReceive(Context context, Intent intent) {
Log.e("receive", "High");
//攔截廣播
abortBroadcast();
//傳遞結(jié)果到下一個(gè)廣播接收器
int code = 0;
String data = "hello";
Bundle bundle = null;
setResult(code, data, bundle);
}
}
- 運(yùn)行代碼
運(yùn)行程序后衷笋,我們點(diǎn)擊發(fā)送廣播。我們以Log信息來(lái)驗(yàn)證我們攔截了廣播
02-27 02:48:44.112 7195-7195/com.example.user.a2017_2_27 E/receive: High
可以看到矩屁,后面的Mid和Low廣播都沒(méi)有Log信息辟宗,說(shuō)明我們攔截成功了
有序廣播、攔截廣播的拓展——終結(jié)廣播
現(xiàn)在有這樣的一個(gè)應(yīng)用場(chǎng)景档插,按照上面的程序走慢蜓,只能在第一個(gè)廣播中被攔截住了,后面的廣播則不執(zhí)行郭膛。如果這個(gè)時(shí)候我們需要一個(gè)不管有沒(méi)有被攔截都必須執(zhí)行的廣播,我們稱為終結(jié)廣播氛悬,那應(yīng)該怎么辦则剃。同樣的,發(fā)送有序廣播也考慮到這一點(diǎn)如捅,通過(guò)以下代碼來(lái)發(fā)送廣播棍现,并指定我們不管有沒(méi)有被攔截都必須執(zhí)行的終結(jié)廣播
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendOrderedBroadcast(intent, null, new PriorityBroadcastReceiver.LowPriority(),
new Handler(), 0, null, null);
}
});
運(yùn)行代碼,我們查看Log信息
02-27 02:54:37.152 7195-7195/com.example.user.a2017_2_27 E/receive: High
02-27 02:54:37.168 7195-7195/com.example.user.a2017_2_27 E/receive: Low
本地廣播
在API21的Support v4包中新增本地廣播镜遣,也就是LocalBroadcastManager己肮。由于之前的廣播都是全局的,所有應(yīng)用程序都可以接收到悲关,這樣就會(huì)帶來(lái)安全隱患谎僻,所以我們使用LocalBroadcastManager只發(fā)送給自己應(yīng)用內(nèi)的信息廣播,限制在進(jìn)程內(nèi)使用
它的用法很簡(jiǎn)單寓辱,只需要把調(diào)用context的sendBroadcast艘绍、registerReceiver、unregisterReceiver的地方換為L(zhǎng)ocalBroadcastManager.getInstance(Context context)中對(duì)應(yīng)的函數(shù)即可秫筏。這里創(chuàng)建廣播的過(guò)程和普通廣播是一樣的過(guò)程诱鞠,這里就不過(guò)多介紹了
- 注冊(cè)Receiver
//創(chuàng)建廣播
receiver = new MyBroadcastReceiver();
//注冊(cè)本地廣播
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter("com.qinqin"));
- 反注冊(cè)Receiver
LocalBroadcastManager.getInstance(ReceiverActivity.this).unregisterReceiver(receiver);
- 發(fā)送異步廣播
final Intent intent = new Intent();
intent.setAction("com.qinqin");
LocalBroadcastManager.getInstance(ReceiverActivity.this).sendBroadcast(intent);
- 發(fā)送同步廣播
LocalBroadcastManager.getInstance(ReceiverActivity.this).sendBroadcastSync(intent);
Sticky廣播
sticky廣播通過(guò)Context.sendStickyBroadcast()函數(shù)來(lái)發(fā)送,用此函數(shù)發(fā)送的廣播會(huì)一直滯留这敬,當(dāng)有匹配此廣播的廣播接收器被注冊(cè)后航夺,該廣播接收器就會(huì)收到此條信息。使用此函數(shù)需要發(fā)送廣播時(shí)崔涂,需要獲得BROADCAST_STICKY權(quán)限
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
sendStickyBroadcast只保留最后一條廣播阳掐,并且一直保留下去,這樣即使已經(jīng)有廣播接收器處理了該廣播,當(dāng)再有匹配的廣播接收器被注冊(cè)時(shí)锚烦,此廣播仍會(huì)被接收觅闽。如果你只想處理一遍該廣播,可以通過(guò)removeStickyBroadcast()函數(shù)來(lái)實(shí)現(xiàn)涮俄。這里創(chuàng)建廣播的過(guò)程和普通廣播是一樣的過(guò)程蛉拙,這里就不過(guò)多介紹了
系統(tǒng)廣播
當(dāng)然系統(tǒng)中也會(huì)有很多自帶的廣播,當(dāng)符合一定條件時(shí)彻亲,系統(tǒng)會(huì)發(fā)送一些定義好的廣播孕锄,比如:重啟、充電苞尝、來(lái)電電話等等畸肆。我們可以通過(guò)action屬性來(lái)監(jiān)聽(tīng)我們的系統(tǒng)廣播
<receiver android:name=".BroadcastReceiver.MyBroadcastReceiver">
<intent-filter>
<!--重啟設(shè)備-->
<action android:name="android.intent.action.REBOOT" />
</intent-filter>
</receiver>
這里創(chuàng)建廣播的過(guò)程和普通廣播是一樣的過(guò)程,這里就不過(guò)多介紹了宙址。常用的廣播action屬性有
- 屏幕被關(guān)閉之后的廣播:Intent.ACTION_SCREEN_OFF
- 屏幕被打開(kāi)之后的廣播:Intent.ACTION_SCREEN_ON
- 充電狀態(tài)轴脐,或者電池的電量發(fā)生變化:Intent.ACTION_BATTERY_CHANGED
- 關(guān)閉或打開(kāi)飛行模式時(shí)的廣播:Intent.ACTION_AIRPLANE_MODE_CHANGED
- 表示電池電量低:Intent.ACTION_BATTERY_LOW
- 表示電池電量充足,即電池電量飽滿時(shí)會(huì)發(fā)出廣播:Intent.ACTION_BATTERY_OKAY
- 按下照相時(shí)的拍照按鍵(硬件按鍵)時(shí)發(fā)出的廣播:Intent.ACTION_CAMERA_BUTTON