說明:BroadcastReceiver——廣播接收者,是Android四大元件之一,在實際的開發過程中BroadcastReceiver的應用場景非常多,本篇文章将詳細講解一下BroadcastReceiver,如果各位碼友發現文中說明存在問題歡迎指正,CV操作請注明出處,謝謝!
1、定義說明。
BroadcastReceiver即廣播接收者,是Android四大元件之一,是一個全局的監聽器。在Android中廣播分為廣播發送者和廣播接收者,廣播發送者(一般是其他的元件進行sendBroadcast操作),廣播接收者(BroadcastReceiver)對發送出來Broadcast進行過濾、接收和響應。
2、使用場景。
Android不同元件間的通信(包括程序内和程序之間,同一App和不同App)。
與Android系統通信(如開機、網絡狀态、安裝/解除安裝應用等)。
3、内部機制(原理)。
設計模式:采用了觀察者模式,基于消息的釋出/訂閱事件模型,使得廣播的發送者和廣播的接收者進行解耦。
參與角色:廣播(消息)發送者、廣播(消息)接收者、AMS(ActivityManagerService)
實作步驟概況:
1、廣播接收者通過Binder機制在AMS注冊。
2、廣播發送者通過Binder機制在AMS發送廣播。
3、AMS根據廣播發送者的要求,在注冊清單中,根據IntentFilter /Permission查找目标廣播接受者。
4、AMS将廣播發送給目标廣播接收者的消息隊列中。
5、廣播接收者通過消息隊列擷取消息,然後回調onReceive()。
4、使用介紹。
4.1、廣播的接收。
廣播接收者的使用大概分為三步:建立廣播接收者、注冊廣播接收者、根據需求實作邏輯。
4.1.1 、建立廣播接收者。繼承BroadcastReceivre,複寫抽象方法onReceive()。
public class XxxReceiver extends BroadcastReceiver {
private static final String TAG = "XxxReceiver";
public XxxReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
//處理業務邏輯等,如發送Notification、啟動Service等
}
}
注意:onReceive運作在UI線程中,是以,onReceive()方法不能執行耗時操作,否則将導緻ANR
另外不要在此有開啟子線程的操作,會造成記憶體洩漏,如果需要請采用其他方式或者IntentService。
4.1.2 、注冊廣播接收者(Android 8.0大部分靜态注冊廣播失效,僅剩下較少的系統廣播可以靜态注冊)。
1、靜态注冊,即在清單檔案中為BroadcastReceiver進行注冊,使用<receive >标簽聲明,并在标簽内<intent-filter >标簽設定過濾器。
這種形式的 BroadcastReceiver 的生命周期伴随着整個應用,如果這種方式處理的是系統廣播,那麼不管應用是否在運作,該廣播接收器都能接收到該廣播
<receiver android:name=".XxxReceiver">
<intent-filter>
<action android:name="com.example.leisure.yyy" />
<!--過濾屬性,隻有具有該屬性的廣播才會被接收-->
</intent-filter>
</receiver>
<XxxReceiver
廣播接收者為四大元件之一,也具有下邊的較為常用的屬性
android:exported="true"<!--外部應用是否可以調用,預設為true,如果不對外開放,建議false-->
android:permission=""<!--具有相應權限的廣播發送者發送的廣播才能被此BroadcastReceiver所接收-->
android:process=""<!--指定程序-->
android:enabled=""<!--能否接收其他App的發出的廣播-->
2、動态注冊。即在代碼中定義并設定好一個IntentFilter對象,然後在需要注冊的地方調用Context.registerReceiver()方法,調用Context.unregisterReceiver()可以取消注冊。
@Override
public void onCreate() {
super.onCreate();//注冊廣播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.leisure.yyy");//
receiver = new XxxReceiver();
registerReceiver(receiver, intentFilter);
}
@Override
public void onDestroy() {
super.onDestroy();//取消注冊廣播
unregisterReceiver(receiver);
}
注意:動态廣播的注冊和取消注冊須要成對出現。如果Activity/Fragment中建議在onResume()注冊、onPause()登出廣播因為onPause()在App死亡前一定會被執行,進而保證廣播在App死亡前一定會被登出,進而防止記憶體洩露。除非必要不建議在onCreate()/onDestory() 或 onStart()/onStop()注冊、登出,因為當系統因為記憶體不足(如優先級更高的應用需要記憶體)要回收Activity占用的資源時,Activity在執行完onPause()方法後就會被銷毀,有些生命周期方法onStop(),onDestory()就不會執行。
當再回到此Activity時,是從onCreate方法開始執行,造成記憶體洩漏。
4.2、廣播的發送。
4.2.1、廣播的分類,可分為5種:Normal Broadcast、System Broadcast、Sticky Broadcast、Local Broadcast。
1、普通廣播(Normal Broadcast)。
最為常用的廣播,一般需要添加action,聲明了對應的action的廣播接收者才能收到廣播,即onReceive()回調。如果添加了權限,則廣播接收者也需要在注冊的時候明确權限。
Intent intent = new Intent();
//對應BroadcastReceiver中intentFilter的action,
intent.setAction("com.example.leisure.yyy");
//發送廣播
sendBroadcast(intent);
2、系統廣播(System Broadcast)。
系統廣播,不需要app去發送,由系統根據情況自動發送,app隻負責接收(如果需要)。
3、有序廣播(Ordered Broadcast)。發送出去的廣播被廣播接收者按照先後順序接收,有序是針對廣播接收者而言的。
廣播接受者接收的順序規則是按照Priority屬性值從大到小排序(同一Priority,動态注冊的廣播優先級大于靜态注冊的廣播);
先接收的廣播接收者可以對廣播進行攔截,小優先級的廣播接收者将無法收到該廣播;
先接收的廣播接收者可以對廣播進行修改,小優先級的廣播接收者将接收到被修改後的廣播。
示例:
Intent intent = new Intent("com.receiver.leisure.common");
intent.putExtra("xxx", "有序廣播");
sendOrderedBroadcast(intent, null);//發送有序廣播
//此處忽略了注冊過程。
public class OrderReceiverXxx extends BroadcastReceiver {//第一優先級
public OrderReceiverXxx() {
}
@Override
public void onReceive(Context context, Intent intent) {
//取出Intent當中傳遞來的資料
String msg = intent.getStringExtra("xxx");
//向下一優先級的Receiver傳遞資料
Bundle bundle = new Bundle();
bundle.putString("yyy", "xxx修改了廣播");
setResultExtras(bundle);
}
}
public class OrderReceiverYyy extends BroadcastReceiver {//第二優先級
public OrderReceiverYyy() {
}
@Override
public void onReceive(Context context, Intent intent) {
//取出上一優先級的Receiver傳遞來的資料
String data = getResultExtras(true).getString("yyy");
//攔截廣播
abortBroadcast();
}
}
public class OrderReceiverZzz extends BroadcastReceiver {//第三優先級
public OrderReceiverZzz() {
}
@Override
public void onReceive(Context context, Intent intent) {
//收不到廣播了
}
}
4、粘性廣播(Sticky Broadcast)。Android5.0(API 21)中已經失效,可忽略。
5、本地廣播(Local Broadcast)。
由于Android中的廣播可以跨程序(App)通信,不同的App注冊的廣播intent-filter可能會相同,也存在其他App根據intent-filter針對性的惡意發送某些廣播造成安全或者效率問題。
Android内提供了本地廣播,廣播的發送者和接收者都同屬于一個App,提高了效率和安全性。
針對普通廣播效率和安全性的問題,一般有兩種方式:
1、注冊廣播時候将exported屬性設定為false;增設相應權限permission,用于權限驗證;發送廣播指定包名。
2、建議使用本地廣播的形式。
本地廣播是使用LocalBroadcastManager來對廣播進行管理,和普通廣播存在注冊、發送的方式的細微差别,除此之外都一樣。
LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter)
注冊Receiver
LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver);
登出Receiver
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent)
發送異步廣播
LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent)
發送同步廣播
5、注意事項。
1、不同注冊方式的廣播接收器回調OnReceive(Context context,Intent intent)中的context傳回值是不一樣的,靜态注冊的廣播是ReceiverRestrictedContext;動态注冊的廣播是Activity Context;本地廣播是Application Context。