BoradcastReceiver基礎(chǔ)

BoradcastReceiver

BroadcastReceiver的簡(jiǎn)介

BroadcastReceiver翻譯為廣播接收者,Broadcast是一種廣泛運(yùn)用在應(yīng)用程序之間的傳輸信息的機(jī)制,簡(jiǎn)單的可以理解為傳統(tǒng)意義上的電臺(tái)廣播稻爬,通俗一點(diǎn)蒿秦,發(fā)布失物招領(lǐng)

廣播機(jī)制是一個(gè)典型的發(fā)布—訂閱模式粉渠,也就是我們所說(shuō)的觀察者模式菱涤。廣播最大的特點(diǎn)就是發(fā)送方并不關(guān)心接收方是否接到數(shù)據(jù)绸栅,也不關(guān)心接收方是如何處理數(shù)據(jù)的海诲,通過(guò)這樣的形式來(lái)達(dá)到接繁莹、收雙方的完全解耦合

普通廣播(自定義廣播)

普通廣播是完全異步的,通過(guò)Context的sendBroadcast()方法來(lái)發(fā)送特幔,消息傳遞效率比較高咨演,但所有receivers(接收器)的執(zhí)行順序不確定。缺點(diǎn)是:接收者不能將處理結(jié)果傳遞給下一個(gè)接收者蚯斯,并且無(wú)法終止廣播Intent的傳播薄风,直到?jīng)]有與之匹配的廣播接收器為止饵较。下面以自定義的普通廣播進(jìn)行演示

  1. 創(chuàng)建廣播

創(chuàng)建廣播非常簡(jiǎn)單,只要繼承BroadcastReceiver并實(shí)現(xiàn)onReceive()方法

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiver", Toast.LENGTH_LONG).show();
    }
}
  1. 注冊(cè)廣播

BroadcastReceiver是四大組件之一遭赂,所以毫不疑問(wèn)需要注冊(cè)循诉,BroadcastReceiver的注冊(cè)有兩種方法:

  • 通過(guò)manifests配置
  • 通過(guò)代碼動(dòng)態(tài)配置

靜態(tài)注冊(cè)是系統(tǒng)級(jí)注冊(cè),只要安裝了應(yīng)用撇他,無(wú)需打開(kāi)茄猫,就能接受到廣播,原生系統(tǒng)可以通過(guò)這個(gè)方法相互喚醒困肩。但是國(guó)產(chǎn)ROM無(wú)法做到這一點(diǎn)

方法一:通過(guò)manifests配置
<receiver android:name=".BroadcastReceiver.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="com.handsome.hensen" />
    </intent-filter>
</receiver>

這里需要加入intent-filter的action中的name屬性划纽,表示我們監(jiān)聽(tīng)的內(nèi)容。當(dāng)有廣播發(fā)送時(shí)锌畸,需要判斷該廣播是否和我們監(jiān)聽(tīng)的內(nèi)容一致勇劣,如果一致則接收

方法二:通過(guò)代碼動(dòng)態(tài)配置
//創(chuàng)建廣播
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
//注冊(cè)廣播
registerReceiver(receiver, new IntentFilter("com.qinqin"));
  1. 反注冊(cè)廣播

BroadcastReceiver必須遵循生到死的周期,如果你是使用動(dòng)態(tài)注冊(cè)廣播的則需要在Activity的onDestroy的時(shí)候反注冊(cè)廣播

  1. 發(fā)送廣播

這里我們以一個(gè)按鈕來(lái)發(fā)送廣播潭枣,通過(guò)sendBroadcast()方法發(fā)送我們的創(chuàng)建的Intent自定義廣播

final Intent intent = new Intent();
//廣播內(nèi)容
intent.setAction("com.qinqin");

bt_send.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       sendBroadcast(intent);
   }
});
  1. 運(yùn)行代碼

運(yùn)行程序后比默,我們點(diǎn)擊發(fā)送廣播。

有序廣播

有序廣播通過(guò)Context.sendOrderedBroadcast()來(lái)發(fā)送盆犁,所有的廣播接收器優(yōu)先級(jí)依次執(zhí)行命咐,廣播接收器的優(yōu)先級(jí)通過(guò)receiver的intent-filter中的Android:priority屬性來(lái)設(shè)置,數(shù)值越大優(yōu)先級(jí)越高蚣抗。

當(dāng)廣播接收器接收到廣播后侈百,可以使用setResult()函數(shù)來(lái)結(jié)果傳給下一個(gè)廣播接收器接收,然后通過(guò)getResult()函數(shù)來(lái)取得上個(gè)廣播接收器接收返回的結(jié)果翰铡。當(dāng)廣播接收器接收到廣播后钝域,也可以用abortBroadcast()函數(shù)來(lái)讓系統(tǒng)攔截下來(lái)該廣播,并將該廣播丟棄锭魔,使該廣播不再傳送到別的廣播接收器接收例证。

  1. 創(chuàng)建廣播

我們創(chuàng)建一個(gè)類,存放三個(gè)有優(yōu)先級(jí)的廣播接收者迷捧,并在最高級(jí)廣播中傳遞結(jié)果到下一個(gè)廣播

public class PriorityBroadcastReceiver {

    public static class HighPriority extends BroadcastReceiver {
        //高級(jí)廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("receive", "High");
            //傳遞結(jié)果到下一個(gè)廣播接收器
            int code = 0;
            String data = "hello";
            Bundle bundle = null;
            setResult(code, data, bundle);
        }
    }

    public static class MidPriority extends BroadcastReceiver {
        //中級(jí)廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("receive", "Mid");
            //獲取上一個(gè)廣播接收器結(jié)果
            int code = getResultCode();
            String data = getResultData();
            Log.e("receive", "獲取到上一個(gè)廣播接收器結(jié)果:" + "code=" + code + "data=" + data);
        }
    }

    public static class LowPriority extends BroadcastReceiver {
        //低級(jí)廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("receive", "Low");
        }
    }
}
  1. 注冊(cè)廣播

這里的注冊(cè)方式和普通廣播是一樣的织咧,這里的區(qū)別在于priority屬性,確定了他們之間的優(yōu)先級(jí)

<receiver android:name=".PriorityBroadcastReceiver$HighPriority">
            <intent-filter android:priority="3000">
                <action android:name="com.qinqin" />
            </intent-filter>
        </receiver>
        <receiver android:name=".PriorityBroadcastReceiver$MidPriority">
            <intent-filter android:priority="2000">
                <action android:name="com.qinqin" />
            </intent-filter>
        </receiver>
        <receiver android:name=".PriorityBroadcastReceiver$LowPriority">
            <intent-filter android:priority="1000">
                <action android:name="com.qinqin" />
            </intent-filter>
        </receiver>

要注意的是:BroadcastReceiver類名與內(nèi)部類的名字之間用$符號(hào)隔開(kāi)漠秋,否則會(huì)報(bào)錯(cuò)

  1. 發(fā)送廣播

和之前的不一樣的地方笙蒙,這里是使用sendOrderedBroadcast()發(fā)送有序廣播

final Intent intent = new Intent();
intent.setAction("com.qinqin");

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        sendOrderedBroadcast(intent,null);
    }
});

要注意的是:這里需要發(fā)送的是有序廣播,否則在接收者中通過(guò)setResult()和getResult()方法會(huì)報(bào)錯(cuò)庆锦,因?yàn)橹挥杏行驈V播才能傳遞結(jié)果

  1. 運(yùn)行代碼
    運(yùn)行程序后捅位,我們點(diǎn)擊發(fā)送廣播。我們以Log信息來(lái)驗(yàn)證發(fā)出的廣播被我們準(zhǔn)確的接收,數(shù)據(jù)被我們準(zhǔn)確的傳遞
02-27 02:44:24.707 7195-7195/com.example.user.a2017_2_27 E/receive: High
02-27 02:44:24.729 7195-7195/com.example.user.a2017_2_27 E/receive: Mid
02-27 02:44:24.729 7195-7195/com.example.user.a2017_2_27 E/receive: 獲取到上一個(gè)廣播接收器結(jié)果:code=0data=hello
02-27 02:44:24.730 7195-7195/com.example.user.a2017_2_27 E/receive: Low

攔截廣播

上面我們提到過(guò)有序廣播中可以攔截廣播艇搀,那么我們?cè)谏厦娉绦虻幕A(chǔ)上修改代碼尿扯,在HighPriority接收器中加上攔截廣播

  1. 創(chuàng)建廣播

通過(guò)在BroadcastReceiver中,執(zhí)行abortBroadcast()方法焰雕,廣播就不會(huì)繼續(xù)往下傳遞了

public static class HighPriority extends BroadcastReceiver {
        //高級(jí)廣播接收者
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("receive", "High");
            //攔截廣播
            abortBroadcast();
            //傳遞結(jié)果到下一個(gè)廣播接收器
            int code = 0;
            String data = "hello";
            Bundle bundle = null;
            setResult(code, data, bundle);
        }
    }
  1. 運(yùn)行代碼

運(yùn)行程序后衷笋,我們點(diǎn)擊發(fā)送廣播。我們以Log信息來(lái)驗(yàn)證我們攔截了廣播

02-27 02:48:44.112 7195-7195/com.example.user.a2017_2_27 E/receive: High

可以看到矩屁,后面的Mid和Low廣播都沒(méi)有Log信息辟宗,說(shuō)明我們攔截成功了

有序廣播、攔截廣播的拓展——終結(jié)廣播

現(xiàn)在有這樣的一個(gè)應(yīng)用場(chǎng)景档插,按照上面的程序走慢蜓,只能在第一個(gè)廣播中被攔截住了,后面的廣播則不執(zhí)行郭膛。如果這個(gè)時(shí)候我們需要一個(gè)不管有沒(méi)有被攔截都必須執(zhí)行的廣播,我們稱為終結(jié)廣播氛悬,那應(yīng)該怎么辦则剃。同樣的,發(fā)送有序廣播也考慮到這一點(diǎn)如捅,通過(guò)以下代碼來(lái)發(fā)送廣播棍现,并指定我們不管有沒(méi)有被攔截都必須執(zhí)行的終結(jié)廣播

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        sendOrderedBroadcast(intent, null, new PriorityBroadcastReceiver.LowPriority(),
                new Handler(), 0, null, null);
    }
});

運(yùn)行代碼,我們查看Log信息

02-27 02:54:37.152 7195-7195/com.example.user.a2017_2_27 E/receive: High
02-27 02:54:37.168 7195-7195/com.example.user.a2017_2_27 E/receive: Low

本地廣播

在API21的Support v4包中新增本地廣播镜遣,也就是LocalBroadcastManager己肮。由于之前的廣播都是全局的,所有應(yīng)用程序都可以接收到悲关,這樣就會(huì)帶來(lái)安全隱患谎僻,所以我們使用LocalBroadcastManager只發(fā)送給自己應(yīng)用內(nèi)的信息廣播,限制在進(jìn)程內(nèi)使用

它的用法很簡(jiǎn)單寓辱,只需要把調(diào)用context的sendBroadcast艘绍、registerReceiver、unregisterReceiver的地方換為L(zhǎng)ocalBroadcastManager.getInstance(Context context)中對(duì)應(yīng)的函數(shù)即可秫筏。這里創(chuàng)建廣播的過(guò)程和普通廣播是一樣的過(guò)程诱鞠,這里就不過(guò)多介紹了

  1. 注冊(cè)Receiver
 //創(chuàng)建廣播
receiver = new MyBroadcastReceiver();
//注冊(cè)本地廣播
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
        new IntentFilter("com.qinqin"));
  1. 反注冊(cè)Receiver
LocalBroadcastManager.getInstance(ReceiverActivity.this).unregisterReceiver(receiver);
  1. 發(fā)送異步廣播
final Intent intent = new Intent();
intent.setAction("com.qinqin");
LocalBroadcastManager.getInstance(ReceiverActivity.this).sendBroadcast(intent);
  1. 發(fā)送同步廣播
LocalBroadcastManager.getInstance(ReceiverActivity.this).sendBroadcastSync(intent);

Sticky廣播

sticky廣播通過(guò)Context.sendStickyBroadcast()函數(shù)來(lái)發(fā)送,用此函數(shù)發(fā)送的廣播會(huì)一直滯留这敬,當(dāng)有匹配此廣播的廣播接收器被注冊(cè)后航夺,該廣播接收器就會(huì)收到此條信息。使用此函數(shù)需要發(fā)送廣播時(shí)崔涂,需要獲得BROADCAST_STICKY權(quán)限

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

sendStickyBroadcast只保留最后一條廣播阳掐,并且一直保留下去,這樣即使已經(jīng)有廣播接收器處理了該廣播,當(dāng)再有匹配的廣播接收器被注冊(cè)時(shí)锚烦,此廣播仍會(huì)被接收觅闽。如果你只想處理一遍該廣播,可以通過(guò)removeStickyBroadcast()函數(shù)來(lái)實(shí)現(xiàn)涮俄。這里創(chuàng)建廣播的過(guò)程和普通廣播是一樣的過(guò)程蛉拙,這里就不過(guò)多介紹了

系統(tǒng)廣播

當(dāng)然系統(tǒng)中也會(huì)有很多自帶的廣播,當(dāng)符合一定條件時(shí)彻亲,系統(tǒng)會(huì)發(fā)送一些定義好的廣播孕锄,比如:重啟、充電苞尝、來(lái)電電話等等畸肆。我們可以通過(guò)action屬性來(lái)監(jiān)聽(tīng)我們的系統(tǒng)廣播

<receiver android:name=".BroadcastReceiver.MyBroadcastReceiver">
    <intent-filter>
        <!--重啟設(shè)備-->
        <action android:name="android.intent.action.REBOOT" />
    </intent-filter>
</receiver>

這里創(chuàng)建廣播的過(guò)程和普通廣播是一樣的過(guò)程,這里就不過(guò)多介紹了宙址。常用的廣播action屬性有

  • 屏幕被關(guān)閉之后的廣播:Intent.ACTION_SCREEN_OFF
  • 屏幕被打開(kāi)之后的廣播:Intent.ACTION_SCREEN_ON
  • 充電狀態(tài)轴脐,或者電池的電量發(fā)生變化:Intent.ACTION_BATTERY_CHANGED
  • 關(guān)閉或打開(kāi)飛行模式時(shí)的廣播:Intent.ACTION_AIRPLANE_MODE_CHANGED
  • 表示電池電量低:Intent.ACTION_BATTERY_LOW
  • 表示電池電量充足,即電池電量飽滿時(shí)會(huì)發(fā)出廣播:Intent.ACTION_BATTERY_OKAY
  • 按下照相時(shí)的拍照按鍵(硬件按鍵)時(shí)發(fā)出的廣播:Intent.ACTION_CAMERA_BUTTON
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抡砂,一起剝皮案震驚了整個(gè)濱河市大咱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌注益,老刑警劉巖碴巾,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丑搔,居然都是意外死亡厦瓢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門啤月,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)煮仇,“玉大人,你說(shuō)我怎么就攤上這事顽冶∑劭梗” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵强重,是天一觀的道長(zhǎng)绞呈。 經(jīng)常有香客問(wèn)我,道長(zhǎng)间景,這世上最難降的妖魔是什么佃声? 我笑而不...
    開(kāi)封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮倘要,結(jié)果婚禮上圾亏,老公的妹妹穿的比我還像新娘十拣。我一直安慰自己,他們只是感情好志鹃,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布夭问。 她就那樣靜靜地躺著,像睡著了一般曹铃。 火紅的嫁衣襯著肌膚如雪缰趋。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天陕见,我揣著相機(jī)與錄音秘血,去河邊找鬼。 笑死评甜,一個(gè)胖子當(dāng)著我的面吹牛灰粮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忍坷,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼粘舟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了承匣?” 一聲冷哼從身側(cè)響起蓖乘,我...
    開(kāi)封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎韧骗,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體零聚,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡袍暴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隶症。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片政模。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蚂会,靈堂內(nèi)的尸體忽然破棺而出淋样,到底是詐尸還是另有隱情,我是刑警寧澤胁住,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布趁猴,位于F島的核電站,受9級(jí)特大地震影響彪见,放射性物質(zhì)發(fā)生泄漏儡司。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一余指、第九天 我趴在偏房一處隱蔽的房頂上張望捕犬。 院中可真熱鬧,春花似錦、人聲如沸碉碉。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)垢粮。三九已至贴届,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間足丢,已是汗流浹背粱腻。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斩跌,地道東北人绍些。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像耀鸦,于是被迫代替她去往敵國(guó)和親柬批。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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