Android四大組件之Activity
Android四大組件之Service
Android四大組件之BroadcastReceiver
Android四大組件之ContentProvider
BroadcastReceiver作為Android四大組件之一,即廣播。廣播分為發(fā)送者和接收者。要想使用廣播,首先必須先注冊(cè)廣播接收者,然后接著發(fā)送廣播。最后在接收者中處理廣播。
1.廣播接收者BroadcastReceiver的使用
1.1創(chuàng)建BroadcastReceiver
繼承BroadcastReceivre基類(lèi),必須復(fù)寫(xiě)抽象方法onReceive()方法。
代碼如下:
public class MyReceivre extends BroadcastReceiver{
// 復(fù)寫(xiě)onReceive()方法,接收到廣播后,則自動(dòng)調(diào)用該方法
@Override
public void onReceive(Context context, Intent intent) {
//寫(xiě)入接收廣播后的操作
}
}
1.2注冊(cè)BroadcastReceiver
注冊(cè)的方式分為兩種:靜態(tài)注冊(cè)、動(dòng)態(tài)注冊(cè)
1.2.1靜態(tài)注冊(cè)
一般為常駐廣播,在AndroidManifest.xml里通過(guò)<receive>標(biāo)簽聲明
<receiver android:name=".MyReceivre">
<intent-filter>
<!--屏幕被打開(kāi)之后的廣播-->
<action android:name="android.intent.action.ACTION_SCREEN_ON"/>
</intent-filter>
</receiver>
當(dāng)此 App首次啟動(dòng)時(shí),系統(tǒng)會(huì)自動(dòng)實(shí)例化MyReceivre 類(lèi),并注冊(cè)到系統(tǒng)中。
1.2.2動(dòng)態(tài)注冊(cè)
非常駐廣播,在使用時(shí)注冊(cè),用完及時(shí)銷(xiāo)毀。在代碼中動(dòng)態(tài)注冊(cè)示例如下:
public class MainActivity extends AppCompatActivity {
private MyReceivre mMyReceivre;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1.實(shí)例化BroadcastReceiver子類(lèi) & IntentFilter
mMyReceivre = new MyReceivre();
IntentFilter intentFilter = new IntentFilter();
//2.設(shè)置接收廣播的類(lèi)型
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
//3.動(dòng)態(tài)注冊(cè):調(diào)用Context的registerReceiver()方法
registerReceiver(mMyReceivre, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//銷(xiāo)毀在onDestroy()方法中的廣播
unregisterReceiver(mMyReceivre);
}
}
需要注意:
對(duì)于動(dòng)態(tài)廣播,有注冊(cè)就必然得有注銷(xiāo),否則會(huì)導(dǎo)致內(nèi)存泄露,重復(fù)注冊(cè)、重復(fù)注銷(xiāo)也不允許。
2.廣播發(fā)送者
2.1廣播的發(fā)送
廣播發(fā)送者 將此廣播的“意圖(Intent)”通過(guò)sendBroadcast()方法發(fā)送出去。
2.2 廣播的類(lèi)型
廣播的類(lèi)型主要分為5類(lèi):
- 普通廣播(Normal Broadcast)
- 系統(tǒng)廣播(System Broadcast)
- 有序廣播(Ordered Broadcast)
- 粘性廣播(Sticky Broadcast)
- 本地廣播(Local Broadcast)
2.2.1普通廣播
開(kāi)發(fā)者自身定義 intent的廣播,通過(guò)Context.sendBroadcast(Intent intent)發(fā)送,可以同時(shí)被所有廣播接收者無(wú)需等待的接收到。
優(yōu)點(diǎn):消息傳遞的效率比較高。
缺點(diǎn):
1、接收者不能修改該廣播。
2、無(wú)法終止廣播Intent的傳播,即無(wú)法阻止其他接收者的接收動(dòng)作。
Intent intent = new Intent();
//對(duì)應(yīng)BroadcastReceiver中intentFilter的action
intent.setAction("ACTION");
//發(fā)送的內(nèi)容
intent.putExtra("msg", "這是一條普通廣播");
//發(fā)送廣播
sendBroadcast(intent);
2.2.2系統(tǒng)廣播
只要涉及到手機(jī)的基本操作(如開(kāi)機(jī)、網(wǎng)絡(luò)狀態(tài)變化、拍照等等),基本上都會(huì)發(fā)出相應(yīng)的系統(tǒng)廣播。每個(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ā)出。當(dāng)使用系統(tǒng)廣播時(shí),只需要在注冊(cè)廣播接收者時(shí)定義相關(guān)的action即可,并不需要手動(dòng)發(fā)送廣播,當(dāng)系統(tǒng)有相關(guān)操作時(shí)會(huì)自動(dòng)進(jìn)行系統(tǒng)廣播。系統(tǒng)廣播常量見(jiàn)文末。
2.2.3有序廣播
通過(guò)Context.sendOrderedBroadcast(intent, receiverPermission)發(fā)送,是按照接收者聲明的優(yōu)先級(jí)別,被接收者依次接收廣播。
廣播接受者接收廣播的順序規(guī)則(同時(shí)面向靜態(tài)和動(dòng)態(tài)注冊(cè)的廣播接受者)
1、按照Priority屬性值從大-小排序;
2、Priority屬性相同者,動(dòng)態(tài)注冊(cè)的廣播優(yōu)先。
優(yōu)點(diǎn):
1、廣播可以通過(guò)接收者調(diào)用abortBroadcast()方法截?cái)鄰V播(被截?cái)嗟膹V播不能再繼續(xù)傳遞該廣播)。
2、接收者能修改處理結(jié)果(比如通過(guò)傳遞Bundle)傳遞給下一個(gè)接收者(一般情況下,不建議對(duì)有序廣播進(jìn)行此類(lèi)操作,尤其是針對(duì)系統(tǒng)中的有序廣播)。
缺點(diǎn):消息傳遞的效率比普通廣播低。
Intent intent2 = new Intent();
intent2.setAction("ACTION");
intent2.putExtra("msg", "這是一條有序廣播");
sendOrderedBroadcast(intent2, null);
2.2.4粘性廣播
通過(guò)mContext.sendStickyBroadcast(intent)發(fā)送,此廣播會(huì)一直滯留(等待),以便有人注冊(cè)這則廣播消息后能盡快的收到這條廣播。其他功能與sendBroadcast相同。但是使用sendStickyBroadcast 發(fā)送廣播需要獲得BROADCAST_STICKY permission,如果沒(méi)有這個(gè)permission則會(huì)拋出異常。在Android5.0 & API 21中已經(jīng)失效。
2.2.5本地廣播
本地廣播和其他的廣播有些不同,它是使用LocalBroadcastManager來(lái)發(fā)送廣播以及注冊(cè)廣播接收器的。
優(yōu)點(diǎn):它發(fā)出的廣播只會(huì)在應(yīng)用程序的內(nèi)部傳播,不用擔(dān)心廣播被其他應(yīng)用接收,造成數(shù)據(jù)泄漏,而廣播接收器也只能接收到自己應(yīng)用發(fā)出的廣播,不會(huì)接收別的應(yīng)用發(fā)來(lái)的廣播,防止接收垃圾信息。
和其他廣播用法有點(diǎn)區(qū)別,具體是使用LocalBroadcastManager類(lèi),示例如下:
//發(fā)送應(yīng)用內(nèi)廣播
Intent intent = new Intent();
intent.setAction("action");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
//注冊(cè)應(yīng)用內(nèi)廣播接收器
//1.實(shí)例化LocalBroadcastManager的實(shí)例
LocalBroadcastManager mBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
//2.設(shè)置接收廣播的類(lèi)型
intentFilter.addAction("action");
//3.接收由發(fā)送廣播的界面?zhèn)鱽?lái)的值(沒(méi)有傳值不用寫(xiě))
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//接收由發(fā)送廣播的界面?zhèn)鱽?lái)的值(沒(méi)有傳值不用寫(xiě))
}
};
//4.調(diào)用LocalBroadcastManager單一實(shí)例的registerReceiver()方法進(jìn)行動(dòng)態(tài)注冊(cè)
mBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//5.取消注冊(cè)應(yīng)用內(nèi)廣播接收器(一定要取消注冊(cè))
mBroadcastManager.unregisterReceiver(mBroadcastReceiver);
注:對(duì)于LocalBroadcastManager方式發(fā)送的應(yīng)用內(nèi)廣播,只能通過(guò)LocalBroadcastManager動(dòng)態(tài)注冊(cè),不能靜態(tài)注冊(cè)
LocalBroadcastManager源碼學(xué)習(xí)
private static LocalBroadcastManager mInstance;
@NonNull
public static LocalBroadcastManager getInstance(@NonNull Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
mAppContext = context;
//在主線程中操作
mHandler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_EXEC_PENDING_BROADCASTS:
executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
- 在獲取LocalBroadcastManager對(duì)象實(shí)例的時(shí)候,這里用了單例模式。并且把外部傳進(jìn)來(lái)的Context 轉(zhuǎn)化成了ApplicationContext,有效的避免了當(dāng)前Context的內(nèi)存泄漏的問(wèn)題。這一點(diǎn)我們?cè)谠O(shè)計(jì)單例模式框架的時(shí)候是值得學(xué)習(xí)的,看源碼可以學(xué)習(xí)到很多東西。
- 在LocalBroadcastManager構(gòu)造函數(shù)中創(chuàng)建了一個(gè)Handler.可見(jiàn) LocalBroadcastManager 的本質(zhì)上是通過(guò)Handler機(jī)制發(fā)送和接收消息的。
- 在創(chuàng)建Handler的時(shí)候,用了 context.getMainLooper() , 說(shuō)明這個(gè)Handler是在Android 主線程中創(chuàng)建的,廣播接收器的接收消息的時(shí)候會(huì)在Android 主線程,所以我們決不能在廣播接收器里面做耗時(shí)操作,以免阻塞UI。
附:部分系統(tǒng)廣播常量
| 系統(tǒng)操作 | action |
|---|---|
| 監(jiān)聽(tīng)網(wǎng)絡(luò)變化 | android.net.conn.CONNECTIVITY_CHANGE |
| 屏幕被關(guān)閉 | Intent.ACTION_SCREEN_OFF |
| 屏幕被打開(kāi) | Intent.ACTION_SCREEN_ON |
| 屏幕鎖屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
| 關(guān)閉或打開(kāi)飛行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
| 充電時(shí)或電量發(fā)生變化 | Intent.ACTION_BATTERY_CHANGED |
| 電池電量低 | Intent.ACTION_BATTERY_LOW |
| 電池電量充足 | Intent.ACTION_BATTERY_OKAY |
| 插上外部電源時(shí)發(fā)出的廣播 | Intent.ACTION_POWER_CONNECTED |
| 已斷開(kāi)外部電源連接時(shí)發(fā)出的廣播 | Intent.ACTION_POWER_DISCONNECTED |
| 關(guān)閉或打開(kāi)飛行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
| 系統(tǒng)啟動(dòng)完成后 | Intent.ACTION_BOOT_COMPLETED |
| 按下照相時(shí)的拍照按鍵(硬件按鍵)時(shí) | Intent.ACTION_CAMERA_BUTTON |
| 插入耳機(jī)時(shí) | Intent.ACTION_HEADSET_PLUG |
| 成功安裝APK | Intent.ACTION_PACKAGE_ADDED |
| 成功刪除APK | Intent.ACTION_PACKAGE_REMOVED |
| 重啟設(shè)備 | Intent.ACTION_REBOOT |
| 關(guān)閉系統(tǒng)時(shí) | Intent.ACTION_SHUTDOWN |
| 改變輸入法時(shí)發(fā)出的廣播 | Intent.ACTION_INPUT_METHOD_CHANGED |
| 設(shè)備當(dāng)前區(qū)域設(shè)置已更改時(shí)發(fā)出的廣播 | Intent.ACTION_LOCALE_CHANGED |
| 時(shí)間被設(shè)置時(shí)發(fā)出的廣播 | Intent.ACTION_TIME_CHANGED |
| 時(shí)區(qū)發(fā)生改變時(shí)發(fā)出的廣播 | Intent.ACTION_TIMEZONE_CHANGED |
| 設(shè)備日期發(fā)生改變時(shí)會(huì)發(fā)出此廣播 | Intent.ACTION_DATE_CHANGED |
關(guān)于廣播就學(xué)習(xí)到這里,如理解有誤,還望指正,謝謝!