Broadcast廣播

廣播是android中各個組件之間的一種通訊方式,一般的使用場景是:
1)APP內,單個組件相同或不同線程之間通信;
2)APP內,不同組件之間的通信(單個進程);
3)不同APP之間的通信;
4)APP和系統時間的通信;
除了第一個不常用之外,其他3個都比較適用,第二個有EventBus,一種更好的處理方式。

從實現原理看上,Android中的廣播使用了觀察者模式,基於消息的發佈/訂閱事件模型。因此,從實現的角度來看,Android中的廣播將廣播的發送者和接受者極大程度上解耦,使得系統能夠方便集成,更易擴展。廣播發送者和廣播接收者的執行是異步的,發出去的廣播不會關心有無接收者接收,也不確定接收者到底是何時才能接收到。

具體的用法是創建類繼承BroadcastReceiver,並重寫其中的onReceive方法。因爲是四大組件之一,因此需要註冊。廣播的註冊方式有2種:
1.在manifest中註冊
application內,

<receiver
            android:name=".broadcast.MyReceiver"
            android:enabled="true"
            android:permission="string"
            android:process="string"                              android:exported="true"
>
 <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
</receiver>

使用的時候,直接在onReceive中判斷廣播種類,分類處理即可;其中需要注意的屬性:
android:exported ——此broadcastReceiver能否接收其他App的發出的廣播,這個屬性默認值有點意思,其默認值是由receiver中有無intent-filter決定的,如果有intent-filter,默認值爲true,否則爲false。(同樣的,activity/service中的此屬性默認值一樣遵循此規則)同時,需要注意的是,這個值的設定是以application或者application user id爲界的,而非進程爲界(一個應用中可能含有多個進程);
android:name —— 此broadcastReceiver類名;
android:permission ——如果設置,具有相應權限的廣播發送方發送的廣播才能被此broadcastReceiver所接收;
android:process ——broadcastReceiver運行所處的進程。默認爲app的進程。可以指定獨立的進程(Android四大基本組件都可以通過此屬性指定自己的獨立進程)
其中,intent-filter由於指定此廣播接收器將用於接收特定的廣播類型。本示例中給出的是用於接收網絡狀態改變或開啓啓動時系統自身所發出的廣播。當此App首次啓動時,系統會自動實例化MyBroadcastReceiver,並註冊到系統中。

2.在activity中動態註冊
一般在activity中創建廣播接受者後,在oncreate()方法中,

  myReceiver2=new MyReceiver2();
        IntentFilter filter=new IntentFilter();
        filter.addAction("com.wy.XXXXX");
        registerReceiver(myReceiver2,filter);

這種註冊方法需要在onDestroy()方法中註銷廣播:

 @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("vivi","onDestroy");
        unregisterReceiver(myReceiver2);
    }

發送廣播:
事實上,廣播的發送是以Intent形式實現的:

Intent intent = new Intent();
2 intent.setAction("com.wy.XXXXX");
3 intent.putExtra("aaa", "hello");
4 sendBroadcast(intent);

在onReceive方法中判斷廣播,從intent中取得相應數據。

注:在android3.1之前,靜態註冊的廣播即使APP進程結束,廣播接收者依然能工作,接收相應廣播。但是在3.1之後,這種情況有可能不在成立。
Android 3.1開始系統在Intent與廣播相關的flag增加了參數,分別是FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES。

FLAG_INCLUDE_STOPPED_PACKAGES:包含已經停止的包(停止:即包所在的進程已經退出)

FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已經停止的包。

自Android3.1開始,系統本身則增加了對所有app當前是否處於運行狀態的跟蹤。在發送廣播時,不管是什麼廣播類型,系統默認直接增加值爲FLAG_EXCLUDE_STOPPED_PACKAGES的flag,導致即使是靜態註冊的廣播接收器,對於其所在進程已經退出的app,同樣無法接收到廣播。
由此,對於系統廣播,由於是系統內部直接發出,無法更改此intent flag值,因此,3.1開始對於靜態註冊的接收系統廣播的BroadcastReceiver,如果App進程已經退出,將不能接收到廣播。

對於自定義的廣播,可以通過複寫此flag爲FLAG_INCLUDE_STOPPED_PACKAGES,使得靜態註冊的BroadcastReceiver,即使所在App進程已經退出,也能能接收到廣播,並會啓動應用進程,但此時的BroadcastReceiver是重新新建的。

 Intent intent = new Intent();
2 intent.setAction(BROADCAST_ACTION);
3 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
4 intent.putExtra("aaaa", "com.wy.xxxx");
5 sendBroadcast(intent);

一種替代方案:通過將Service與App本身設置成不同的進程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章