本篇主要总结了广播的使用,包括常用系统广播列举、动态注册广播、静态注册广播和自定义发送广播的示例。
常用系统广播
系统广播常量的声明和定义在Intent.java中。
- 系统启动完成
ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"
- 重启设备
ACTION_REBOOT = "android.intent.action.REBOOT"
- 息屏
ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF"
- 亮屏
ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"
- 屏幕锁屏
ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS"
- 日期改变
ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED"
- 时间改变(1min)
ACTION_TIME_TICK = "android.intent.action.TIME_TICK"
- 注:系统启动广播可以用来实现自启动apk或服务等功能,自启动apk也可以在AndroidManifest.xml中添加home属性实现。
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
动态注册广播
以时间变化的系统广播为例,动态注册广播可分为3步:
- 创建广播接收器BroadcastReceiver;
- 创建Intent过滤器实例,给IntentFilter实例添加系统广播的action;
- 在使用的Activity中动态注册和取消注册;
- 创建BroadcastReceiver
创建一个类继承自BroadcastReceiver,重写父类的onReceive()方法,当接收到广播时该方法就会执行,可以通过intent的action区分不同的广播,执行对应操作。
<MyBroadcastReceiver.kt>
class MyBroadcastReceiver : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
// 接收到广播就会执行onReceive
if (intent == null) {
return
}
Log.d("=========", "onReceive: ${intent.action} ========")
if (intent.action == Intent.ACTION_TIME_TICK){
Toast.makeText(context, "time has changed", Toast.LENGTH_SHORT).show()
}
}
}
- 创建IntentFilter实例
创建IntentFilter实例,给该实例添加需要监听的系统广播的action,这样当系统时间改变发出这条广播时,当前组件就可以在接收器的onReceive()中接收到。
<MainActivity.kt>
class MainActivity : AppCompatActivity() {
private lateinit var myBroadcastReceiver: MyBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initBroadcastReceiver()
}
private fun initBroadcastReceiver(){
// 创建IntentFilter实例
val intentFilter = IntentFilter()
intentFilter.addAction("android.intent.action.TIME_TICK")
myBroadcastReceiver = MyBroadcastReceiver()
// 动态注册系统广播
registerReceiver(myBroadcastReceiver, intentFilter)
}
override fun onDestroy() {
super.onDestroy()
// 取消广播注册
unregisterReceiver(myBroadcastReceiver)
}
}
- 动态注册和取消注册
动态注册广播时,需要将接收器实例和intent过滤器实例都传入到registerReceiver()中,动态注册的广播接收器系统不会回收,使用完成后需要在onDestroy()中unregisterReceiver()取消注册.
静态注册广播
动态注册必须在应用程序启动后才能接收到广播,有些操作需要在设备一开机就执行,这种情况就需要使用静态注册的方式,以开机广播为例,静态注册广播也分为3步:
- 创建广播接收器BroadcastReceiver;
- 在AndroidManifest.xml中注册静态广播;
- 添加广播权限;
- 创建BroadcastReceiver
注册静态广播可借助AS工具来创建BroadcastReceiver类,右击包文件夹--New--Other--BroadcastReceiver,在弹窗中修改类名确认即可,这种方法创建的BroadcastReceiver类会自动注册在AndroidManifest.xml中。
然后重写父类的onReceive()方法处理接收到的广播消息,注意,由于onReceive()时运行在主线程中,需要避免执行耗时操作。
<MyBroadcastReceiver.kt>
class MyBroadcastReceiver : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
// 接收到广播就会执行onReceive
if (intent == null) {
return
}
Log.d("=========", "onReceive: ${intent.action} ========")
if (intent.action == Intent.ACTION_BOOT_COMPLETED){
Toast.makeText(context, "system started", Toast.LENGTH_SHORT).show()
}
}
}
- 在AndroidManifest.xml中注册静态广播
与动态注册类似,需要在广播注册时添加系统广播的action。
<AndroidManifest.xml>
<!-- 静态注册系统广播 -->
<receiver android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
- 添加广播权限
大多数系统广播属于隐式广播,不指定时发送给哪个应用程序的广播,为了防止不良应用程序通过系统广播主动从后台唤醒,Android 8.0 之后静态注册隐式广播需要添加广播权限。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
自定义广播
广播有标准广播和有序广播两种类型:
标准广播:是一种异步执行广播,广播发出后所有BroadcastReceiver几乎可以同时收到,广播接收器接收广播无先后顺序;
有序广播:是一种同步执行广播,广播发出后同一时刻只有一个BroadcastReceiver能接收到,这个广播接收机逻辑执行完毕之后才会传给下一个,接收器接收的先后顺序可以通过优先级来设置,并且可以截断广播,不继续往后发。
- 发送标准广播
- 现在已经有一个MyBroadcastReceiver广播接收器了,再创建一个SecondBroadcastReceiver用于测试标准广播,所有接收器都可以同时接收到广播,且无先后顺序的特征。
<SecondBroadcastReceiver.kt>
class SecondBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val data = intent.getStringExtra("data")
Log.d("=========", "SecondBroadcastReceiver: ${intent.action} ,data = $data ========")
}
}
- 静态注册广播时添加action,action内容可以自行定义,只要接收和发送使用的action统一即可。
<AndroidManifest.xml>
<!-- 静态注册系统广播 -->
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcastDemo_test" />
</intent-filter>
</receiver>
<receiver
android:name=".SecondBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcastDemo_test" />
</intent-filter>
</receiver>
- 页面中添加一个按钮,通过点击按钮来发送广播:
<MainActivity.kt>
private fun initView(){
btn.setOnClickListener{
val intent = Intent("com.example.broadcastDemo_test")
// 广播可携带数据
intent.putExtra("data", "Broadcast Demo Test!")
intent.setPackage(packageName)
// 发送标准广播
sendBroadcast(intent)
}
}
运行之后点击按钮发送广播,两个接收器在同一时间接收到了自定义发送的标准广播。
- 发送有序广播
有序广播只需要在标准广播的基础上稍作修改即可实现。
- 发送标准广播使用的是sendBroadcast()方法,发送有序广播需要改为sendOrderedBroadcast()方法。
<MainActivity.kt>
private fun initView(){
btn.setOnClickListener{
val intent = Intent("com.example.broadcastDemo_test")
// 广播可携带数据
intent.putExtra("data", "Broadcast Demo Test!")
intent.setPackage(packageName)
// 有序广播
sendOrderedBroadcast(intent, null)
}
}
- 有序广播是有先后顺序的,可以在intent的filter中设置接收器的优先级,这里将SecondBroadcastReceiver的优先级设置为100。
<AndroidManifest.xml>
<receiver
android:name=".SecondBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcastDemo_test" />
</intent-filter>
</receiver>
- SecondBroadcastReceiver优先接收到广播,并且有权决定广播之后发送给其他接收器,如果不希望广播继续发送的话可以截断广播。
<SecondBroadcastReceiver.kt>
class SecondBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val data = intent.getStringExtra("data")
Log.d("=========", "SecondBroadcastReceiver: ${intent.action}, data = $data ========")
// 广播截断
abortBroadcast()
}
}
运行之后就只有优先级高的SecondBroadcastReceiver的打印,广播被截断了,MyBroadcastReceiver根本没有收到广播,因此不会打印内容。