Broadcast Receiver總結


這是四大組件的第一篇(其他還沒整理好:) ),之前有個習慣,就是把一些筆記記在書上,但是隨著書越來越多,翻閱的時候比較麻煩,尤其是一段時間不用之后,想要翻閱某個知識點太費勁,這里就打算統一整理在一起,方便查看。

其中有很多內容參照了網上的博文,但是時間比較久,忘記出處了。另外就是參照Android developer的相關文檔,加上自己的理解,如果有錯誤,歡迎指出啊。

應用場景

  • 同一APP內部的同一組件內的消息通信(單個或多個線程之間)

  • 同一APP內部的不同組件間的消息通信(單個進程)

  • 同一APP內部的具有不同進程的多個組件間的消息通信(多個進程)

  • 不同APP組件間的消息通信(多個進程)

  • Android系統與APP之間的消息通信(系統廣播)

分類

1. 普通廣播

<pre>
public abstract void sendBroadcast (Intent intent, String receiverPermission)

public abstract void sendBroadcast (Intent intent)
</pre>
所有receiver都是無序的,各receiver往往同時運行。相對來說更為高效,但各receiver無法終止廣播或使用其他廣播執行的結果。

2. 有序廣播

<pre>
public abstract void sendOrderedBroadcast (Intent intent, String receiverPermission)

public abstract void sendOrderedBroadcast (Intent intent,
String receiverPermission,
BroadcastReceiver finalResultReceiver,
Handler scheduler,
int initialCode,
String initialData,
Bundle initialExtras)
</pre>

finalResultReceiver作為最末尾的receiver,可以得到前面一系列receiver的處理結果。通常應該提供自定義的receiver。

scheduler一般設為null,說明使用context的主線程。

initialCode一般設為RESULT_OK,作為resultCode的初始值。

initialData一般設為null。作為resultData的初始值。

initialExtras一般設為null,作為resultExtras的初始值。

通過Context.sendOrderedBroadcast發送,receiver會按照android:priority所指定的優先級由大到小依次執行(android:priority范圍為-1000~1000,數值越大優先級越高,默認優先級為0),由于是有序傳播,可以實現如下效果:

  • 終止傳播:通過調用abortBroadcast,之后的receiver將接收不到該廣播

  • 向后繼者傳遞數據:在onReceive中可以調用setResult、setResultCode、setResultData/setResultExtras設置信息,后繼者可以通過getResultCode、getResultData、getResultExtra來獲取信息。sendOrderedBroadcast中的參數initialCode、initialData、initialExtras提供了初始值。

注意:當靜態注冊與動態注冊使用了相同的優先級(priority)時,動態注冊的receiver處于更優先的位置。

安全方面的考慮

1. 隱患

  • 其他APP可能會針對性的發出與當前APP中intent-filter相匹配的廣播,導致當前APP不斷受到廣播并處理。

  • 其他APP可能注冊與當前APP一致的intent-filter用于接收廣播,從而截獲了廣播的具體信息

2. 措施

  • 如果receiver是用于同一APP內部的,則直接將其exported設為false

  • 在發送廣播時,使用含有permission的版本

  • 在動態注冊receiver時,使用含有permission的版本

  • 在靜態注冊receiver時,在xml中增加permission字段

  • 在發送廣播時,可以指定receiver的包名。通過intent.setPackage(packageName)

3. 更便捷的方式——使用LocalBroadcastManager

  • 獲取單例
    <pre>
    static LocalBroadcastManager getInstance(Context context);
    </pre>

  • 注冊
    <pre>
    void registerReceiver(BroadcastReceiver receiver, IntentFilter filter);
    </pre>

  • 注銷
    <pre>
    void unregisterReceiver(BroadcastReceiver receiver);
    </pre>

  • 發送廣播
    <pre>
    boolean sendBroadcast(Intent intent);
    </pre>

  • 發送廣播(同步發送,會阻塞直至所有相關receiver執行完畢onReceive并返回)
    <pre>
    void sendBroadcastSync(Intent intent);
    </pre>

注冊方式

1. 靜態注冊

通過xml文件的形式進行注冊,此種方式注冊的receiver會在APP運行期間一直存在,當APP被kill后就接收不到了。此種方式更為常用。

通過靜態注冊方式注冊的receiver,其onReceive(Context context, Intent intent)中的context為ReceiverRestrictedContext(Context含有的bindService和registerReceiver函數被禁用)

注意:當BroadcastReceiver作為內部類被實現,同時又使用了靜態注冊的方式,那么該內部類必須聲明為“public static

注意:從4.0開始,需要至少啟動一次APP后,靜態注冊的receiver才算注冊完畢

2. 動態注冊

通過代碼的方式進行注冊,BroadcastReceiver可實現為內部類或一般的外部類。

一般情況下,可以在onResume注冊receiver,在onPause中注銷receiver(少數情況下,也可以在onCreate中注冊,在onDestory中注銷)

通過動態注冊方式注冊的receiver,其onReceive(Context context, Intent intent)中的context為Activity的Context。

3. LocalBroadcastManager的動態注冊

如果廣播只是在APP內部進行收發,那么更高效和安全的方式是使用LocalBroadcastManager。這種方式只能夠進行動態注冊。

采用此種方式注冊的receiver,其onReceive(Context context, Intent intent)中的context為Application的Context。

生命周期

receiver的生命周期

receiver對象只有在onReceive的調用期間是有效的,是“活躍”的,一旦從onReceive中返回,那么系統將認為該對象已經結束,變為“不活躍”狀態。

任何需要異步的操作都不應該放在onReceive中,因為當異步操作結束時,receiver可能已經處于“不活躍”狀態,不能保證對象是否還存在。

注意:不能夠在onReceive中顯示對話框,可行的替代方案是使用NotificationManager相關功能。

注意:不能夠在onReceive中綁定服務(bindService),可行的替代方案是通過startService發送命令。

process的生命周期

正在執行receiver中onReceive的代碼的process被認為是“前臺進程”,它會一直保持運行(除非遇到非常極端的內存方面的壓力才會被kill,這一般不會出現)

一旦從onReceive中返回,receiver變為“不活躍”狀態,它所在的process的重要性將取決于運行在該process中的其他組件。如果這個process沒有其他組件在運行(比如一個APP,用戶近期沒有與之交互過),那么系統將認為這是一個“空process”,會在合適的時機kill掉它。

產生的問題:如果在onReceive中產生一個thread,然后返回,整個進程、包括新產生的thread,都不認定為“不活躍”的,存在被kill的危機。解決的方式是與service相結合,在onReceive中啟動一個Service,讓Service去做具體的工作,由于Service的存在,當前的process的重要性取決于Service的狀態,只要Service執行的工作未完成,它就一直是“活躍”的,就不會被kill。

其他注意事項

如果希望在receiver中的onReceive中開啟一個Activity,則必須增加FLAG_ACTIVITY_NEW_TASK標記。

onReceive必須在10秒鐘內執行完畢,否則會產生ANR(Application Not Response)。如確實需要進行耗時的操作,可以通過啟動一個Service的方式進行。

與廣播相關的Intent的FLAG:

<pre>
FLAG_EXCLUDE_STOPPED_PACKAGES (不再通知process被終止的receiver,默認行為)

FLAG_INCLUDE_STOPPED_PACKAGES (仍然通知process被終止的receiver)
</pre>

從3.1開始,如果靜態注冊的APP退出后,不一定能夠收到廣播。

因為3.1開始系統增加了對APP是否處于運行狀態的跟蹤。在發送廣播時,系統默認增加了FLAG_EXCLUDE_STOPPED_PACKAGES的flag,導致即使是靜態注冊的receiver,當其所在process退出后,同樣無法接收到廣播。

對于自定義的廣播,可以修改這種行為,使靜態注冊的receiver在process被結束后依然可以收到廣播,方法就是在intent中將FLAG_EXCLUDE_STOPPED_PACKAGES改寫為FLAG_INCLUDE_STOPPED_PACKAGES。

對于系統廣播,則無能為力了。

常見系統廣播

ACTION_TIME_TICK

當前時間變化,每分鐘廣播一次。只能使用Context.registerReceiver()動態注冊,靜態注冊無效。

值: "android.intent.action.TIME_TICK"

ACTION_TIME_CHANGED

系統時間被設置。

值: "android.intent.action.TIME_SET"

ACTION_TIMEZONE_CHANGED

時區被修改。帶有extra:time-zone

值: "android.intent.action.TIMEZONE_CHANGED"

ACTION_BOOT_COMPLETED

系統啟動完成。可用進行一些初始化工作,比如安裝alarm等。

權限:RECEIVE_BOOT_COMPLETED

值: "android.intent.action.BOOT_COMPLETED"

ACTION_PACKAGE_ADDED

新的APP被安裝。(新安裝的APP不會受到此廣播)

Data:新APP的包名

可能包含的Extras:

  • EXTRA_UID 新APP的UID.
  • EXTRA_REPLACING 是否是重裝或升級。如果這個廣播緊跟在ACTION_PACKAGE_REMOVED之后,并且作用的是同一個包,那么這個值為true

值: "android.intent.action.PACKAGE_ADDED"

ACTION_PACKAGE_CHANGED

已安裝的APP被改動,比如禁用或使能了某個組件。

Data: 包名

Extras:

  • EXTRA_UID 包的UID
  • EXTRA_CHANGED_COMPONENT_NAME_LIST 包含了被修改的組件的類名(或包名本身)
  • EXTRA_DONT_KILL_APP 布爾量,是否覆蓋重啟APP的默認action(待確認)

值: "android.intent.action.PACKAGE_CHANGED"

ACTION_PACKAGE_REMOVED

已安裝的APP被卸載。

Data:被卸載的APP的包名。

Extras:

  • EXTRA_UID 被卸載APP的uid
  • EXTRA_DATA_REMOVED 如果整個APP(包含代碼和數據)被卸載,其值被設為true
  • EXTRA_REPLACING 是否是重裝或升級。如果這個廣播后面緊跟著ACTION_PACKAGE_ADDED之后,并且作用的是同一個包,那么這個值為true

值: "android.intent.action.PACKAGE_REMOVED"

ACTION_PACKAGE_RESTARTED

用戶重啟了這個APP,它的所有process被kill,所有與它相關的運行時狀態被移除(包括process、alarm、notification等)。被重啟的APP收不到這個廣播。

Data:被重啟APP的包名

Extras:

  • EXTRA_UID 被重啟APP的uid

值: "android.intent.action.PACKAGE_RESTARTED"

ACTION_PACKAGE_DATA_CLEARED

用戶清空了APP的數據。這需要發生在ACTION_PACKAGE_RESTARTED之前。在擦除該APP所有持久化數據之后,本廣播被發出。被清空的APP收不到此廣播。

Data:被清空數據的APP的包名

Extras:

  • EXTRA_UID APP的uid

值: "android.intent.action.PACKAGE_DATA_CLEARED"

ACTION_UID_REMOVED

UID被從系統移除。UID被以EXTRA_UID為鍵存儲在extras中。

值: "android.intent.action.UID_REMOVED"

ACTION_BATTERY_CHANGED

粘性廣播被聲明為過時的,此處待驗證。

ACTION_POWER_CONNECTED

連接外部電源。

值: "android.intent.action.ACTION_POWER_CONNECTED"

ACTION_POWER_DISCONNECTED

外部電源被移除。

值: "android.intent.action.ACTION_POWER_DISCONNECTED"

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

推薦閱讀更多精彩內容