前言:
最近的計划是學習一下iOS的NSNotificationCenter,突然想起來的Android的廣播機制,所以還是覺得先對BroadcastReceiver來個全面的總結然后再去學習NSNotificationCenter。
BroadcastReceiver簡介:
BroadcastReceiver是Android四大組件之一,廣播是一種廣泛運用的在應用程序之間傳輸信息的機制,而BroadcastReceiver 是對發送出來的廣播進行過濾接收並響應的一類組件;廣播接收者( BroadcastReceiver )用於接收廣播 Intent ,廣播 Intent 的發送是通過調用 Context.sendBroadcast() 、 Context.sendOrderedBroadcast() 來實現的。通常一個廣播 Intent 可以被訂閱了此 Intent 的多個廣播接收者所接收。
廣播的使用場景:
1.同一app內部的同一組件內的消息通信(單個或多個線程之間);
2.同一app內部的不同組件之間的消息通信(單個進程);
3.同一app具有多個進程的不同組件之間的消息通信;
4.不同app之間的組件之間消息通信;
5.Android系統在特定情況下與App之間的消息通信。
廣播的分類:
普通廣播:
發送方式:Context.sendBroadcast()
優點:完全異步,消息傳遞效率高,
缺點:不能處理廣播傳給一個接收者,不能終止廣播的傳播
有序廣播:
發送方式:Context.sendOrderedBroadcast()
優點:可以根據廣播接收者的優先級依次傳播,廣播接收者可以處理廣播然后再傳給一下廣播接收者,也可以根據需要調用abortBroadcast()終止廣播傳播。
缺點:效率低
廣播的使用方式:
動態注冊:
//注冊廣播 private void registerReceiver(){ IntentFilter dynamicFilter = new IntentFilter(); dynamicFilter.addAction(ActionCodes.DYNAMICACTION);//添加動態廣博Action registerReceiver(dynamicReceiver, dynamicFilter); } //解除注冊 private void unRegisterReceiver() { unregisterReceiver(dynamicReceiver); } //動態廣播的Receiver private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(ActionCodes.DYNAMICACTION)){ //動作檢測 String msg = intent.getStringExtra("msg"); String finalMsg= String.format("%s%s","CActivity----->收到廣播:",msg); Log.e("dynamicReceiver",finalMsg); Toast.makeText(context, finalMsg, Toast.LENGTH_SHORT).show(); } } };
一般情況在Activity/Fragment 的onCreate/onStart/onResume 中注冊, 在onDestory/onStop/onPause 中解除注冊,根據不同的需求選擇不能的生命周期函數。
靜態注冊:
<receiver android:name=".StaticReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" /> </intent-filter> </receiver>
發送廣播:
//發送普通廣播 Intent intent = new Intent(); intent.setAction(ActionCodes.DYNAMICACTION);//設置Action intent.putExtra("msg", "我是普通廣播(動態注冊)");//添加附加信息 sendBroadcast(intent); //發送有序廣播 Intent intent = new Intent(); intent.setAction(ActionCodes.DYNAMICACTION);//設置Action intent.setPackage(getPackageName());//設置包名 intent.putExtra("msg", "我是有序廣播(動態注冊)");//添加附加信息 sendOrderedBroadcast(intent,null);
以上基本上可以滿足廣播的基本使用了,接下來我們在寫個測試程序:分別在A,B,C三個Activity中動態注冊廣播,分別發送普通廣播和和有序廣播。
發送普通廣播接收順序:
分別給A,B,C三個Activity中動態注冊廣播的優先級設置未100,500,1000接收順序:
附上設置優先級方式:
IntentFilter dynamicFilter = new IntentFilter(); dynamicFilter.addAction(ActionCodes.DYNAMICACTION);//添加動態廣播的Action dynamicFilter.setPriority(1000);//設置優先級 registerReceiver(dynamicReceiver, dynamicFilter);
上文已知有序廣播可以修改廣播信息傳遞給下一級優先級低的接收者,我們讓BActivity修改 讓AActivity接收:
BActivity 廣播實現
//動態廣播的Receiver private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(ActionCodes.DYNAMICACTION)){ //動作檢測 String msg = intent.getStringExtra("msg"); String finalMsg= String.format("%s%s","BActivity----->收到廣播:",msg); Log.e("dynamicReceiver",finalMsg); Toast.makeText(context, finalMsg, Toast.LENGTH_SHORT).show(); if(isOrderedBroadcast()) { //創建一個Bundle對象,並存入數據 Bundle bundle = new Bundle(); bundle.putString("msg", msg + "來自BActivity"); //將bundle放入結果中 setResultExtras(bundle); //取消Broadcast的繼續發送 //abortBroadcast(); } } } };
AActivity 如何接收:
//動態廣播的Receiver private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(ActionCodes.DYNAMICACTION)) { //動作檢測 String msg = intent.getStringExtra("msg"); String finalMsg = String.format("%s%s", "AActivity----->收到廣播:", msg); Log.e("dynamicReceiver", finalMsg); if (isOrderedBroadcast()) { Bundle bundle = getResultExtras(true);//接收來自上一級優先級較高的廣播修改的信息 String from = bundle.getString("msg"); if (TextUtils.isEmpty(from)) { return; } Log.e("dynamicReceiver", String.format("%s%s", "AActivity----->收到廣播:", from)); Toast.makeText(context, finalMsg, Toast.LENGTH_SHORT).show(); } } } };
運行結果:
有序廣播如何終止廣播傳播:
// 終止Broadcast的繼續發送 abortBroadcast();
運行結果:
靜態注冊的廣播上述測試運行結果一致,設置優先級方式不同而已:
<receiver android:name=".AStaticReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"><!--設置優先級--> <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" /> </intent-filter> </receiver>
接下來測試一下app應用之間發送廣播,發送方式也是通過隱式Intent方式:
動態注冊廣播接收情況:
普通廣播:
有序廣播:
靜態注冊廣播接收情況:
普通廣播:
有序廣播:
看了上述測試結果基本上和app內運行效果一模一樣,所以按照上述那種注冊方式和使用方式,一旦app被反編譯之后有一定的安全隱患,如何安全的傳輸呢?
第一種方式:
靜態注冊廣播可以設置:android:exported="false"
<receiver android:name=".AStaticReceiver" android:enabled="true" android:exported="false" <!--設置只能接收app內廣播 --> > <intent-filter android:priority="100"><!--設置優先級--> <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" /> </intent-filter> </receiver>
第二種方式:通過設置發送的廣播只能app內接收
Intent intent = new Intent(); intent.setAction(ActionCodes.DYNAMICACTION);//設置Action intent.setPackage(getPackageName());//設置包名使廣播只能被包名的app內接收者接收 intent.putExtra("msg", "我是普通廣播(動態注冊)");//添加附加信息 sendBroadcast(intent);
第三種方式通過自定義權限:通過上述兩種方式只能達到屏蔽外來廣播以及廣播只在app內傳播,無法實現app之間安全發送廣播
自定義權限:
<permission android:name="com.whoislcj.broadcastreceiver.MySelfBroadcastReceiver" /> <uses-permission android:name="com.whoislcj.broadcastreceiver.MySelfBroadcastReceiver"/>
動態注冊:
IntentFilter dynamicFilter = new IntentFilter(); dynamicFilter.addAction(ActionCodes.DYNAMICACTION);//添加動態廣播的Action dynamicFilter.setPriority(500); //設置權限 registerReceiver(dynamicReceiver, dynamicFilter,ActionCodes.MYPERMISSION,null);
靜態注冊:
<receiver android:name=".BStaticReceiver" android:enabled="true" android:exported="true" <!--設置權限--> android:permission="com.whoislcj.broadcastreceiver.MySelfBroadcastReceiver"> <intent-filter android:priority="500"> <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" /> </intent-filter> </receiver>
發送廣播:
//普通廣播 sendBroadcast(intent,ActionCodes.MYPERMISSION); //有序廣播 sendOrderedBroadcast(intent,ActionCodes.MYPERMISSION);
第四種方式:通過LocalBroadcastManager方式
注冊:
LocalBroadcastManager.getInstance(getInstance()).registerReceiver(receiver, filter);
解除注冊:
LocalBroadcastManager.getInstance(getInstance()).unregisterReceiver(receiver);
發送廣播:
LocalBroadcastManager.getInstance(getInstance()).sendBroadcastSync(intent);
總結:
通過本文可以看出BroadcastReceiver使用方式雖然看似簡單,想要實現比較完善的廣播還是要費一番功夫的。