Android Broadcast

广播机制

标准广播(normal broadcast)

标准广播是一种完全异步执行的广播,在广播发出之后,所有的 BroadcastReceiver 几乎会在同一时刻收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。

有序广播(ordered broadcasts)

有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个 BroadcastReceiver 能够收到这条广播消息,当这个 BroadcastReceiver 中的逻辑执行完毕后,广播才会继续传递。所以此时的 BroadcastReceiver 是有先后顺序的,优先级高的 BroadcastReceiver 就可以先收到广播消息,并且前面的 BroadcastReceiver 还可以截断正在传递的广播,这样后面的 BroadcastReceiver 就无法收到广播消息了。

接收系统广播

动态注册

新建一个类,让它继承自 BroadcastReceiver,并重写父类的 onReceive() 方法:

class MainActivity : BaseActivity() {

lateinit var timeChangeReceiver: TimeChangeReceiver

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
val intentFilter = IntentFilter()
intentFilter.addAction("android.intent.action.TIME_TICK")
timeChangeReceiver = TimeChangeReceiver()
registerReceiver(timeChangeReceiver, intentFilter)
}

override fun onDestroy() {
super.onDestroy()
unregisterReceiver(timeChangeReceiver)
}

inner class TimeChangeReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()
}

}
}

创建一个 IntentFilter 的实例,并给它添加一个 action,接下来创建一个 TimeChangeReceiver 的实例,然后调用 registerReceiver() 方法进行注册,将 TimeChangeReceiver 的实例和 IntentFilter 的实例都传进去,这样 TimeChangeReceiver 就会收到指定 action 的广播。

动态注册的 BroadcastReceiver 一定要取消注册才行,这里在 onDestroy() 方法中通过调用 unregisterReceiver() 方法来实现。

onResume() 方法中注册,在 onPause() 方法中取消注册,这样可以防止内存泄漏,因为 onPause () 方法一定会执行,onDestroy()onStop() 某些情况下不会执行。

动态注册的 BroadcastReceiver 可以自由地控制注册与注销,在灵活性方面有很大的优势。但必须在程序启动之后才能接收广播。

静态注册

静态注册可以在程序未启动的情况下可以接收广播

新建一个类,让它继承自 BroadcastReceiver,并重写父类的 onReceive() 方法:

class MyBroadcastReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show()
}
}

静态的 BroadcastReceiver 一定要在 AndroidManifest.xml 文件中注册:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application
...>
...
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>

exported 属性表示是否允许这个 BroadcastReceiver 接收本程序以外的广播,enabled 属性表示是否启用这个 BroadcastReceiver。

不要在 onReceive() 方法中添加过多的逻辑或者进行任何的耗时操作,因为 BroadcastReceiver 中是不允许开启线程的,当 onReceive() 方法运行了较长时间而没有结束时,程序就会出现错误。

发送自定义广播

发送标准广播

val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
intent.setPackage(packageName)
sendBroadcast(intent)

packageNamegetPackageName() 的语法糖写法,用于获取当前应用程序的包名。在 Android 8.0 系统之后,静态注册的 BroadcastReceiver 是无法接收隐式广播的,而默认情况下我们发出的自定义广播恰恰都是隐式广播。因此这里一定要调用 setPackage() 方法,指定这条广播是发送给哪个应用程序的,从而让它变成一条显式广播,否则静态注册的 BroadcastReceiver 将无法接收到这条广播。

发送有序广播

发送有序广播只需要将 sendBroadcast() 方法改成 sendOrderedBroadcast() 方法。sendOrderedBroadcast() 方法接收两个参数:第一个参数仍然是 Intent;第二个参数是一个与权限相关的字符串,可以传入 null。

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

<application
...>
...
<receiver
android:name="..MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
</application>

如果在 onReceive() 方法中调用了 abortBroadcast() 方法,就表示将这条广播截断,后面的 BroadcastReceiver 将无法再接收到这条广播。