标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻受到这条广播消息。标准广播的效率比较高,但同时它是无法被截断的。
有序广播则是一种同步执行的广播。同步简单来说就是必须一件事一件事做,等前一件做完了才能做下一件事。在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器的逻辑执行完毕之后,广播才会继续传递。优先级高的广播接收器优先收到广播消息,并且可以切断正在传递的广播。
Android 内置很多系统级别的广播,比如手机开机完成会发出一条广播,电池的电量发生变化会发出一条广播,时间或者时区发生改变会发出一条广播等等。
动态注册:在代码中注册;只有启动程序才能注册;最后要 unregisterReceiver;自由地控制注册与注销,灵活性。
(1)动态注册需要传入 BroadcastReceiver 和 IntentFilter 两个参数:
第一个参数:使用自定义类 extends BroadcastReceiver,并重写onReceive()
方法。
第二个参数:创建一个 IntentFilter 的实例,想监听什么广播就在 IntentFilter 中添加相应的 action。
最后要记得,动态注册的广播接收器一定都要注销才行。
...
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//当网络发生变化系统会发出一条值为 android.net.conn.CONNECTIVITY_CHANGE 的广播
receiver = new NetworkChangeReceiver();
registerReceiver(receiver, filter);
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);//一定要注销接收器
}
class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "网络变化", Toast.LENGTH_SHORT).show();
}
}
(2)只是提醒网络发生变化还不够人性化,修改onReceive()
方法:
首先通过getSystemService()
方法获取 ConnectivityManager 实例,这是一个系统服务类,专门用于管理网络连接。
然后调用它的getActiveNetworkInfo()
获取 NetworkInfo 的实例,再调用 NetworkInfo 的isAvailable()
来判断是否有网络,以此来提示用户。
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context,Intent intent){
ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isAvailable()) {
Toast.makeText(context, "网络已连接", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(context,"网络已断开",Toast.LENGTH_SHORT).show();
}
}
}
如果程序需要访问一些系统的关键性信息,必须在配置文件中声明权限才可以,否则程序将会直接崩溃。访问 http://developer.android.com/reference/android/Manifest.permission.html 查看系统所有可声明的权限。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
静态注册:程序未启动就能注册;系统级别,不需要手动取消注册。
(1)首先不再使用内部类方式定义广播接收器,因为要在 AndroidManifest.xml 中将这个广播接收器的类名注册进去,定义一个 BootCompleteReceiver 类:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context,"开机完毕",Toast.LENGTH_SHORT).show();
}
}
(2)在 AndroidManifest.xml 中注册,并开启权限:
<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED">
</action>
</intent-filter>
</receiver>
不要在onReceive()
方法中添加过多的逻辑或者进行任何耗时的操作,因为在广播接收器中是不允许开启线程的,当onReceive()
方法运行时间过长,程序就会报错。因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如启动一个服务。
(1)在发送之前,先定义一个广播接收器来接收广播。新建一个 MyBroadcastReceiver 继承自 BroadcastReceiver 。
public class MyBroadcastReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "啦啦啦广播已接收", Toast.LENGTH_SHORT).show();
}
}
然后在 AndroidManifest.xml 中对这个接收器进行注册,这里让 MyBroadcastReceiver 接收一条值为 com.example.test.MY_BROADCAST 的广播。
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
<action android:name="com.example.test.MY_BROADCAST" />
</intent-filter>
</receiver>
(2)在布局中定义一个按钮,用作发送广播的触发点。
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.test.MY_BROADCAST");
sendBroadcast(intent);
}
});
另外,由于广播是用 Intent 进行传递的,因此还可以在 Intent 中携带一些数据传递给广播接收器。
发送方:intent.putExtra("data","233333");
接收方:String data = intent.getExtras().getString("data");
或者是
String data = intent.getStringExtra("data");
发送有序广播只需要改动一行代码:将sendBroadcast(intent);
改成sendOrderedBroadcast(intent, null);
sendOrderedBroadcast()
方法接收两个参数,第一个还是 Intent,第二个参数是一个与权限相关的字符串。
在注册的时候设定广播接收器的优先级:<intent-filter android:priority = "100">
如果收到广播不想让之后的接收器继续收到广播,可以在接收器中截断广播:abortBroadcast();
使用本地广播的代码基本上和动态注册广播接收器以及发送广播的代码是一样的。首先通过 LocalBroadcastManager 的getInstance()
方法得到实例,然后在注册广播接收器的时候调用 LocalBroadcastManager 的registerReceiver()
方法,发送广播调用的是 LocalBroadcastManager 的sendBroadcast()
方法。另外要注意的是,本地广播是无法通过静态注册的方式来接收的。