1.0Android中的广播类型
Android中的广播主要可以分为两种类型:标准广播和有序广播。
-
标准广播(normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎会在同一时刻收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
标准广播的工作流程如图:
标准广播工作示意图
-
有序广播(ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver能够收到这条广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才会继续传递。所以此时的BroadcastReceiver是有先后顺序的,优先级高的BroadcastReceiver就可以先收到广播消息,并且前面的BroadcastReceiver还可以截断正在传递的广播,这样后面的BroadcastReceiver就无法收到广播消息了。
有序广播的工作流程如图:

2.0BroadcastReceiver
2.1接收系统广播
Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一条广播,系统时间发生改变也会发出一条广播,等等。
注册BroadcastReceiver的方式一般有两种:在代码中注册和在AndroidManifest.xml中注册。其中前者也被称为动态注册,后者也被称为静态注册。
2.1.1动态注册监听时间变化
MainActivity中定义了一个内部类TimeChangeReceiver,这个类是继承自BroadcastReceiver的,并重写了父类的onReceive()方法。这样每当系统时间发生变化时,onReceive()方法就会得到执行
如果想查看完整的系统广播列表,可以到如下的路径中去查看:
<Android SDK>/platforms/<任意android api版本>/data/broadcast_actions.txt
2.1.2静态注册实现开机启动
动态注册的BroadcastReceiver可以自由地控制注册与注销,在灵活性方面有很大的优势。但是它存在着一个缺点,即必须在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下也能接收广播呢?这就需要使用静态注册的方式了。
代码如下:

静态的BroadcastReceiver一定要在AndroidManifest.xml文件中注册才可以使用。

- Exported属性表示是否允许这个BroadcastReceiver接收本程序以外的广播
- Enabled属性表示是否启用这个BroadcastReceiver
- android.intent.action.BOOT_COMPLETED是一条开机广播
- Android 系统为了保护用户设备的安全和隐私,做了严格的规定:如果程序需要进行一些对用户来说比较敏感的操作,必须在AndroidManifest.xml文件中进行权限声明,否则程序将会直接崩溃。比如这里接收系统的开机广播就是需要进行权限声明的,所以我们在上述代码中使用<uses-permission>标签声明了android.permission.RECEIVE_BOOT_COMPLETED权限。
在Android 8.0系统之后,所有隐式广播都不允许使用静态注册的方式来接收了。隐式广播指的是那些没有具体指定发送给哪个应用程序的广播,大多数系统广播属于隐式广播,但是少数特殊的系统广播目前仍然允许使用静态注册的方式来接收。这些特殊的系统广播列表详见https://developer.android.google.cn/guide/components/broadcast-exceptions.html。
2.2发送自定义广播
2.2.1发送标准广播
创建一个BroadcastReceiver如下:

在AndroidManifest.xml中对这个BroadcastReceiver进行修改,让MyBroadcastReceiver接收一条值为com.example.broadcasttest.MY_BROADCAST的广播。

定义了一个按钮,用于作为发送广播的触发点,代码如下:

在Android 8.0系统之后,静态注册的BroadcastReceiver是无法接收隐式广播的,而默认情况下我们发出的自定义广播恰恰都是隐式广播。因此这里一定要调用setPackage()方法,指定这条广播是发送给哪个应用程序的,从而让它变成一条显式广播,否则静态注册的BroadcastReceiver将无法接收到这条广播。
广播是使用Intent来发送的,因此你还可以在Intent中携带一些数据传递给相应的BroadcastReceiver,这一点和Activity的用法是比较相似的。
2.2.2发送有序广播
和标准广播不同,有序广播是一种同步执行的广播,并且是可以被截断的。

sendOrderedBroadcast()方法接收两个参数:
- 第一个参数仍然是Intent
- 第二个参数是一个与权限相关的字符串,这里传入null就行了
在AndroidManifest.xml中对这个BroadcastReceiver的配置进行修改,代码如下所示:

通过android:priority属性给BroadcastReceiver设置了优先级,优先级比较高的BroadcastReceiver就可以先收到广播。

abortBroadcast()方法,就表示将这条广播截断,后面的BroadcastReceiver将无法再接收到这条广播。
网友评论