目录
注:本文中代码部分使用Kotlin语言进行编写
一、介绍
广播分为两个方面: 广播发送者和广播接收者(BroadcastReceiver)
广播类型:
1. 标准广播(normal broadcasts): 是一种完全异步执行的广播,在广播发出去之后,所有的BroadcastReceiver几乎会在同一时刻收到这条广播。所以对于BroadcastReceiver来说它们没有顺序可言。这种广播效率高,但也无法被截断。
2. 有序广播(ordered broadcasts): 同步执行广播,在广播发出去之后同一时刻只会有一个BroadcastReceiver接收到广播,当这个BroadcastReceiver中的逻辑执行完之后才会继续传递。所以,对于BroadcastReceiver来说是有先后顺序之分的,优先级高的BroadcastReceiver先接受到广播,优先级低的BroadcastReceiver后接收到广播,并且BroadcastReceiver还可以截断广播,使优先级低于当前BroadcastReceiver的BroadcastReceiver无法接收到广播。
使用场景:
同一app内部的同一组件内的消息通信(单个或多个线程之间)
同一app内部的不同组件之间的消息通信(单个进程)
同一app具有多个进程的不同组件之间的消息通信
不同app之间的组件之间消息通信Android系统在特定情况下与App之间的消息通信。
二、简单使用
BroadcastReceiver在使用时要先进行注册,注册BroadcastReceiver的方式一般分为静态注册(在AndroidManifest.xml中注册)、动态注册(在代码中注册)。静态注册可以让程序在未启动的状态下也能接收广播,而动态注册则只能在程序启动之后才能接收广播。
2.1 静态广播
以接收开机广播为例
新建BroadcastReceiver,右键点击含有主类的包,New->Other->Broadcast Receiver,
在新建的BroadcastReceiver中编写逻辑
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context,"成功接收开机广播",Toast.LENGTH_LONG).show()
}
}
注:BroadcastReceiver中是不允许开启线程的,当onReceive()方法运行较长时间时,程序会报错,不建议添加过多的逻辑及耗时间的操作
在AndroidManifest.xml
中注册,其中enabled
属性表示表示是否启用这个BroadcastReceiver,exported
属性表示是否允许BroadcastReceiver接收本程序外的广播
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
</receiver>
在receiver
标签中添加一个intent-filter
标签,使BroadcastReceiver可以接受开机广播
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
为了保证用户隐私,接收开机广播需要使用系统权限,在AndroidManifest.xml
中声明系统权限(在application上方声明)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
2.2 自定义广播
2.2.1 标准广播
创建一个BroadcastReceiver来接收广播,参考上述静态广播中的创建方法
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context,"成功接收开机广播",Toast.LENGTH_LONG).show()
}
}
在receiver
标签中添加一个intent-filter
标签,使BroadcastReceiver可以接受自定义广播广播
<intent-filter>
<action android:name="com.example.broadcastreceviertext.MY_BROADCAST"/>
</intent-filter>
在activity_main.xml
中添加代码,创建一个按钮作为触发点
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BUTTON"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
给按钮设置点击监听事件
button.setOnClickListener {
//新建一个Intent对象,并将要发送的广播的值传入
val intent = Intent("com.example.broadcastreceviertext.MY_BROADCAST")
//将当前应用程序的包名传给intent
intent.setPackage(packageName)
//发送广播
sendBroadcast(intent)
}
注:Android8.0系统之后,静态注册的BroadcastReceiver是无法接受隐式广播的,默认情况下我们创建的自定义广播均为隐式广播,所以要调用setPackage()方法指定广播要发给那个应用程序,从而将广播设置为显式广播
运行程序,点击按钮即可发送广播,在BroadcastReceiver接受到广播时将会执行我们编写的逻辑Toast.makeText(context,"成功接收开机广播",Toast.LENGTH_LONG).show()
由于广播是使用Intent来发送的,所以我们还可以在发送广播的同时携带数据传递给相应的BroadcastReceiver
2.2.2 有序广播
有序广播式一种同步执行广播,并且可以被截断
再创建一个BroadcastReceiver,新建MyReceiver_2
class MyReceiver_2 : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context,"MyReceiver_2成功接收开机广播", Toast.LENGTH_LONG).show()
}
}
修改AndroidManifest.xml
中代码,使两个BroadcastReceiver监听同一条广播
<receiver
android:name=".MyReceiver_2"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcastreceviertext.MY_BROADCAST" />
</intent-filter>
</receiver>
**运行程序可以看到分别弹出两条提示信息
成功接收开机广播
MyReceiver_2成功接收开机广播
修改按钮监听事件的代码
button.setOnClickListener {
//新建一个Intent对象,并将要发送的广播的值传入
val intent = Intent("com.example.broadcastreceviertext.MY_BROADCAST")
//将当前应用程序的包名传给intent
intent.setPackage(packageName)
//发送有序广播
sendOrderedBroadcast(intent,null)
}
添加代码android:priority="100"
,将MyReceiver
的优先级设置为100,保证MyReceiver的优先级高于MyReceiver_2
<receiver
android:name=".MyReceiver_2"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcastreceviertext.MY_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcastreceviertext.MY_BROADCAST" />
</intent-filter>
</receiver>
修改 MyReceiver
中的代码,将广播截断
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context,"MyReceiver成功接收开机广播",Toast.LENGTH_LONG).show()
//将广播截断
abortBroadcast()
}
}
运行程序可以看到只会弹出MyReceiver
中设置的提示信息
成功接收开机广播
使用sendOrderedBroadcast()
方法,将广播设置为有序广播,并且MyReceiver
的优先级比MyReceiver_2
高,所以MyReceiver
先接收到广播,MyReceiver_2
后接收广播,但是MyReceiver
中使用abortBroadcast()
方法将广播截断,所以MyReceiver_2
无法接收到广播