安卓系统大量的使用了Broadcast Intents去广播系统的事件,比如网络连接、底座模式的状态、电话接听状态等。
当然也可以自定义的去广播。
当你广播消息的时候,Intent指定action,data,和category,这样准确去确定由哪个广播接受者去接受广播。
对于自定义的action,为了避免重名,通常是以包名为开头,如:
public static final String NEW_LIFEFORM_DETECTED =“com.paad.action.NEW_LIFEFORM”;
我们知道intent是可以指定uri标识数据(setData),或者添加额外的基础类型数据:
例子:
Intent intent = new Intent(LifeformDetectedReceiver.NEW_LIFEFORM);
intent.putExtra(LifeformDetectedReceiver.EXTRA_LIFEFORM_NAME,
detectedLifeform);
intent.putExtra(LifeformDetectedReceiver.EXTRA_LONGITUDE,
currentLongitude);
intent.putExtra(LifeformDetectedReceiver.EXTRA_LATITUDE,
currentLatitude);
sendBroadcast(intent);
那么由谁来接受广播?
那就是大名鼎鼎的BroadcastReceiver(广播接受者)来接收Broadcast Intents。
作为组件之一,像activity一样,也可以为其定义intent-filter这里先不讨论。
当然需要为其注册,像activity一样,对于广播接受者,注册方式分为2种:第一种在代码中动态注册,第二种就像activity一样在mainfest中直接注册声明。
在mainfest中的接受者,不需要自个人所在的app跑起来,当有合适的Intent发来的时候,它会自动启动。
BroadcastReceiver 框架代码:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//TODO: React to the Intent received.
}
}
这个Reiceiver的onReceive方法默认在主线程中执行,所以避免ANR,不要做耗时的操作。
略微完整的DEMO:
public class LifeformDetectedReceiver
extends BroadcastReceiver {
public final static String EXTRA_LIFEFORM_NAME
= “EXTRA_LIFEFORM_NAME”;
public final static String EXTRA_LATITUDE = “EXTRA_LATITUDE”;
public final static String EXTRA_LONGITUDE = “EXTRA_LONGITUDE”;
public static final String
ACTION_BURN = “com.paad.alien.action.BURN_IT_WITH_FIRE”;
public static final String
NEW_LIFEFORM = “com.paad.alien.action.NEW_LIFEFORM”;
@Override
public void onReceive(Context context, Intent intent) {
// Get the lifeform details from the intent.
Uri data = intent.getData();
String type = intent.getStringExtra(EXTRA_LIFEFORM_NAME);
double lat = intent.getDoubleExtra(EXTRA_LATITUDE, 0);
double lng = intent.getDoubleExtra(EXTRA_LONGITUDE, 0);
Location loc = new Location(“gps”);
loc.setLatitude(lat);
loc.setLongitude(lng);
if (type.equals(“facehugger”)) {
Intent startIntent = new Intent(ACTION_BURN, data);
startIntent.putExtra(EXTRA_LATITUDE, lat);
startIntent.putExtra(EXTRA_LONGITUDE, lng);
context.startService(startIntent);
}
}
}
在代码中动态注册:
private IntentFilter filter =
new IntentFilter(LifeformDetectedReceiver.NEW_LIFEFORM);
private LifeformDetectedReceiver receiver =
new LifeformDetectedReceiver();
@Override
public void onResume() {
super.onResume();
// 在运行时注册。
registerReceiver(receiver, filter);
}
@Override
public void onPause() {
// 在暂停状态注销。
unregisterReceiver(receiver);
super.onPause();
}
在Mainfest中注册:
<receiver android:name=”.LifeformDetectedReceiver”>
<intent-filter>
<action android:name=”com.paad.alien.action.NEW_LIFEFORM”/>
</intent-filter>
</receiver>
广播有序的Intents
就是发送有序的广播,根据广播接受者的优先级不同,优先级高的接收者可以优先接受到发来的有序广播,除非你中途中止了广播(abortBroadcast),不然会继续往下传播。
那么如何广播有序的Intents?
String requiredPermission = “com.paad.MY_BROADCAST_PERMISSION”;
sendOrderedBroadcast(intent, requiredPermission);
哪里指定优先级?
<receiver
android:name=”.MyOrderedReceiver”
android:permission=”com.paad.MY_BROADCAST_PERMISSION”>
<intent-filter
android:priority=”100”>
<action android:name=”com.paad.action.ORDERED_BROADCAST” />
</intent-filter>
</receiver>
代码中的话:
IntentFilter 对象的setPriority即可。
一个常见的例子来接收有序广播:目标是接收一个处理过的结果集。首先把最终接收到结果的接受者优先级设低点,然后比它高的接受者优先处理了这些数据,层层处理,最后的接受者接收到的会是最终的结果。
//在未被最后个接受者接收时,所初始化的值。
int initialResult = Activity.RESULT_OK;
String initialData = null;
String initialExtras = null;
// A special Handler instance on which to receive the final result.
// Specify null to use the Context on which the Intent was broadcast.
Handler scheduler = null;
sendOrderedBroadcast(intent, requiredPermission, finalResultReceiver,
scheduler, initialResult, initialData, initialExtras);
怎么获得最终的值?
在接受者的onReceive里,可以get到这些值。
广播Sticky Intents
英文意思解释起来貌似是粘性的Intent(意图),那么什么是粘性的呢?与其它的intent有什么不同?
答:这种intent会保存与最后一个广播相关的值,也就是说下一个接收到的也是最近的值。
IntentFilter battery = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent currentBatteryCharge = registerReceiver(null, battery);
上述代码,你会发现注册的接收者居然是为null,首先这里是为了接收到当前系统电池状态的广播intent---系统设备状态广播(比如电池、还有底座状态等),它们广播的是Sticky Intents,所以你经常不需要去弄个接收者去接收这些intents. 只要像上面代码那样registerReceiver它会返回最新的intent。
那么我如何去广播我自己的Sticky intents?
答:首先,你的App的mainfest必须包含BROADCAST_STICKY权限。然后在程序中,你就可以使用sendStickyBroadcast(intent)去发送这样的广播。
既然你说这种Intent会保留下值来,那么我不想要了,如何移除它呢?
答:removeStickyBroadcast(intent).