解析BroadcastReceiver之你需要瞭解的一些東東

来源:http://www.cnblogs.com/shouce/archive/2016/04/05/5353707.html
-Advertisement-
Play Games

前些天把四大組件之一的Service扯了一遍,今天就要開始談談它的弟兄BroadcastReceiver了。寫到這裡我挺糾結的,因為廣播接收者確實比較簡單,但是各位就不要以為簡單的就不內涵,也許我們慢慢探討一下還能有另外一片天地。 慣例還是先會介紹一下基礎的知識,後面會說說關於BroadcastRe ...


  前些天把四大組件之一的Service扯了一遍,今天就要開始談談它的弟兄BroadcastReceiver了。寫到這裡我挺糾結的,因為廣播接收者確實比較簡單,但是各位就不要以為簡單的就不內涵,也許我們慢慢探討一下還能有另外一片天地。

  慣例還是先會介紹一下基礎的知識,後面會說說關於BroadcastReceiver的接收順序還有其他的一些小知識。

 

BroadcastReceiver的概念

  BroadcastReceiver的作用主要是用來監聽系統或者應用發出的廣播信息,然後根據廣播信息作為相應的邏輯處理;說通俗點其實上就是一種全局監聽器,要來實現系統中不同組件之間的通信。有時候也會用來作為傳輸少量而且發送頻率低的數據,但是如果數據的發送頻率比較高或者數量比較大就不建議用廣播接收者來接收了,因為這樣的效率很不好,因為BroadcastReceiver接收數據的開銷還是比較大的。

 

BroadcastReceiver的基礎使用

  我們先來看看廣播接收者的代碼,如下:

1 public class MyBroadcastReceiver extends BroadcastReceiver {
2     @Override
3     public void onReceive(Context arg0, Intent arg1) {
4         //  用來實現廣播接受者接收到廣播後執行的代碼邏輯
5     }
6 }

  簡單而完美,實現一個廣播接受者僅僅需要我們重寫一個函數onReceiver(),如果廣播接受者接收到廣播後將會執行該函數;但是這個前提是需要將這個廣播接收者進行註冊,一般來說,BroadcastReceiver的註冊方式有且只有兩種,一種是靜態註冊,另外一種是動態註冊,廣播接收者在註冊後就開始監聽系統或者應用之間發送的廣播消息。

 

靜態註冊的方式:打開AndroidManifest清單文件中,像Activity、Service那種添加一個數據項進行註冊,如下:

<receiver android:name=".MyBroadcastReceiver">
  <intent-filter>
    <!-- action的命名規則一般建議為:包名.intent.類名  -->
    <action android:name="com.net168.testBcr.intent.mybroadcastreceiver"/>
  </intent-filter>
</receiver>

  靜態註冊的廣播接收者就是一個常駐在系統中的全局監聽器,也就是說如果你應用中配置了一個靜態的BroadcastReceiver,而且你安裝了應用而無論應用是否處於運行狀態,廣播接收者都是已經常駐在系統中了。但是有些人會很鬱悶怎麼銷毀掉這個廣播接收者,其實只要調用PackageManager將Receiver禁用就行了,簡單實用吧?

 

動態註冊的方式:使用registerReceiver(receiver, filter)進行廣播接收者的註冊,代碼如下:

//filter是設置receiver的攔截器
IntentFilter filter = new IntentFilter("com.net168.testBcr.intent.mybroadcastreceiver");
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
//動態註冊廣播接收者
registerReceiver(receiver, filter);

動態註冊的廣播接收者只有執行了registerReceiver(receiver, filter)才會開始監聽廣播消息,並對廣播消息作為相應的處理。

銷毀一個動態註冊的BroadcastReceiver如下:

//撤銷廣播接受者的動態註冊
unregisterReceiver(receiver);

撤銷註冊後廣播接收者將不會再監聽系統的廣播消息。

 

靜態註冊的BroadcastReceiver和動態註冊的BroadcastReceiver的一些區別

1、靜態註冊的廣播接收者一經安裝就常駐在系統之中,不需要重新啟動喚醒接收者;動態註冊的廣播接收者隨著應用的生命周期,由registerReceiver開始監聽,由unregisterReceiver撤銷監聽,另外需要註意的一點就是如果應用退出後,沒有撤銷已經註冊的接收者應用應用將會報錯。

2、當廣播接收者通過intent啟動一個activity或者service時,如果intent中無法匹配到相應的組件。動態註冊的廣播接收者將會導致應用報錯,而靜態註冊的廣播接收者將不會有任何報錯,因為自從應用安裝完成後,廣播接收者跟應用已經脫離了關係。

 

廣播接收者機制

  當系統或應用發出廣播時,將會掃描系統中的所有廣播接收者,通過action匹配將廣播發送給相應的接收者,接收者收到廣播後將會產生一個廣播接收者的實例,執行其中的onReceiver()這個方法;特別需要註意的是這個實例的生命周期只有10秒,如果10秒內沒執行結束onReceiver(),系統將會報錯。另外在onReceiver()執行完畢之後,該實例將會被銷毀,所以不要在onReceiver()中執行耗時操作,也不會在裡面創建子線程處理業務(因為可能子線程沒處理完,接收者就被回收了);正確的處理方法就是通過intent調用activity或者service處理業務。

 

發送廣播

  廣播有三種類型:普通廣播和有序廣播,還有另外一種不怎麼常用的粘性廣播

  Android為了滿足各種應用要求,設置了兩個發送廣播的方式,各有特點。一般普通廣播可以應用在需要通知各個廣播接收者的情況下如開機啟動結束髮送的廣播;而有序廣播則應用在需要有特定攔截的場景下如黑名單簡訊、電話攔截。

 

普通廣播普通廣播是完全非同步的,可以在同一時刻(邏輯上)被所有接收者接收到,消息傳遞的效率比較高,並且無法中斷廣播的傳播。

Intent intent = new Intent();
intent.setAction("com.net168.testBcr.intent.mybroadcastreceiver");
intent.putExtra("data", "hello");
//發送普通廣播
sendBroadcast(intent);

通過sendBroad(intent)來發送普通的廣播消息。

 

有序廣播:發送有序廣播後,廣播接收者將按預先聲明的優先順序依次接收Broadcast。優先順序高的優先接收到廣播,而在其onReceiver()執行過程中,廣播不會傳播到下一個接收者,此時當前的廣播接收者可以終止廣播繼續向下傳播,也可以將intent中的數據進行修改設置,然後將其傳播到下一個廣播接收者。

通過sendOrderedBroadcast()來發送有序廣播。

//發送有序廣播
 sendOrderedBroadcast(intent, null);

對於有序廣播接收者,我們可以再onReceiver中進行一些操作

複製代碼
public void onReceive(Context arg0, Intent intent) {
  //獲取上一個廣播的bundle數據
  Bundle bundle = getResultExtras(true);//true:前一個廣播沒有結果時創建新的Bundle;false:不創建Bundle
  bundle.putString("key", "168168");
  //將bundle數據放入廣播中傳給下一個廣播接收者
  setResultExtras(bundle);
  //終止廣播傳給下一個廣播接收者
  abortBroadcast();
}
複製代碼

在有序廣播中,我們可以在前一個廣播接收者將處理好的數據傳送給後面的廣播接收者,也可以調用abortBroadcast()來終結廣播的傳播。

 

粘性廣播:該廣播比較不常用,我們可以通過sendStickyBroadcast()來發送該類型的廣播信息,這種的廣播的最大特點是,當粘性廣播發送後,最後的一個粘性廣播會滯留在操作系統中。如果在粘性廣播發送後的一段時間里,如果有新的符合廣播的動態註冊的廣播接收者註冊,將會收到這個廣播消息,雖然這個廣播是在廣播接收者註冊之前發送的,另外一點,對於靜態註冊的廣播接收者來說,這個等同於普通廣播。

 

 廣播接收者接收廣播的次序

註意一點:廣播接收者的優先順序範圍谷歌文檔上標示的最大級為1000,但是實際上最大的級數是Integer.MAX(即2147483647)。

  靜態廣播接收的處理器是由PackageManagerService負責,當手機啟動或者新安裝了應用的時候,PackageManagerService會掃描手機中所有已安裝的APP應用,將AndroidManifest.xml中有關註冊廣播的信息解析出來,存儲至一個全局靜態變數當中。需要註意的是:

 1、PackageManagerService掃描目錄的順序如下:

  system/framework  ->  system/app  ->  vendor/app  ->  data/app  -> drm/app-private

 2、當處於同一目錄下時:按照file.list()的返回順序。(題外話:因為在data/app下的應用都是用戶安裝的,並且都是以com.xxx.xxx-1.apk 的形式出現,所以如果打算做手機管家之類的應用,需要好好的研究下包名,爭取在file.list()的獨木橋下搶的頭籌---優先接收開機啟動完成的廣播。)

 

    動態廣播接收的處理器是由ActivityManagerService負責,當APP的服務或者進程起來之後,執行了註冊廣播接收的代碼邏輯,即進行載入,最後會存儲在一個另外的全局靜態變數中。需要註意的是:

 1、 這個並非是一成不變的,當程式被殺死之後,已註冊的動態廣播接收器也會被移出全局變數,直到下次程式啟動,再進行動態廣播的註冊,當然這裡面的順序也已經變更了一次。

 2、這裡也並沒完整的進行廣播的排序,只記錄的註冊的先後順序,並未有結合優先順序的處理。

 

廣播發出的時候,廣播接收者接收的順序如下:

如果廣播為有序廣播,那麼會將動態廣播處理器和靜態廣播處理器合併在一起處理廣播的消息,最終確定廣播接收的順序:

1、優先順序高的先接收 2、同優先順序的動靜態廣播接收器,動態優先於靜態 3、同優先順序的動態廣播接收器或者同優先順序的靜態廣播接收器;分靜態:先掃描的大於後掃描的,動態:先註冊的大於後註冊的。   當廣播為普通廣播時,有如下的接收順序: 1、無視優先順序,動態廣播接收器優先於靜態廣播接收器 2、同優先順序的動態廣播接收器或者同優先順序的靜態廣播接收器;分靜態:先掃描的大於後掃描的,動態:先註冊的大於後註冊的。     作者:enjoy風鈴
出處:http://www.cnblogs.com/net168/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則下次不給你轉載了。

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

-Advertisement-
Play Games
更多相關文章
  • 本節教程將介紹如何用DeviceOne簡單而高效的完成一個新聞頁面。 導入項目 數據模板分離MVVM模型 自定義事件 展示新聞 九宮格展示 將要學習的demo效果圖如下所示 1. 導入完整項目 本節示例demo請參考下載地址,可以導入到設計器中學習。 為了方便大家理解頁面結構,請參考下圖圖中紅框所示 ...
  • 流程式控制制 順序、分支、迴圈 順序結構 代碼一行一行從上往下執行並解析 分支結構 if語句 switch語句 if語句 單分支 if(條件表達式){ //語句塊 } 含義:當條件表達式為真的時候就執行裡面的語句塊 示例: 雙分支: if(條件表達式){ //語句塊1 }else{ //語句塊2 } 含... ...
  • 問題引發:最近在整理DOM系列的一些知識點,發現在DOM的某些介面API中,存在一些我想不通的現象。就隨便舉個例子吧:DOM文檔模型中的文本節點,可以通過nodeValue或data屬性訪問文本節點的文本內容,而且在更新data的時候nodeValue也即時更新,反之亦然。不光是data或nodeV ...
  • 前些日子用到了eval()處理json數據,習慣於每次添加'('+json+')'處理數據,也沒去深究為什麼這麼做,剛好同事問我這個問題,瞬間啞口無言,只會如何操作,卻講不出原因,這不符合咱程式員嚴謹的工作態度,仔細思考了一會,簡略的談談吧。 可能會隨時腦洞,望各位見諒。 1.什麼是json? JS ...
  • document.write()和window.alert() 1、window.document.write(字元串或者是變數名) 作用:它會在body標簽內輸出內容 說明: window代表當前瀏覽器視窗 它是頂級對象 因為它是頂級對象可以省略不寫 document 代表當前文檔 它既是wind... ...
  • 作者:禪樓望月( http://www.cnblogs.com/yaoyinglong ) JavaScript里也可以像Java等面向對象的語言世界里創建自定義的類型,但是由於JavaScript中不支持使用class關鍵字來創建自定義的類型,因此我們只能另闢蹊徑……下麵我們一起來看在JavaSc ...
  • 一,代碼。 二,輸出。 ...
  • 最近研究了一下iOS的自動化編譯,目的是為了簡化測試和開發的同學溝通協調的次數,實現測試同學可以隨時從網頁操作編譯SVN最新源碼並打包ipa進行測試。 具體思路是通過從配置文件讀取需要編譯的項目配置列表展示在網頁上,測試同學選擇需要編譯的項目,確定後將選擇項目的相關參數傳入shell腳本運行,編譯完 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...