在Android中的每个应用程序可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能来自于系统的,也可能来自于其他应用程序的。Android提供了一整套完整的API,允许应用程序自由地发送和接收广播。发送广播就是借助之前了解过的Intent,接收广播则需要用到广播接收器(Broadcast Receiver)。.
1、广播的类型
- 标准广播:Normal broadcast,是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此他们之间没有任何先后顺序可言。这种广播效率比较高,同时也意味着无法被截断。
- 有序广播:Ordered broadcast,是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有顺序的,优先级高的广播接收器可以先接受到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
2、广播接收器的使用方法
Android系统内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。例如,手机开机完成后会发出一条广播消息,电池的电量发生变化时会发出一条广播,时间或时区发生改变时也会发出一条广播等等;我们如果想要接收到这些广播,则需要用到广播接收器。
创建广播接收器的方法很简单,我们只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑可以在这个方法中进行处理。
3、广播接收器的注册
广播接收器可以自由地对自己感兴趣的广播进行注册,这样才能在有相应的广播发出时,广播接收器就能够收到该广播,并在内部进行相应的逻辑处理。注册广播的方式有两种:
- 在代码内注册:也称动态注册。这种注册方法一般过程是
- 在Activity中创建一个IntentFilter的对象,然后用IntentFilter对象的addAction()方法添加相应的广播类型
- 我们还需要有一个我们自定义的广播接收器的对象,
- 然后通过Activity的registerReceiver(BroadcastReceiver , IntentFilter)将过滤器和广播接收器连接在一起,这样就完成了注册
- 最后要记得,动态注册的广播接收器一定要记得取消注册才行,取消时是通过unregisterReceiver(networkChangeReceiver);方法就可以取消注册
1 public class ThirdActivity extends Activity { 2 3 private IntentFilter intentFilter ; 4 private NetworkChangeReceiver networkChangeReceiver ; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_third); 10
11 intentFilter = new IntentFilter() ; 12 intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); 13 networkChangeReceiver = new NetworkChangeReceiver() ; 14 registerReceiver(networkChangeReceiver, intentFilter) ; 15 16 unregisterReceiver(networkChangeReceiver); 17 } 18 19 class NetworkChangeReceiver extends BroadcastReceiver{ 20 @Override 21 public void onReceive(Context context, Intent intent) { 22 Toast.makeText(context, "network changed", Toast.LENGTH_SHORT).show(); 23 } 24 } 25 }优缺点:动态注册的广播接收器可以自由地控制注册和注销,非常灵活,但是也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在Activity的onCreate()方法中的。
- 在AndroidManifest.xml中注册:也称静态注册。这种情况下,我们一般不用内部类的方法来定义广播接收器,因为需要在AndroidManifest.xml中进行注册时需要用到我们自定义的广播接收器的类名。其具体的注册方法同Activity的注册方法类似。在intent-filter中加入我们想要接收的广播就行了。
<receiver android:name=".BootCompleteReceiver"> <intent-filter > <action android:name="android.intent.action.BOOT_COMPLETED /> </intent-filter> </receiver>
静态注册的优点在于可以一开机就可以开始接收相应的广播,不会像动态注册那样必须要等到启动程序后才可以。
- 此外,还有一点非常重要的是,android系统为了保证应用程序的安全性做了规定,如果程序中需要访问系统的关键性信息,必须在配置文件中声明权限才行,否则程序将会直接崩溃,比如像上面的查询网络状态就需要声明权限。
- 不要在广播接收器的onReceive()方法中添加过多的逻辑或者进行任何耗时操作,因为在广播接收器中是不允许开启线程的,当onReceive()方法运行太长时间而没有结束时,系统会报错。
4、发送自定义广播
广播是一种可以跨进程的通信方式,我们可以在我们的应用程序中发送广播,其他应用进程也可以收到我们的广播信息。发送广播是通过Intent来实现的。
- 发送标准广播:通过创建一个Intent对象,然后通过Activity的sendBroadcast(Intent intent)方法来进行发送。广播的类型可以在我们创建Intent对象的时候通过构造方法Intent(String action)来自定义,eg:
1 button.setOnClickListener(new OnClickListener() { 2 @Override 3 public void onClick(View v) { 4 Intent intent = new Intent("com.keli.MY_BROADCAST") ; 5 sendBroadcast(intent); 6 } 7 });
当然,我们也可以在发送广播的Intent中携带一些数据。然后在广播接收器的onReceive()方法中通过getIntent()方法来获取Intent,并取出相应的数据。
- 发送有序广播:发送有序广播的方法和发送标准广播的方法基本相同,只是需要将最后的sendBroadcast(intent)发送方法换成sendOrderedBroadcast(intent,null)即可。这里的第二个参数是一个与权限相关的字符串。那么设定广播的先后顺序是根据广播的优先级来判断的,我们可以在AndroidManifest.xml中注册广播接收器时通过android:priority属性来设置优先级。
1 <receiver android:name=".MyBroascastReceiver"> 2 <intent-filter android:priority="100"> 3 <action android:name="com.keli.MY_BROADCAST"/> 4 </intent-filter> 5 </receiver>
此外,对于有序广播,我们可以在我们的广播接收器中的onReceive()方法的逻辑中对该广播进行截断,截断广播的方法也很简单,直接调用abortBroadcast();方法就可以了。
- 使用本地广播:Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播。主要是使用了一个LocalBroadcastManager对象来对广播进行管理,并提供了发送和注册广播接收器的方法。本地广播是无法通过静态注册的方法进行注册的。
5、在广播接收器中启动活动
在广播接收器中也可以启动一个活动,但是我们启动活动之前必须给intent加入FLAG_ACTIVITY_NEW_TASK标志,否则将无法启动。下面的代码是创建一个广播接收器,在接收到广播后弹出一个警告对话框,并且设置该对话框不可取消,只能通过点击确定按钮来启动另一个活动页面。
1 public class NetworkChangeReceiver extends BroadcastReceiver{ 2 @Override 3 public void onReceive(final Context context, Intent intent) { 4 //构建对话框,并设置对话框的标题、内容 5 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context) ; 6 dialogBuilder.setTitle("Warning") ; 7 dialogBuilder.setMessage("You are forced to ofline. Please try to login again") ; 8 //设置对话框不可取消 9 dialogBuilder.setCancelable(false) ; 10 //设置对话框的确定按钮,第一个参数是按钮上显示的text,
11 //第二个参数是添加点击确定按钮的响应事件,这里我们设定为启动一个登陆界面 11 dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { 12 @Override 13 public void onClick(DialogInterface dialog, int which) { 14 Intent intent = new Intent(context, LoginActivity.class) ; 15 //必须添加FLAG_ACTIVITY_NEW_TASK标志 16 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ; 17 context.startActivity(intent); 18 } 19 }); 20 AlertDialog alertDialog = dialogBuilder.create() ; 21 //设置AlertDialog的类型,保证在广播接收器中可以正常弹出 22 alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 23 } 24 }