摘要:作為的四大組件之二,其應用場景非常多。作用可以監(jiān)聽或接收應用或系統(tǒng)發(fā)出的廣播消息,并做出響應??梢灾付í毩⒌倪M程四大組件都可以通過此屬性指定自己的獨立進程。對于應用內廣播的動態(tài)注冊方式,回調中的返回值是。
前言
Hi,大家好,又雙見面啦,上一期我們講了如何使用Activity,肯定有不少小伙伴已經(jīng)創(chuàng)建了屬于自己的FirstActivity,那么這一期我們主要為大家介紹第二個重要組件BroadcastReceiver(廣播接收器)。作為Android的四大組件之二,其應用場景非常多。下面,就詳細介紹下 BroadcastReceiver 的相關知識。
1. 定義BroadcastReceiver(廣播接收器)即廣播,是一個全局的監(jiān)聽器。
Android 廣播分為兩個角色:廣播發(fā)送者、廣播接受者。
2. 作用可以監(jiān)聽或接收應用 App 或系統(tǒng)發(fā)出的廣播消息,并做出響應。
3. 應用場景同一 App 內部的同一組件內的消息通信(單個或多個線程之間);
同一 App 內部的不同組件之間的消息通信(單個進程);
同一 App 具有多個進程的不同組件之間的消息通信;
不同 App 之間的組件之間消息通信;
Android系統(tǒng)在特定情況下與App之間的消息通信,如:網(wǎng)絡變化、電池電量、屏幕開關等。
4. 實現(xiàn)原理Android中的廣播使用了觀察者模式:基于消息的發(fā)布 / 訂閱事件模型,將廣播的發(fā)送者和接收者解耦,使得系統(tǒng)方便集成,更易擴展。
消息的事件模型中有三個角色:
消息訂閱者(廣播接收者)
消息發(fā)布者(廣播發(fā)送者)
消息中心(AMS,即Activity Manager Service)
具體實現(xiàn)流程如下:
廣播接收者BroadcastReceiver通過Binder機制向AMS中進行注冊;
廣播發(fā)送者通過binder機制向AMS發(fā)送廣播;
AMS查找符合相應條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發(fā)送到BroadcastReceiver(一般情況下是Activity)相應的消息循環(huán)隊列中;
消息循環(huán)執(zhí)行拿到此廣播,回調 BroadcastReceiver 中的 onReceive() 方法。
注意:廣播發(fā)送者和廣播接受者的執(zhí)行順序是異步的,發(fā)送者不會關心有無接收者及接收者是否接收。
5. 使用步驟//繼承BroadcastReceiver public class MyBroadcaseReceiver extends BroadcastReceiver { //接收到廣播后,則自動調用該方法 @Override public void onReceive(Context context, Intent intent) { } }
繼承 BroadcastReceivre 基類,重寫 onReceive() 方法。廣播接收器接收到相應廣播后,會自動回調 onReceive() 方法,此方法中可與其他組件進行交互,如發(fā)送通知、啟動服務等。
默認情況下,廣播接收器運行在主線程中,所以,onReceive() 方法不能執(zhí)行耗時操作,否則會導致 ANR 異常。
廣播接收器的注冊分為兩種:靜態(tài)注冊、動態(tài)注冊。
靜態(tài)注冊:靜態(tài)注冊即在清單文件(AndroidManifest.xml)中為 BroadcastReceiver 進行注冊,使用< receiver >標簽聲明,并在標簽內用 < intent-filter > 標簽設置過濾器。這種形式的 BroadcastReceiver 的生命周期伴隨著整個應用。如果這種方式處理的是系統(tǒng)廣播,那么不管應用是否在運行,該廣播接收器都能接收到該廣播。
android:exported ——此 BroadcastReceiver 能否接收其他 App 的發(fā)出的廣播,其默認值是由 receiver 中有無 intent-filter 決定的,如果有 intent-filter,默認值為true,否則為false。(同樣的,activity/service中的此屬性默認值一樣遵循此規(guī)則);
android:name —— 此 BroadcastReceiver 類名;
android:permission ——如果設置,具有相應權限的廣播發(fā)送方發(fā)送的廣播才能被此 BroadcastReceiver 所接收;
android:process —— BroadcastReceiver 運行所處的進程。默認為 App 的進程??梢灾付í毩⒌倪M程(Android四大組件都可以通過此屬性指定自己的獨立進程)。
intent-filter/action ——用于指定此廣播接收器將接收的廣播類型,本示例中給出的是用于接收網(wǎng)絡狀態(tài)改變時發(fā)出的廣播。
注冊示例:
當此 App首次啟動時,系統(tǒng)會自動實例化 MyBroadcaseReceiver 類,并注冊到系統(tǒng)中。
注意:Android 7.0版本開始,對靜態(tài)注冊的廣播做了限制,導致靜態(tài)注冊失效。應用無法使用清單注冊隱式廣播,仍然可以在運行時動態(tài)注冊這些廣播,并且可以使用清單注冊專門針對它們的顯式廣播。
具體可查看:https://developer.android.goo...
動態(tài)注冊:動態(tài)注冊 BroadcastReceiver 是在代碼中定義并設置好一個 IntentFilter 對象,然后在需要注冊的地方調用 Context.registerReceiver() 方法,調用 Context.unregisterReceiver() 方法取消注冊,此時就不需要在清單文件中注冊 Receiver 了。
@Override protected void onResume() { super.onResume(); //1.實例化MyBroadcaseReceiver MyBroadcaseReceiver myBroadcaseReceiver = new MyBroadcaseReceiver(); //2.設置廣播類型 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //3.動態(tài)注冊廣播 registerReceiver(myBroadcaseReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); //銷毀在onResume()中注冊的廣播 unregisterReceiver(mBroadcastReceiver); }
注意:對于動態(tài)廣播,有注冊必須得有注銷,否知會造成內存泄露,重復注冊、重復注銷也不允許。
Android 中所有與觀察者模式有關的設計中,一旦涉及到 register,必定在相應的時機需要 unregister。
廣播發(fā)送:廣播的“發(fā)送”與“接收”,表面上看是廣播作為 Android 廣播機制中的實體,實際上這一實體本身是并不是以所謂的”廣播“對象存在的,而是以”意圖“(Intent)去表示。定義廣播的定義本質,實際就是相應廣播”意圖“的定義過程,然后通過廣播發(fā)送者通過 sendBroadcast() 方法將此”意圖“發(fā)送出去。
廣播類型:根據(jù)廣播的發(fā)送方式,可以將其分為以下幾種類型
1.普通廣播(Normal Broadcast)
開發(fā)者自身定義 intent的廣播。發(fā)送廣播使用如下:
Intent intent = new Intent(); //對應BroadcastReceiver中intentFilter的action intent.setAction("MY_BROADCAST_ACTION"); //發(fā)送廣播 sendBroadcast(intent);
被注冊了的廣播接收者中注冊時 intentFilter 的 action 與上述匹配,就會接收此廣播,并回調onReceive()。如下的 BroadcastReceiver 則會接收上述廣播:
注意:若發(fā)送廣播有相應權限,那么廣播接收者也需要相應權限
2.系統(tǒng)廣播(System Broadcast)
Android系統(tǒng)中內置了多個系統(tǒng)廣播,只要涉及到手機的基本操作,基本上都會發(fā)出相應的系統(tǒng)廣播。如:開機啟動,網(wǎng)絡狀態(tài)改變,拍照,屏幕關閉與開啟,電量不足等等。
每個系統(tǒng)廣播都具有特定的 intent-filter,其中主要包括具體的 action,系統(tǒng)廣播發(fā)出后,將被相應的BroadcastReceiver 接收。
當使用系統(tǒng)廣播時,只需在注冊廣播接收者時定義相關的action即可,不需要手動發(fā)送廣播,當系統(tǒng)有相關操作時會自動進行系統(tǒng)廣播的發(fā)送。
3.有序廣播(Ordered Broadcast)
有序廣播中的“有序”是針對廣播接收者而言的,指的是發(fā)送出去的廣播被 BroadcastReceiver 按照先后順序進行接收。有序廣播的定義過程與普通廣播無異,只是其發(fā)送方式變?yōu)椋簊endOrderedBroadcast(intent);
廣播接受者接收廣播的順序規(guī)則(同時面向靜態(tài)和動態(tài)注冊的廣播接受者):按照 Priority 屬性值從大-小排序,Priority屬性相同者,動態(tài)注冊的廣播優(yōu)先。
特點:接收廣播按順序接收;先接收的廣播接收者可以對廣播進行截斷,即后接收的廣播接收者不再接收到此廣播;先接收的廣播接收者也可以對廣播進行修改,那么后接收的廣播接收者將接收到被修改后的廣播。當然,一般情況下,不建議對有序廣播進行此類操作,尤其是針對系統(tǒng)中的有序廣播。
4.App應用內廣播(Local Broadcast)
由于 Android 中的廣播可以跨 App 直接通信(exported對于有intent-filter情況下默認值為true),可能會出現(xiàn)相應安全隱患:
a. 其他 App 針對性發(fā)出與當前 App intent-filter 相匹配的廣播,由此導致當前 App 不斷接收廣播并處理;
b. 其他 App 注冊與當前 App 一致的 intent-filter 用于接收廣播,獲取廣播具體信息;即會出現(xiàn)安全性 & 效率性的問題。
解決方案:
方案1:將全局廣播設置成局部廣播
a. 對于同一 App 內部發(fā)送和接收廣播,將 exported 屬性設置成false,使得非本 App 內部發(fā)出的此廣播不被接收;
b. 在廣播發(fā)送和接收時,都增加上相應的permission,用于權限驗證;
c. 發(fā)送廣播時,指定特定廣播接收器所在的包名,具體是通過 intent.setPackage(packageName) 指定,這樣此廣播將只會發(fā)送到此包中的 App 內與之相匹配的有效廣播接收器中。
方案2:使用App應用內廣播(LocalBroadcastManager類)
App應用內廣播可理解為一種局部廣播,廣播的發(fā)送者和接收者都同屬于一個App。相比于全局廣播(普通廣播),App應用內廣播優(yōu)勢體現(xiàn)在:安全性高 & 效率高。
使用封裝好的 LocalBroadcastManager 類使用方式上與全局廣播幾乎相同,只是注冊/取消注冊廣播接收器和發(fā)送廣播時將參數(shù)的 context 變成了 LocalBroadcastManager 的單一實例。
注意:對于LocalBroadcastManager方式發(fā)送的應用內廣播,只能通過LocalBroadcastManager動態(tài)注冊,不能靜態(tài)注冊。
//注冊應用內廣播接收器 //1:實例化MyBroadcaseReceiver MyBroadcaseReceiver myBroadcaseReceiver = new MyBroadcaseReceiver(); //2:實例化IntentFilter、設置接收廣播的類型 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //3:實例化LocalBroadcastManager LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); //4:調用LocalBroadcastManager的registerReceiver()方法進行動態(tài)注冊 localBroadcastManager.registerReceiver(myBroadcaseReceiver, intentFilter); //取消注冊應用內廣播接收器 localBroadcastManager.unregisterReceiver(myBroadcaseReceiver); //發(fā)送應用內廣播 Intent intent = new Intent(); intent.setAction("MY_BROADCAST_ACTION"); localBroadcastManager.sendBroadcast(intent);
5.粘性廣播(Sticky Broadcast)
由于在 Android 5.0 & API 21 中已經(jīng)失效,所以不建議使用,在這里不作闡述。
6. 特別注意對于不同注冊方式的廣播接收器回調 onReceive(Context context,Intent intent)中的context返回值是不一樣的:
1.對于靜態(tài)注冊(全局+應用內廣播),回調 onReceive(context, intent) 中的 context 返回值是:ReceiverRestrictedContext;
2.對于全局廣播的動態(tài)注冊,回調onReceive(context, intent)中的context返回值是:Activity Context;
3.對于應用內廣播的動態(tài)注冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context。
4.對于應用內廣播的動態(tài)注冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context。
結語作為Android的四大組件之二,并且項目開發(fā)過程中一些場景下經(jīng)常被使用到,小伙伴們趕緊上手實操,把它靈活的運用到項目中,結合上一期的Activity實現(xiàn)有趣的交互吧。
PS:如果還有未看懂的小伙伴,歡迎加入我們的QQ技術交流群:892271582,里面有各種大神回答小伙伴們遇到的問題哦~
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/76163.html
摘要:但是,一定會被執(zhí)行,從而保證了廣播在死亡前一定會被注銷,從而防止內存泄露。對于應用內廣播的動態(tài)注冊非方式,回調中的返回值是 前言 BroadcastReceiver(廣播接收器),屬于Android四大組件之一 在Android開發(fā)中,BroadcastReceiver的應用場景非常多 今天,我將詳細講解關于BroadcastReceiver的一切相關知識 目錄 showImg(...
摘要:靜態(tài)注冊廣播的方法動態(tài)注冊廣播在中動態(tài)注冊廣播,通常格式如下動態(tài)注冊廣播動態(tài)注冊監(jiān)聽滅屏點亮屏幕的廣播在廣播中動態(tài)注冊廣播請注意一定要使用,防止為空,引起空指針異常。綁定模式此模式通過綁定組件等調用啟動此服務隨綁定組件的消亡而解除綁定。 showImg(https://segmentfault.com/img/remote/1460000019975019?w=157&h=54); 極...
閱讀 1363·2023-04-26 00:10
閱讀 2461·2021-09-22 15:38
閱讀 3937·2021-09-22 15:13
閱讀 3552·2019-08-30 13:11
閱讀 672·2019-08-30 11:01
閱讀 3069·2019-08-29 14:20
閱讀 3236·2019-08-29 13:27
閱讀 1753·2019-08-29 11:33