文章目录
一、广播的概念
广播(BroadCastReceiver)是安卓四大组件之一,用于安卓组件之间的通信,信息由广播发送者流向广播接收者。广播的使用一般有以下场景;
- 同一 app 内部的不同组件之间的消息通信
- 不同 app 之间的组件之间消息通信
- Android 系统在特定情况下与App之间的消息通信
广播使用观察者模式,广播发布者和广播接收者分别为消息发布者和消息订阅者,其大致流程如下:
- 广播接收者通过 Binder 机制向 AMS(Activity Manager Service) 进行注册。
- 广播发送者通过 Binder 机制向 AMS 发送广播。
- AMS查找符合相应条件的广播接收者,并将广播发送到其消息队列中。
- 消息队列拿到此广播,回调 onReceive() 方法。
二、广播的分类
根据广播发送方式的不同,可以将广播分为以下几种类型:
2.1 无序广播(Normal Broadcast)
无序广播也叫普通广播,使用 sendBroadcast() 方法发送广播,广播可以发送给所有的广播接收者,广播接收者在接收广播时有以下顺序:
- 动态广播接收器优先于静态广播接收器
- 同优先级的同类广播接收器,静态:先扫描的优先于后扫描的,动态:先注册的优先于后注册的。
(编写 demo 进行测试时发现动态地后注册的反而先接受,不知道是为什么)
2.2 有序广播(Ordered broadcast)
有序广播使用 sendOrderedBroadcast() 方法发送广播,广播将按照事先设置好的优先级依次发送给广播接收者。广播接收者可以终止广播的继续传播;广播的接收者可以将数据放进广播中传递给后面的广播接收者。广播接收者在接收广播时有以下顺序:
- 优先级高的先接收
- 同优先级的广播接收器,动态优先于静态
- 同优先级的同类广播接收器,静态:先扫描的优先于后扫描的,动态:先注册的优先于后注册的。
2.3 粘性广播(Sticky Broadcast)
粘性广播使用 sendStickyBroadcast() 方法发送广播,发送粘性广播需要申请权限:
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
粘性广播一般用来确保重要的状态改变后的信息被持久保存,并且能随时广播给新的广播接收器。对于普通广播和有序广播,若广播发送者发送广播时广播接收者还未进行注册,则广播接收者无法再收到这个广播;而对于粘性广播,即使广播发送者发送广播时广播接收者还未进行注册,广播接收者会保留这条广播,当广播接收者注册时将此条广播发送给接收者,可以在接收到广播后调用 removeStickyBroadcast(intent) 移除该广播。
2.4 系统广播(System Broadcast)
安卓的大量系统事件都会对外发送标准广播,应用可以通过监听系统广播来实现对系统事件的响应。例如:手机开机、电池电量低、系统时间被改变等。更多的系统广播可见此博客。
2.5 本地广播(Local Broadcast)
本地广播是在应用内部进行广播,不让其它应用参与,相比于使用全局广播添加限制实现本地广播的效果(从上述的广播大致流程可知全局广播有两次通过 Binder 跟 AMS 进行通信的步骤),Local Broadcast 更加安全和高效。关于本地广播的源码解读可以看此博客。
三、广播的注册方式
3.1 静态注册
静态注册的示例如下:
<receiver android:name="com.example.broadcasttest.MainActivity$Receiver">
<intent-filter>
<action android:name="com.example.broadcasttest.update"></action>
</intent-filter>
</receiver>
3.2 动态注册
动态注册的示例如下:
val receiver = MyReceiver()
val filter = IntentFilter()
filter.addAction("com.example.broadcasttest.update")
registerReceiver(receiver, filter)
注意:动态广播需要在使用后进行注销,一般在 onDestroy() 中注销。
unRegisterReceiver(receiver)
3.3 区别
- 动态注册广播不是常驻型广播,也就是说广播跟随activity的生命周期。注意: 在activity结束前,移除广播接收器。
- 静态注册一般持续到进程结束(应用关闭),如果想要在应用关闭后仍然可以接受广播,则需要在发送广播时给 intent 设置 flag,示例如下:
val intent = Intent("com.example.qingyunhuohuo.update")
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
sendBroadCast(sendIntent)
3.4 本地广播的注册
本地广播只能采用动态注册的方式,其注册实例如下:
val receiver = MyReceiver()
val filter = IntentFilter()
filter.addAction("com.example.broadcasttest.update")
LocalBroadcastManager.getInstance (this).registerReceiver(receiver, filter)
注意:本地广播也需要在使用后进行注销,一般在 onDestroy() 中注销。
LocalBroadcastManager.getInstance (this).unregisterReceiver(receiver)