Android 廣播內容全知道

版權聲明:

本賬號發布文章均來自公眾號,承香墨影(cxmyDev),版權歸承香墨影所有。

未經允許,不得轉載。

一、前言

Broadcast 是 Android 四大組件之一,與傳統意義上的電臺廣播類似,一個廣播需要有一個發布者,以及任意多個接收者,并且它的特點也非常的明顯,發布者只負責將廣播發布出去,而不去關心接收者是否能正常接收到廣播內容,也不關心接收者是如何處理廣播的。以這種形式來達到發送者和接收者完全的解耦。

Broadcast 可以被大致分為三個角色:發送者、接收者(BroadcastReceiver)以及承載 Broadcast 的 Intent 對象。接下來就這三個角色進行單獨講解。

二、Broadcast 的類型

在 Android 中,為了適應不同的場景,Broadcast 可以被分為:

  • 無序廣播。
  • 有序廣播。
  • 本地廣播。
  • Sticky 廣播。

先來看看對于不同類型廣播的特點。

1、無序廣播

無序廣播是完全異步的,通過 Context.sendBroadcast() 方法來發送,從效率上來看,還算是比較高的。

sendBroadcast() 方法中,還有一個第二個參數為 String 類型的重載方法,它是用來設定接收者的權限的,這個權限可以是系統權限,也可以是自定義的權限。

但是正如它的名稱一樣,無序廣播對所有廣播接收者(Receivers)而言,是無序的,也就是說,所有接收者無法確定接收時序的順序,這樣也導致了,無序廣播無法被停止。當它被發送出去之后,它將通知所有這條廣播的接收者,直到沒有與之匹配的廣播接收者為止。

2、有序廣播

有序廣播通過 Context.sendOrderedBroadcast() 方法來發送。有序廣播和無序廣播最大的不同,就是它可以允許接收者設定優先級,它會按照接收者設定的優先級依次傳播。而高優先級的接收者,可以對廣播的數據進行處理或者停止掉此條廣播的繼續傳播。

想要設定有序廣播的優先級,需要在 IntentFilter 中進行設定。在 AndroidManifest.xml 中,使用 android:priority 屬性設置,在代碼中,可以通過 IntentFilter.setPriority() 方法設定。這取決于 Broadcast 的注冊方式。

可以看到,它的取值是有限定范圍的,需要在 SYSTEM_LOW_PRIORITY 和 SYSTEM_HIGH_PRIORITY 之間。

可以看到,這樣的 priority 的限定范圍,就是在 -1000 ~ 1000 之間,而如果不對其進行設定,它的默認值為 0。

前面也提到,高優先級的接收者可以附加數據以及停止當前廣播的傳播。附加數據,可以通過 setResult() 方法來操作,同時也可以通過 getResult() 方法來獲取比自己更高優先級的接收者設置的數據內容。而停止這條廣播繼續傳播,可以調用 abortBroadcast() 方法。

3、Sticky廣播

Sticky 廣播和它的名字很像,它是一個具有粘性的廣播。它被發出去之后,會一直滯留在系統中,直到有與之匹配的接收者,才會將其發出去。

Sticky 廣播,使用 Context.sendStickyBroadcast() 方法進行發送廣播。

從文檔上可以看到,如果想要發送一個 Sticky 廣播,需要具有 BROADCAST_STICKY 權限,這個可以在 AndroidManifest.xml 中進行注冊,而如果沒有此權限,則會拋出 SecurityException 異常。

對于系統而言,只會保留最后一條 Sticky 廣播,并且會一直保留下去,也就是說,如果我們發送的 Sticky 廣播不被取消,當有一個接收者的時候就會收到它,再來一個還是能收到。所有我們需要在合適的實際,調用 removeStickyBoradcast() 方法,將其取消掉。

從上面的方法文檔中也可以看到 StickyBroadcast 已經被標記為 @Deprecated ,出于一些安全的考慮,已經將其標記為廢棄,不再推薦使用。我們作為開發者,對于一些被標記為 @Depracated 的方法,使用起來還是需要謹慎的。

4、本地廣播

前面介紹的廣播,都是全局的,只要被發出去之后,所有注冊了此廣播的 App ,都可以接受到它,這樣就帶來了安全的隱患。而有時候,我們只是想讓自己的 App 進程內使用,而無需將廣播公布出去。那么就可以使用本地廣播。

本地廣播是 Android Support v4 : 21 版本才新增的廣播類型,它使用 LocalBroadcastManager (以下簡稱 LBM)類來管理。

LocalBroadcast 的使用非常的簡單,只需要將 Broadcast 的對應 API,替換為 LBM 為我們提供的 API 即可。

LBM 是一個單例對象,可以使用 LocalBroadcastManager.getInstance(Context ) 方法獲取到。在 Context 中定義的和 Broadcast 相關的方法,在 LBM 中都有對應的 API 。非常有意思的是,LBM 為了區分異步和同步,使用了 sendBroadcast()sendBroadcastSync() 方法來做為區分。

三、注冊廣播接收者方式

在 Android 中 ,Broadcast 有兩種注冊方式:

  • AndroidManifest.xml 靜態注冊。
  • 代碼中動態注冊。

1、靜態注冊

在 AndroidManifest.xml 靜態注冊,是一種非常常用的注冊方式。


這里注冊了一個監聽輸入法改變的系統廣播的 BroadcastReceiver。

2、動態注冊

有一些情況下,我們因為一些限制,會需要使用到動態注冊監聽。

Context 中,為我們提供了動態注冊廣播接收者對應的 api。


這幾行代碼和上面靜態注冊的效果是一樣的。但是既然是動態注冊,可以在需要的時候進行廣播接收者的注冊,那么在不需要的時候就需要對其進行取消。

動態取消廣播接收者的注冊,需要使用 Context.unregisterReceiver() 方法,它需要一個 BroadcastReceiver 對象作為參數,這就是我們之前用于注冊的 Receiver 對象。

3、動態注冊和靜態注冊有什么區別?

理論上來說上來說,無論是使用靜態注冊,還是動態注冊,當這個廣播接收者被注冊上之后,他們的后續操作是一樣的。但是它們的注冊時機卻不同。

對于靜態注冊的接收者而言,實際上它在安裝到設備中之后,就已經被注冊上了,只要有與它匹配的廣播被發出來,它就是可以被激活并處理廣播的,而對于動態注冊,只有當前 App 被啟動,并且執行到 registerReceiver() 方法之后,才會完成注冊,才能接收匹配的廣播。

既然如此,Android 為了一些效率和安全的原因,規定一些系統廣播無法被靜態注冊,例如:SCREEN_ON、SCREEN_OFF、TIME_TICK 等,這種觸發頻率比較高的系統廣播。這些廣播只允許動態注冊,使用靜態注冊的方式雖然不會報錯,但是也不會有效。

4、BroadcastReceiver

無論是使用那種注冊方式,我們都需要有一個 BroadcastReceiver 對象,它是用于實際去處理廣播的對象,它是一個抽象類,需要實現其內的方法 onReceive()。


使用 BroadcastReceiver 就可以接受到與之匹配的廣播,廣播是通過 IntentFilter 為過濾條件來匹配的,我們可以通過 onReceiver() 方法中的 intent 對象,來獲取到接收到的廣播的相關數據。

四、查缺補漏

到這里,基本上 Broadcast 的相關內容就講解清楚了。但是實際使用中,有時候還是會碰到問題,這里單獨用一個小結來分析碰到的問題,有新的問題會持續更新。

1、被停止的 App 無法接收 Broadcast

對于 Broadcast 的 api ,在 Android api level 11 (Android 3.1)之后有過調整。新增了兩個 FLAG,用來控制 Broadcast 是否對處于停止狀態的 App 起作用。

這兩個 FLAG 為:

  • FLAG_INCLUDE_STOPPED_PACKAGES:表示包含未啟動的 App。
  • FLAG_EXCLUDE_STOPPED_PACKAGES:表示不包含未啟動的 App。

而加了這兩個 flag 的版本之后,系統會默認向所有 Broadcast 的 Intent 增加 FLAG_EXCLUDE_STOPPED_PACKAGES 這個 flag,這樣做是為了防止喚醒已經被停止的 App 來處理這個廣播,這樣可以節約很多不必要的資源浪費。可以看到 ,Android 為了優化效率,一直是在做努力的,在 最新的 Android O 上也做了大的優化。

而這樣導致如果 App 處于停止的狀態下,默認就不會接收到廣播的。那么有沒有辦法解決這個問題?如果廣播的發送方我們可以控制,只需要為廣播增加 FLAG_INCLUDE_STOPPED_PACKAGES 即可,如果沒發控制,暫時也沒什么好的辦法讓被停止的 App 接收到這部分廣播。

那么,我們還需要確定,什么情況下,App 會處于停止狀態,現在能確定的就是兩種狀態:

  • 首次安裝未啟動過。
  • 在任務管理器中,被『強行停止』后。

當然不排除有一些管理軟件會模擬『強行停止』的動作。

公眾號二維碼.jpg
公眾號二維碼.jpg
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容