1. 程式人生 > 其它 >學習Android之廣播機制

學習Android之廣播機制

廣播機制簡介

 Android中的廣播機制十分靈活,每個應用程式都可以對自己感興趣的廣播進行註冊,這樣該程式就只會收到自己所關心的廣播內容,這些廣播可能是來自於系統的,也可能是來自於其他應用程式的。

 Android提供了一套完整的API,允許應用程式自由地傳送和接收廣播。

 傳送廣播可以藉助Intent,接收廣播則需要藉助BroadcastReceiver

 廣播的型別

 標準廣播和有序廣播。

 標準廣播:一種完全非同步執行的廣播,發出後,所有的BroadcastReceiver幾乎同時收到這條廣播訊息,沒有先後順序。效率高,但無法被截斷。

 有序廣播:一種非同步執行的廣播,發出後,同一時刻只能有一個BroadcastReceiver收到訊息,當這個BroadcastReceiver處理完後,廣播才能繼續傳遞下去,有先後順序。優先順序高的BroadcastReceiver會先收到廣播訊息。並且還可以截斷正在傳遞的廣播。

 接收系統廣播

 Android內建了很多系統級別的廣播,比如手機開機,電量變化等等。想要接收他們的廣播,就要用到BroadcastReceiver。

 動態註冊監聽時間變化

 註冊方法一般有兩種:在程式碼中註冊(動態註冊)和在AndroidManifest.xml中註冊(靜態註冊)。

 那麼如何建立一個BroadcastReceiver呢?

 只需要新建一個類,繼承自BroadcastReceiver,並重寫父類的onReceive()方法即可。當有廣播來時,onReceive()方法就會執行。

 例子:動態註冊一個監聽時間變化的程式。

 在MainActivity中定義了一個內部類TimeChangeReceiver,繼承自BroadcastReceiver,重寫了onReceive()方法。

    inner class TimeChangeReceiver : BroadcastReceiver() {
        override fun onReceive(p0: Context?, p1: Intent?) {
            TODO("Not yet implemented")
        }
    }

 

 在onCreate()方法,先建立一個IntentFilter的例項,給它新增一個值為android.intent.action.TIME_TICK的action。因為系統時間發生變化時,系統發出的正是一條值為android.intent.action.TIME_TICK的廣播。也就是說,想要監聽什麼廣播,就在這裡新增相應的action。

 接下來建立一個TimeChangeReceiver的例項,然後呼叫registerReceiver()方法進行註冊,將TimeChangeReceiver的例項和IntentFilter的例項都傳了進去,這樣TimeChangeReceiver就會收到所有值為android.intent.action.TIME_TICK的廣播,也就實現了監聽系統時間變化的功能。

        val intentFilter = IntentFilter()
        intentFilter.addAction("android.intent.action.TIME_TICK")
        timeChangeReceiver = TimeChangeReceiver()
        registerReceiver(timeChangeReceiver,intentFilter)

 

 這裡需要將timeChangeReceiver宣告為全域性變數,需要用到延遲初始化:

lateinit var  timeChangeReceiver: TimeChangeReceiver

 

 最後記得,動態註冊的BroadcastReceiver一定要取消註冊才行,在onDestory()中呼叫unregisterReceiver()方法即可。

unregisterReceiver(timeChangeReceiver)

 

 最後執行程式,系統每隔一分鐘就會發出一條android.intent.action.TIME_TICK的廣播。

 

 想要檢視完整的系統廣播列表,前往如下路徑:

 <Android SDK>/platforms/<任意android api版本>/data/broadcast_actions.txt

 

 靜態註冊實現開機啟動

 動態註冊的可以自由地控制註冊與登出,在靈活性方面有很大的優勢。但是有一個缺點就是必須在程式啟動之後才能接收廣播。因為實在onCreate()中註冊的。

 靜態註冊則能實現程式未啟動的情況下也能接收廣播。(簡述一下原理,在安裝應用的時候,系統會啟動PackageManagerService管理服務,這個服務對AndroidManifest進行解析,從而得到應用程式的相關資訊,比如service,activity,Broadcast等等。)

 實現開機廣播的action值為android.intent.action.BOOT_COMPLETED。

 首先我們需要新建一個廣播類,可以通過New->Other->Broadcast新建。新建時有兩個屬性:Exported屬性表示是否允許這個BroadcastReceiver接收本程式以外的廣播,Enabled屬性表示是否啟用這個BroadcastReceiver。都勾選上。

 然後在onReceive()中編寫邏輯即可。

 另外,靜態的BroadcastReceiver需要在AndroidManifest.xml檔案中註冊。不過新建時自動註冊了。

        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true"></receiver>

 

 同時,需要在<receiver>標籤中添加了一個<intent-filter>標籤,在裡面宣告相應的action。

        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

最後再進行許可權宣告。

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

 

 傳送自定義廣播

 傳送標準廣播

 1. 建立廣播接收者:在傳送廣播之前,需要先定義一個BroadcastReceiver來準備接收此廣播。新建一個MyBroadcastReceiver,並在onReceive()方法中編寫邏輯。

 2. 新增廣播接收者需要接收的action:在AndroidManifest對這個BroadcastReceiver修改。將action設為com.example.broadcasttest.MY_BROADCAST。所以等會就會發送這樣一條廣播。

 3. 傳送廣播:在MainActivity中的新增按鈕點選事件,裡面編寫廣播發送程式碼。

        val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
        intent.setPackage(packageName)
        sendBroadcast(intent)

 

 為什麼會用到setPackage()方法:在Android 8.0系統之後,靜態註冊的BroadcastReceiver是無法接收隱式廣播的,而預設情況下我們發出的自定義廣播恰恰都是隱式廣播。因此這裡一定要呼叫setPackage()方法,指定這條廣播是傳送給哪個應用程式的,從而讓它變成一條顯式廣播,否則靜態註冊的BroadcastReceiver將無法接收到這條廣播。

 

 傳送有序廣播

 有序廣播是可以被截斷的。傳送有序廣播只需要改動一行程式碼。

sendOrderedBroadcast(intent,null)

 

 此方法接收兩個引數:第一個Intent,第二個是一個與許可權相關的字串,這裡傳入null就行了。

 這個時候的BroadcastReceiver是有先後順序的,而且前面的BroadcastReceiver還可以將廣播截斷,以阻止其繼續傳播。

 設定先後順序是在註冊的時候進行設定,修改AndroidManifest.xml中的程式碼,如下所示:

<intent-filter android:priority="1">
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>

 

 通過android:priority屬性設定優先順序,值越大優先順序越高。

 然後在onReceive()方法中呼叫abortBroadcast()方法,表示將這條廣播截斷,後面的BroadcastReceiver將無法再接收到這條廣播。

    override fun onReceive(context: Context, intent: Intent) {
        TODO("BootCompleteReceiver.onReceive() is not implemented")
        abortBroadcast()
    }