Android廣播的那些事兒

Android App可以接收來(lái)自系統(tǒng)和其他App的廣播消息入录,也可以向它們發(fā)送廣播消息,比較類似于“發(fā)布-訂閱”的設(shè)計(jì)模式佳镜,本文主要介紹廣播的類型僚稿,如何注冊(cè)廣播,如何發(fā)送廣播以及使用廣播需要注意的一些事兒蟀伸。

I. 廣播的分類

  1. 無(wú)序廣播
    沒(méi)有順序的廣播蚀同,廣播的接收方?jīng)]有嚴(yán)格的順序可言,不可中斷啊掏。

  2. 有序廣播
    在注冊(cè)時(shí)可指定優(yōu)先級(jí)蠢络,優(yōu)先級(jí)高的廣播接收者優(yōu)先收到廣播,優(yōu)先級(jí)以一個(gè)整數(shù)來(lái)標(biāo)識(shí)迟蜜,數(shù)值越大優(yōu)先級(jí)越高刹孔。可中斷娜睛,可再修飾髓霞。

  3. 粘滯廣播
    發(fā)出的廣播會(huì)滯留卦睹,注冊(cè)時(shí)間可晚于發(fā)送時(shí)間,其他功能與無(wú)序廣播相同方库。

II. 注冊(cè)廣播

編寫一個(gè)廣播接收者分预,通常是繼承BroadcastReceiver并重寫onReceive(Context,Intent)方法。

public class MyReceiver extends BroadcastReceiver {
    
    private static final String TAG = "MyReceiver";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: do somethings
        // 這個(gè)方法運(yùn)行在主線程下
        String action = intent.getAction();
        Log.d(TAG, "onReceive: " + action);
    }
}

編寫完廣播接收者后薪捍,就需要進(jìn)行注冊(cè)(訂閱)笼痹,告訴系統(tǒng)這個(gè)廣播接收者對(duì)哪些廣播感興趣。注冊(cè)的方式有靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè)兩種:

  • 在AndroidManifest.xml文件中聲明(靜態(tài)注冊(cè))
<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="jdqm.intent.action.TEST"/>
    </intent-filter>
</receiver>
  • 通過(guò)Java代碼注冊(cè)(動(dòng)態(tài)注冊(cè))
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.BOOT_COMPLETED");
intentFilter.addAction("jdqm.intent.action.TEST");
registerReceiver(myReceiver, intentFilter);

通過(guò)動(dòng)態(tài)注冊(cè)的廣播接收者酪穿,在宿主(注冊(cè)時(shí)所使用的Context)的生命周期期間都是有效的凳干。當(dāng)然你也可以在適當(dāng)?shù)臅r(shí)間調(diào)用unregisterReceiver(BroadcastReceiver)來(lái)解除注冊(cè),這個(gè)“適當(dāng)”取決于具體的業(yè)務(wù)需求被济。例如使用Activity的Context在onCreate(Bundle) 中注冊(cè)的一個(gè)廣播接收者救赐,可以在onDestory()方法回調(diào)時(shí)解除注冊(cè)來(lái)防止廣播接收者泄漏。原則:不重復(fù)注冊(cè)只磷,不泄露经磅。

以上注冊(cè)的廣播接收者對(duì) android.intent.action.BOOT_COMPLETED 和 jdqm.intent.action.TEST 這兩種action的廣播感興趣,后者是自定義的廣播钮追,前者是開機(jī)完成時(shí)由系統(tǒng)發(fā)出(通常自啟動(dòng)的應(yīng)用會(huì)注冊(cè)這個(gè)廣播)预厌,但注冊(cè)這個(gè)廣播須要以下權(quán)限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

III. 發(fā)送廣播

  1. 發(fā)送無(wú)序廣播
Intent intent = new Intent("jdqm.intent.action.TEST");
sendBroadcast(intent);
  1. 發(fā)送有序廣播
Intent intent = new Intent("jdqm.intent.action.TEST");
//第二個(gè)參數(shù)是權(quán)限
sendOrderedBroadcast(intent, null);
  1. 發(fā)送本地廣播
Intent intent = new Intent("jdqm.intent.action.TEST");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

本地廣播只有本應(yīng)用內(nèi)通過(guò)LocalBroadcastManager.getInstance(this).registerReceiver方法注冊(cè)的廣播接收者能收到,具有更高的安全性元媚,效率也更高(不用跨進(jìn)程通信)轧叽。

  1. 發(fā)送粘滯廣播
Intent intent = new Intent("jdqm.intent.action.TEST");
sendStickyBroadcast(intent);

這種類型廣播在Android6.0中已經(jīng)被標(biāo)記被過(guò)時(shí), 它有不安全(任何App都能訪問(wèn)), 沒(méi)有保護(hù) (任何App都能修改)等問(wèn)題刊棕。另外發(fā)送這種廣播需要以下權(quán)限

<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

IV. 接收順序

  1. 對(duì)于無(wú)序廣播炭晒,動(dòng)態(tài)注冊(cè)的廣播接收者會(huì)先收到,可以從源碼中得到理論支撐甥角。在BroadcastQueue類中有兩個(gè)集合
//存儲(chǔ)所有動(dòng)態(tài)注冊(cè)的無(wú)序廣播接受者
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();

//存儲(chǔ)所有靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè)的有序廣播接收者
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

然后在其processNextBroadcast(boolean fromMsg)方法中网严,首先是處理了mParallelBroadcasts集合。

  1. 對(duì)于有序廣播嗤无,優(yōu)先級(jí)高的接受者先收到震束,如果優(yōu)先級(jí)相同,順序就是不確定的翁巍。先收到的接收者可以調(diào)用abortBroadcast()來(lái)中斷此廣播驴一,后續(xù)優(yōu)先級(jí)較低的接受者將無(wú)法收到。除了中斷還可以調(diào)用setResultXxx()方法來(lái)往廣播添加數(shù)據(jù)灶壶,后續(xù)的接收者可以讀取這些數(shù)據(jù)肝断。

IV. 安全性與實(shí)踐

  1. 如果你的廣播不需要發(fā)送給本應(yīng)用以外的組件,使用LocalBroadcastManager來(lái)發(fā)送廣播,這樣安全性和效率都比較高

  2. 靜態(tài)注冊(cè)有可能造成大量的App啟動(dòng)胸懈,這將會(huì)影響系統(tǒng)的性能担扑,所以盡量使用動(dòng)態(tài)注冊(cè)來(lái)替代靜態(tài)注冊(cè)。這一點(diǎn)Android系統(tǒng)就做出了很好的示范趣钱,比如 CONNECTIVITY_ACTION 這個(gè)廣播只發(fā)送給動(dòng)態(tài)注冊(cè)的廣播接收者涌献。

  3. 不在廣播的Intent中包含敏感的信息,因?yàn)橹灰?cè)了這個(gè)廣播就能讀取到這些信息首有。你可以通過(guò)以下3中方式來(lái)獲得一定的安全性燕垃。

  • 通過(guò)使用權(quán)限來(lái)發(fā)送廣播,這樣只有聲明了該權(quán)限的應(yīng)用才能收到廣播井联。但是你很難確保你的權(quán)限不被泄漏卜壕。
  • Android4.0及以上版本,在發(fā)送廣播的時(shí)候可以通過(guò)setPackage來(lái)指定package(可以指定多個(gè))烙常,這樣只有匹配的package能接受到轴捎。
  • 使用LocalBroadcastManager來(lái)發(fā)送本地廣播。
  1. 當(dāng)你注冊(cè)了一個(gè)廣播蚕脏,意味著任何App都可以給你發(fā)送廣播侦副,以下有三點(diǎn)可以限制接收者:
  • 注冊(cè)的時(shí)候增加權(quán)限。
  • 在AndroidManifest.xml注冊(cè)receivers時(shí)驼鞭,將android:exported屬性設(shè)為false秦驯。
  • 使用LocalBroadcastManager來(lái)注冊(cè)。
  1. action的命名空間是全局的终议,這意味著action有可能會(huì)與其他App沖突汇竭,所以最好是有一個(gè)自己的命名空間葱蝗。

  2. 因?yàn)閺V播接收者是運(yùn)行在主線程穴张,它應(yīng)該快速地被執(zhí)行并且return,所以不要在onReveive方法中做比較耗時(shí)的操作两曼。

  3. 不要在廣播接收者中啟動(dòng)activitys皂甘,這違背了用戶的使用習(xí)慣,特別是不止一個(gè)接收者時(shí)悼凑。這種情況下可以考慮展示一個(gè)notification來(lái)替代偿枕。

V. 其他

  1. 系統(tǒng)廣播的action的完整列表在Android SDK下的 BROADCAST_ACTIONS.TXT,路徑為: Android/sdk/platforms/android-26/data/BROADCAST_ACTIONS.TXT

  2. Android3.1開始户辫,系統(tǒng)的package manager將記錄處于停止?fàn)顟B(tài)的應(yīng)用渐夸。默認(rèn)情況下,靜態(tài)注冊(cè)了廣播的處于“停止”狀態(tài)的應(yīng)用渔欢,是不會(huì)被啟動(dòng)的墓塌,即不會(huì)收到廣播。當(dāng)然你也可以為Intent指定flag來(lái)該變這個(gè)行為:

  • FLAG_INCLUDE_STOPPED_PACKAGES:包含處于“停止”狀態(tài)的應(yīng)用;
  • FLAG_EXCLUDE_STOPPED_PACKAGES:不包含處于“停止”狀態(tài)的應(yīng)用苫幢;

如果Intent不包含(或都包含)這兩個(gè)flag访诱,則表現(xiàn)形式是包含處于“停止”轉(zhuǎn)態(tài)的應(yīng)用,但是系統(tǒng)默認(rèn)添加了FLAG_EXCLUDE_STOPPED_PACKAGES這個(gè)flag韩肝,這一點(diǎn)在源碼中有所體現(xiàn):

ActivityManagerService#broadcastIntentLocked

final int broadcastIntentLocked(ProcessRecord callerApp,
    String callerPackage, Intent intent, String resolvedType,
    IIntentReceiver resultTo, int resultCode, String resultData,
    Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
    boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    
    intent = new Intent(intent);

    // By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    ...
}

這就意味著如果你想啟動(dòng)處于“停止”狀態(tài)的應(yīng)用触菜,必須添加FLAG_INCLUDE_STOPPED_PACKAGES這個(gè)flag。那么一個(gè)應(yīng)用在什么情況下會(huì)處于停止?fàn)顟B(tài)哀峻?①應(yīng)用首次安裝并且沒(méi)有啟動(dòng)過(guò)涡相;②被人為地強(qiáng)制停止。開機(jī)完成的廣播就是FLAG_EXCLUDE_STOPPED_PACKAGES這種類型的Intent剩蟀,這意味著如果你的應(yīng)用被停止了漾峡,開機(jī)自啟就會(huì)失效。下一篇文章將從源碼的角度來(lái)分析廣播的工作流程喻旷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末生逸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子且预,更是在濱河造成了極大的恐慌槽袄,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锋谐,死亡現(xiàn)場(chǎng)離奇詭異遍尺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)涮拗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門乾戏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人三热,你說(shuō)我怎么就攤上這事鼓择。” “怎么了就漾?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵呐能,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抑堡,道長(zhǎng)摆出,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任首妖,我火速辦了婚禮偎漫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘有缆。我一直安慰自己象踊,他們只是感情好舌仍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著通危,像睡著了一般铸豁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菊碟,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天节芥,我揣著相機(jī)與錄音,去河邊找鬼逆害。 笑死头镊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的魄幕。 我是一名探鬼主播相艇,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼纯陨!你這毒婦竟也來(lái)了坛芽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤翼抠,失蹤者是張志新(化名)和其女友劉穎咙轩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阴颖,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡活喊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了量愧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钾菊。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖偎肃,靈堂內(nèi)的尸體忽然破棺而出煞烫,到底是詐尸還是另有隱情,我是刑警寧澤软棺,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布红竭,位于F島的核電站,受9級(jí)特大地震影響喘落,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜最冰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一瘦棋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暖哨,春花似錦赌朋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赡若。三九已至,卻和暖如春团甲,著一層夾襖步出監(jiān)牢的瞬間逾冬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工躺苦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留身腻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親百新。 傳聞我的和親對(duì)象是個(gè)殘疾皇子互墓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 廣播接收器 是Android的四大組件之一,可見(jiàn)廣播在Android中的重要性渠旁; 1. 什么是廣播? 廣播(Bro...
    Lost_Robot閱讀 1,939評(píng)論 2 10
  • 諸多無(wú)奈,最近在改一個(gè)項(xiàng)目的bug的時(shí)候尤溜,腦子老是一片空白,可能是最近腦子不夠用汗唱,總之宫莱,好多東西忘了,閱讀一些別人...
    狗子王1948閱讀 7,707評(píng)論 6 53
  • 前言 本來(lái)想寫一下廣播的哩罪,發(fā)現(xiàn)查閱后有整理的不錯(cuò)的授霸,只好轉(zhuǎn)載圖個(gè)簡(jiǎn)便,日后好復(fù)習(xí)轉(zhuǎn)載:http://www.cnb...
    提升即效率閱讀 1,385評(píng)論 0 10
  • Android中的廣播 廣播接受器际插,可以比喻成收音機(jī)碘耳。而廣播則可以看成電臺(tái)。 Android系統(tǒng)內(nèi)部相當(dāng)于已經(jīng)有一...
    sunhaiyu閱讀 3,183評(píng)論 1 0
  • 第一次聽到《吳哥窟》這首歌時(shí),雖然聽不懂歌詞瑟枫,但是從曲子上聽斗搞,已經(jīng)能感覺(jué)酸澀。我認(rèn)認(rèn)真真學(xué)了這首歌...
    并不帥的昵稱閱讀 3,609評(píng)論 0 2