Android四大組件之BroadcastReceiver

来源:https://www.cnblogs.com/xmkh/archive/2019/08/28/11423430.html
-Advertisement-
Play Games

前言 Hi,大家好,又雙見面啦,上一期我們講瞭如何使用Activity,肯定有不少小伙伴已經創建了屬於自己的FirstActivity,那麼這一期我們主要為大家介紹第二個重要組件BroadcastReceiver(廣播接收器)。作為Android的四大組件之二,其應用場景非常多。下麵,就詳細介紹下 ...


前言

Hi,大家好,又雙見面啦,上一期我們講瞭如何使用Activity,肯定有不少小伙伴已經創建了屬於自己的FirstActivity,那麼這一期我們主要為大家介紹第二個重要組件BroadcastReceiver(廣播接收器)。作為Android的四大組件之二,其應用場景非常多。下麵,就詳細介紹下 BroadcastReceiver 的相關知識。

 

1. 定義

BroadcastReceiver(廣播接收器)即廣播,是一個全局的監聽器。

Android 廣播分為兩個角色:廣播發送者廣播接受者

2. 作用

可以監聽或接收應用 App 或系統發出的廣播消息,並做出響應。

3. 應用場景

  1. 同一 App 內部的同一組件內的消息通信(單個或多個線程之間);

  2. 同一 App 內部的不同組件之間的消息通信(單個進程);

  3. 同一 App 具有多個進程的不同組件之間的消息通信;

  4. 不同 App 之間的組件之間消息通信;

  5. Android系統在特定情況下與App之間的消息通信,如:網路變化、電池電量、屏幕開關等。

4. 實現原理

Android中的廣播使用了觀察者模式:基於消息的發佈 / 訂閱事件模型,將廣播的發送者接收者解耦,使得系統方便集成,更易擴展。

消息的事件模型中有三個角色:

  1. 消息訂閱者(廣播接收者)

  2. 消息發佈者(廣播發送者)

  3. 消息中心(AMS,即Activity Manager Service)

具體實現流程如下:

  1. 廣播接收者BroadcastReceiver通過Binder機制向AMS中進行註冊;

  2. 廣播發送者通過binder機制向AMS發送廣播;

  3. AMS查找符合相應條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發送到BroadcastReceiver(一般情況下是Activity)相應的消息迴圈隊列中;

  4. 消息迴圈執行拿到此廣播,回調 BroadcastReceiver 中的 onReceive() 方法。

註意:廣播發送者和廣播接受者的執行順序是非同步的,發送者不會關心有無接收者及接收者是否接收。

5. 使用步驟

5.1 自定義廣播接收者BroadcastReceiver
//繼承BroadcastReceiver
public class MyBroadcaseReceiver extends BroadcastReceiver {   
    //接收到廣播後,則自動調用該方法    
    @Override    
    public void onReceive(Context context, Intent intent) {
    }
}

 

繼承 BroadcastReceivre 基類,重寫 onReceive() 方法。廣播接收器接收到相應廣播後,會自動回調 onReceive() 方法,此方法中可與其他組件進行交互,如發送通知、啟動服務等。

預設情況下,廣播接收器運行在主線程中,所以,onReceive() 方法不能執行耗時操作,否則會導致 ANR 異常。

5.2 註冊廣播接收器

廣播接收器的註冊分為兩種:靜態註冊、動態註冊。

靜態註冊:靜態註冊即在清單文件(AndroidManifest.xml)中為 BroadcastReceiver 進行註冊,使用< receiver >標簽聲明,併在標簽內用 < intent-filter > 標簽設置過濾器。這種形式的 BroadcastReceiver 的生命周期伴隨著整個應用。如果這種方式處理的是系統廣播,那麼不管應用是否在運行,該廣播接收器都能接收到該廣播。

<receiver 
    android:enabled=["true" | "false"]
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
    android:name="string"
    android:permission="string"
    android:process="string" >
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

 

android:exported ——此 BroadcastReceiver 能否接收其他 App 的發出的廣播,其預設值是由 receiver 中有無 intent-filter 決定的,如果有 intent-filter,預設值為true,否則為false。(同樣的,activity/service中的此屬性預設值一樣遵循此規則); android:name —— 此 BroadcastReceiver 類名; android:permission ——如果設置,具有相應許可權的廣播發送方發送的廣播才能被此 BroadcastReceiver 所接收; android:process —— BroadcastReceiver 運行所處的進程。預設為 App 的進程。可以指定獨立的進程(Android四大組件都可以通過此屬性指定自己的獨立進程)。

intent-filter/action ——用於指定此廣播接收器將接收的廣播類型,本示例中給出的是用於接收網路狀態改變時發出的廣播。

註冊示例:

<receiver   
    android:name=".MyBroadcaseReceiver">    
    <intent-filter>        
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />    
    </intent-filter>
</receiver>

 

當此 App首次啟動時,系統會自動實例化 MyBroadcaseReceiver 類,並註冊到系統中。

註意:Android 7.0版本開始,對靜態註冊的廣播做了限制,導致靜態註冊失效。應用無法使用清單註冊隱式廣播,仍然可以在運行時動態註冊這些廣播,並且可以使用清單註冊專門針對它們的顯式廣播。

具體可查看:https://developer.android.google.cn/about/versions/oreo/background

動態註冊:動態註冊 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.動態註冊廣播    
    registerReceiver(myBroadcaseReceiver, intentFilter);
}
​
@Override
protected void onDestroy() {    
    super.onDestroy();    
    //銷毀在onResume()中註冊的廣播    
    unregisterReceiver(mBroadcastReceiver);
}

 

註意:對於動態廣播,有註冊必須得有註銷,否知會造成記憶體泄露,重覆註冊、重覆註銷也不允許。

Android 中所有與觀察者模式有關的設計中,一旦涉及到 register,必定在相應的時機需要 unregister。

5.3 廣播發送及廣播類型

廣播發送:廣播的“發送”與“接收”,錶面上看是廣播作為 Android 廣播機制中的實體,實際上這一實體本身是並不是以所謂的”廣播“對象存在的,而是以”意圖“(Intent)去表示。定義廣播的定義本質,實際就是相應廣播”意圖“的定義過程,然後通過廣播發送者通過 sendBroadcast() 方法將此”意圖“發送出去。

廣播類型:根據廣播的發送方式,可以將其分為以下幾種類型

1.普通廣播(Normal Broadcast)

開發者自身定義 intent的廣播。發送廣播使用如下:

  
Intent intent = new Intent();
   //對應BroadcastReceiver中intentFilter的action
   intent.setAction("MY_BROADCAST_ACTION");
   //發送廣播
   sendBroadcast(intent);

 

被註冊了的廣播接收者中註冊時 intentFilter 的 action 與上述匹配,就會接收此廣播,並回調onReceive()。如下的 BroadcastReceiver 則會接收上述廣播:

  
<receiver 
    android:name=".MyBroadcastReceiver" >
    <intent-filter>
        <action android:name="MY_BROADCAST_ACTION" />
    </intent-filter>
   </receiver> 

 

註意:若發送廣播有相應許可權,那麼廣播接收者也需要相應許可權

2.系統廣播(System Broadcast)

Android系統中內置了多個系統廣播,只要涉及到手機的基本操作,基本上都會發出相應的系統廣播。如:開機啟動,網路狀態改變,拍照,屏幕關閉與開啟,電量不足等等。

每個系統廣播都具有特定的 intent-filter,其中主要包括具體的 action,系統廣播發出後,將被相應的BroadcastReceiver 接收。

當使用系統廣播時,只需在註冊廣播接收者時定義相關的action即可,不需要手動發送廣播,當系統有相關操作時會自動進行系統廣播的發送。

3.有序廣播(Ordered Broadcast)

有序廣播中的“有序”是針對廣播接收者而言的,指的是發送出去的廣播被 BroadcastReceiver 按照先後順序進行接收。有序廣播的定義過程與普通廣播無異,只是其發送方式變為:sendOrderedBroadcast(intent);

廣播接受者接收廣播的順序規則(同時面向靜態和動態註冊的廣播接受者):按照 Priority 屬性值從大-小排序,Priority屬性相同者,動態註冊的廣播優先。

特點:接收廣播按順序接收;先接收的廣播接收者可以對廣播進行截斷,即後接收的廣播接收者不再接收到此廣播;先接收的廣播接收者也可以對廣播進行修改,那麼後接收的廣播接收者將接收到被修改後的廣播。當然,一般情況下,不建議對有序廣播進行此類操作,尤其是針對系統中的有序廣播。

4.App應用內廣播(Local Broadcast)

由於 Android 中的廣播可以跨 App 直接通信(exported對於有intent-filter情況下預設值為true),可能會出現相應安全隱患

a. 其他 App 針對性發出與當前 App intent-filter 相匹配的廣播,由此導致當前 App 不斷接收廣播並處理;

b. 其他 App 註冊與當前 App 一致的 intent-filter 用於接收廣播,獲取廣播具體信息;即會出現安全性 & 效率性的問題。

解決方案

方案1:將全局廣播設置成局部廣播

a. 對於同一 App 內部發送和接收廣播,將 exported 屬性設置成false,使得非本 App 內部發出的此廣播不被接收;

b. 在廣播發送和接收時,都增加上相應的permission,用於許可權驗證;

c. 發送廣播時,指定特定廣播接收器所在的包名,具體是通過 intent.setPackage(packageName) 指定,這樣此廣播將只會發送到此包中的 App 內與之相匹配的有效廣播接收器中。

方案2:使用App應用內廣播(LocalBroadcastManager類)

App應用內廣播可理解為一種局部廣播,廣播的發送者和接收者都同屬於一個App。相比於全局廣播(普通廣播),App應用內廣播優勢體現在:安全性高 & 效率高。

使用封裝好的 LocalBroadcastManager 類使用方式上與全局廣播幾乎相同,只是註冊/取消註冊廣播接收器和發送廣播時將參數的 context 變成了 LocalBroadcastManager 的單一實例。

註意:對於LocalBroadcastManager方式發送的應用內廣播,只能通過LocalBroadcastManager動態註冊,不能靜態註冊。

  
//註冊應用內廣播接收器
   //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()方法進行動態註冊 
   localBroadcastManager.registerReceiver(myBroadcaseReceiver, intentFilter);
   
   
   //取消註冊應用內廣播接收器
   localBroadcastManager.unregisterReceiver(myBroadcaseReceiver);
   
   
   //發送應用內廣播
   Intent intent = new Intent();
   intent.setAction("MY_BROADCAST_ACTION");
   localBroadcastManager.sendBroadcast(intent);

 

5.粘性廣播(Sticky Broadcast)

由於在 Android 5.0 & API 21 中已經失效,所以不建議使用,在這裡不作闡述。

6. 特別註意

對於不同註冊方式的廣播接收器回調 onReceive(Context context,Intent intent)中的context返回值是不一樣的:

1.對於靜態註冊(全局+應用內廣播),回調 onReceive(context, intent) 中的 context 返回值是:ReceiverRestrictedContext

2.對於全局廣播的動態註冊,回調onReceive(context, intent)中的context返回值是:Activity Context

3.對於應用內廣播的動態註冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context

4.對於應用內廣播的動態註冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context

結語

作為Android的四大組件之二,並且項目開發過程中一些場景下經常被使用到,小伙伴們趕緊上手實操,把它靈活的運用到項目中,結合上一期的Activity實現有趣的交互吧。

PS:如果還有未看懂的小伙伴,歡迎加入我們的WXGZH:下碼看花,裡面有各種大神回答小伙伴們遇到的問題哦~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 簡介 資料庫,現代化的數據存儲存儲手段,是一種特殊的文件,其中存儲著需要的數據。 特點: 持久化存儲 讀寫速度極高 保證數據的有效性 對程式支持性非常好,容易擴展 2. Mysql (1)具有數據完整性: 一個資料庫就是一個完整的業務單元,可以包含多張表,數據被存儲在表中。在表中為了更加準確的 ...
  • 設置主機名 [root@localhost ~]# cat /etc/hosts127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4::1 localhost localhost.localdomai... ...
  • 前言 最近在處理一個歷史遺留項目的時候飽受其害,主要表現為偶發性的 SharedPreferences 配置文件數據錯亂,甚至丟失。經過排查發現是多進程的問題。項目中有兩個不同進程,且會頻繁的讀寫 SharedPreferences 文件,所以導致了數據錯亂和丟失。趁此機會,精讀了一遍 Shared ...
  • 本篇概要 小程式開發前的準備 小程式視圖與渲染 小程式事件 註:總的來說,微信小程式的開發代碼寫法,和 HTML、CSS、JavaScript類似很像.jpg 一,微信小程式開發前的準備 於微信小程式官網進行註冊 ==> https://mp.weixin.qq.com/cgi-bin/wx 註冊完 ...
  • void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);然後在創建上下文以pxdata 所指向的記憶體作為上下文數據存貯的容器, 最後 渲染 上下文[self.webView.layer renderInContext:context];這樣就將 we ...
  • 使用SharedPreferences(保存用戶偏好參數)保存數據, 當我們的應用想要保存用戶的一些偏好參數,比如是否自動登陸,是否記住賬號密碼,是否在Wifi下才能 聯網等相關信息,如果使用資料庫的話,顯得有點大材小用了!我們把上面這些配置信息稱為用戶的偏好 設置,就是用戶偏好的設置,而這些配置信 ...
  • 問題 問題 ld: library not found for -lstdc++.6.0.9 clang: error: linker command failed with exit code 1 (use -v to see invocation) 官方解釋 官方解釋 Xcode更新後沒有這個庫 ...
  • 前言 Hi,大家好,上一期我們講瞭如何使用BroadcastReceiver,這一期我們講解Android四大組件之Service相關知識。每天一篇技術乾貨,每天我們一起進步。 耐心專註不僅僅是美德,更是一筆財富。 1.簡介與定義 Service是一個可以在後臺執行長時間運行操作而不提供用戶界面的應 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...