Android初試--Android中的BroadcastReceiver(2)
如果有多個接收者都註冊了相同的廣播地址,又會是什麼情況呢,能同時接收到同一條廣播嗎,相互之間會不會有干擾呢?這就涉及到普通廣播和有序廣播的概念了。
普通廣播(Normal Broadcast)
普通廣播對於多個接收者來說是完全非同步的,通常每個接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對於這種廣播,接收者無法終止廣播,即無法阻止其他接收者的接收動作。
為了驗證以上論斷,我們新建三個BroadcastReceiver,演示一下這個過程,FirstReceiver、SecondReceiver和ThirdReceiver的程式碼如下:
FirstReceiver
package com.scott.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class FirstReceiver extends BroadcastReceiver {
private static final String TAG = "NormalBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "FirstReceiver: " + msg);
}
}
SecondReceiver
public class SecondReceiver extends BroadcastReceiver {
private static final String TAG = "NormalBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "SecondReceiver: " + msg);
}
}
ThirdReceiver
public class ThirdReceiver extends BroadcastReceiver {
private static final String TAG = "NormalBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "ThirdReceiver: " + msg);
}}
從上面程式的執行結果來看這三個接收者都接收到這條廣播了,我們稍微修改一下三個接收者,在 onReceive 方法的最後一行新增以下程式碼,試圖終止廣播:abortBroadcast();再次執行,我們會發現,控制檯中三個接收者仍然都列印了自己的日誌,表明接收者並不能終止廣播。有序廣播(Ordered Broadcast)
有序廣播比較特殊,它每次只發送到優先順序較高的接收者那裡,然後由優先順序高的接受者再傳播到優先順序低的接收者那裡,優先順序高的接收者有能力終止這個廣播。
為了演示有序廣播的流程,我們修改一下上面三個接收者的程式碼,如下:
FirstReceiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class FirstReceiver extends BroadcastReceiver {
private static final String TAG = "OrderedBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.i(TAG, "FirstReceiver: " + msg);
Bundle bundle = new Bundle();
bundle.putString("msg", msg + "@FirstReceiver");
setResultExtras(bundle);
}
}
SecondReceiver
public class SecondReceiver extends BroadcastReceiver {
private static final String TAG = "OrderedBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultExtras(true).getString("msg");
Log.i(TAG, "SecondReceiver: " + msg);
Bundle bundle = new Bundle();
bundle.putString("msg", msg + "@SecondReceiver");
setResultExtras(bundle);
}}
ThirdReceiver
public class ThirdReceiver extends BroadcastReceiver {
private static final String TAG = "OrderedBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultExtras(true).getString("msg");
Log.i(TAG, "ThirdReceiver: " + msg);
}
}
我們注意到,在FirstReceiver和SecondReceiver中最後都使用了setResultExtras方法將一個Bundle物件設定為結果集物件,傳遞到下一個接收者那裡,這樣以來,優先順序低的接收者可以用getResultExtras獲取到最新的經過處理的資訊集合。
程式碼改完之後,我們需要為三個接收者註冊廣播地址,我們修改一下AndroidMainfest.xml檔案:
<receiver android:name=".FirstReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".SecondReceiver">
<intent-filter android:priority="999">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".ThirdReceiver">
<intent-filter android:priority="998">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
我們看到,現在這三個接收者的<intent-filter>多了一個android:priority屬性,並且依次減小。這個屬性的範圍在-1000到1000,數值越大,優先順序越高。
現在,我們需要修改一下發送廣播的程式碼,如下:
public void send(View view) {
Intent intent = new Intent("android.intent.action.MY_BROADCAST");
intent.putExtra("msg", "hello receiver.");
sendOrderedBroadcast(intent, "scott.permission.MY_BROADCAST_PERMISSION");
}
注意,使用sendOrderedBroadcast方法傳送有序廣播時,需要一個許可權引數,如果為null則表示不要求接收者宣告指定的許可權,如果不為null,則表示接收者若要接收此廣播,需宣告指定許可權。這樣做是從安全形度考慮的,例如系統的簡訊就是有序廣播的形式,一個應用可能是具有攔截垃圾簡訊的功能,當簡訊到來時它可以先接受到簡訊廣播,必要時終止廣播傳遞,這樣的軟體就必須宣告接收簡訊的許可權。
所以我們在AndroidMainfest.xml中定義一個許可權:
<permission android:protectionLevel="normal"
android:name="scott.permission.MY_BROADCAST_PERMISSION" />
然後宣告使用了此許可權:
<uses-permission android:name="scott.permission.MY_BROADCAST_PERMISSION" />
然後我們執行程式,我們看到接收是按照順序的,第一個和第二個都在結果集中加入了自己的標記,並且向優先順序低的接收者傳遞下去。
既然是順序傳遞,試著終止這種傳遞,看一看效果如何,我們修改FirstReceiver的程式碼,在onReceive的最後一行新增以下程式碼:
abortBroadcast();
此次,只有第一個接收者執行了,其它兩個都沒能執行,因為廣播被第一個接收者終止了。