BroadcastReceiver详解
1. BroadcastReceiver介绍
BroadcastReceiver,“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。在Android系统中,
广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能;当网络
状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;当电池电量改变时,系统会
产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度等等。Android中的广播机制设计的非常出色,
很多事情原本需要开发者亲自操作的,现在只需等待广播告知自己就可以了,大大减少了开发的工作量和开发周期。而
作为应用开发者,就需要数练掌握Android系统提供的一个开发利器,那就是BroadcastReceiver。
2. 注册方式
2.1. 静态注册
静态注册通常在 AndroidManifest.xml 文件中进行。这种方式注册的广播接收器在应用程序启动时就会被创建,并在整个应用程序的生命周期内保持活动状态。
<receiver android:name=".MyBroadCastReceiver">
<intent-filter> <action android:name="com.pateo.mybroadcast"/></intent-filter>
</receiver>
2.1.1. 特点
在 AndroidManifest.xml 文件中配置。
适用于需要在应用程序启动时即开始监听某些广播的场景,如系统启动广播。
即使在应用程序未运行时也能接收广播。
2.1.2. 不同android版本对于静态广播的印象
- android 8之后部分系统广播不能注册静态广播来接收
2.2. 动态注册广播
2.2.1. 动态注册
动态注册是在代码中进行的,通常在活动(Activity)或服务(Service)的 onCreate() 方法中注册广播接收器,并在 onDestroy() 方法中注销。这种方式注册的广播接收器只在注册它的组件处于活动状态时接收广播。
//注册
IntentFilter filter = new IntentFilter("android.intent.action.AIRPLANE_MODE");
registerReceiver(myReceiver, filter);
//反注册
unregisterReceiver(myReceiver);
2.2.3. 特点
- 在代码中动态注册和注销。
- 适用于只在特定组件活动时才需要监听广播的场景。
- 当组件不再活动时,广播接收器会被自动注销。
3. 广播类型
android 中广播一般分为四种:
- 普通广播
- 有序广播
- 粘性广播
- 系统广播
- APP内广播
3.1. 普通广播
普通广播会多个个接收器同时接收到。如下图:
这种广播所有监听该广播的接收器都可以监听到该广播,同一个级别的接受顺序是随机的或则说是无序的,接收器不能
对收到的广播做任何处理,也不能截断广播继续传播。该种类的广播用sendBroadcast发送
3.1.1. 代码示例
class ABroadcastReceiver : BroadcastReceiver() {
private val logTag = "ABroadcastReceiver"
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(logTag, "我是广播接收器A")
}
}
class BBroadcastReceiver : BroadcastReceiver() {
private val logTag = "ABroadcastReceiver"
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(logTag, "我是广播接收器B")
}
}
<receiver
android:name=".ABroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="my.broadcase" />
</intent-filter>
</receiver>
<receiver
android:name=".BBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="my.broadcase" />
</intent-filter>
</receiver>
//方法以未定义的顺序向所有接收器发送广播。这称为常规广播。这种方式效率更高,但也意味着接收器无法从其他接收器读取结果、传播从广播接收到的数据或中止广播。
sendBroadcast(Intent("my.broadcase"))
//ABroadcastReceiver,BBroadcastReceiver都可以接收到
3.2. 有序广播
android中的有序广播,也是一种比较常用的广播,该种类的广播用sendOrderedBroadcast发送。,该中广播主要有
一下特性:
- 按照接收者的优先顺序来接收广播,优先级别在intent-filter中的priority中声明,-
1000
到1000
之间,值越 大优先级越高 - 可以终止广播的继续传播,接受者可以修改intent的内容。
- 同级别接收顺序是随机的,级别低的后收到。
- 能截断广播的继续传播,高级别的广播接收器接收广播后能决定时候截断。能处理广播。
- 同级别动态注册高于静态注册。
常用函数:
- setResultExtras 设置返回值
- abortBroadcast 截断广播
3.2.1. 示例
//广播类
class ABroadcastReceiver : BroadcastReceiver() {
private val logTag = "ABroadcastReceiver"
override fun onReceive(context: Context?, intent: Intent?) {
var bundle: android.os.Bundle? = android.os.Bundle()
bundle?.putString("data", "from ABroadcastReceiver")
setResultExtras(bundle)
}
}
class BBroadcastReceiver : BroadcastReceiver() {
private val logTag = "ABroadcastReceiver"
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(logTag, "我是广播接收器B")
val data: String? = getResultExtras(false)?.getString("data")
Log.d(logTag, "data:$data")
val bundle: android.os.Bundle? = android.os.Bundle()
bundle?.putString("data", "from BBroadcastReceiver")
setResultExtras(bundle)
abortBroadcast()
}
}
class CBroadcastReceiver : BroadcastReceiver() {
private val logTag = "ABroadcastReceiver"
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(logTag, "我是广播接收器C")
val data: String? = getResultExtras(false)?.getString("data")
Log.d(logTag, "data:$data")
var bundle: android.os.Bundle? = android.os.Bundle()
bundle?.putString("data", "from CBroadcastReceiver")
setResultExtras(bundle)
}
}
//注册表
<receiver
android:name=".ABroadcastReceiver"
android:exported="false">
<intent-filter android:priority="100">
<action android:name="my.broadcase" />
</intent-filter>
</receiver>
<receiver
android:name=".BBroadcastReceiver"
android:exported="false"
>
<intent-filter android:priority="50">
<action android:name="my.broadcase" />
</intent-filter>
</receiver>
<receiver
android:name=".CBroadcastReceiver"
android:exported="false" android:priority="10">
<intent-filter>
<action android:name="my.broadcase" />
</intent-filter>
</receiver>
sendOrderedBroadcast(Intent("my.broadcase"), null)
log:
D 我是广播接收器A
D data:null
D 我是广播接收器B
D data:from ABroadcastReceiver
- 发送广播 由于ABroadcastReceiver的优先级最高所以先接收到广播,
- 在ABroadcastReceiver 使用setResultExtras设置返回值
- 下来的优先级是BBroadcastReceiver 所以BBroadcastReceiver接受广播,并且设置返回值。但是又调用的abortBroadcast函数
- 由于BBroadcastReceiver调用了abortBroadcast所以广播传播被截断,所以CBroadcastReceiver无法接收到广播。
3.3. 粘性广播
粘性广播的特点是Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制,10秒限制是指普通的广播如
果onReceive方法执行时间太长,超过10秒的时候系统会将这个广播置为可以干掉的candidate,一旦系统资源不够的
时候,就会干掉这个广播而让它不执行。该广播用sendStickyBroadcast发送。
注:目前已不推荐使用
3.4. 系统广播
android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的
广波,每个广播都有特定的Intent - Filter(包括具体的action),android常用系统广播action如下:
名称 | 广播 |
---|---|
监听网络变化 | android.net.conn.CONNECTIVITY_CHANGE |
关闭或打开飞行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
充电时或电量发生变化 | Intent.ACTION_BATTERY_CHANGED |
电池电量低 | Intent.ACTION_BATTERY_LOW |
电池电量充足(即从电量低变化到饱满时会发出广播 | Intent.ACTION_BATTERY_OKAY |
系统启动完成后(仅广播一次) | Intent.ACTION_BOOT_COMPLETED |
按下照相时的拍照按键(硬件按键)时 | Intent.ACTION_CAMERA_BUTTON |
屏幕锁屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
设备当前设置被改变时(界面语言、设备方向等) | Intent.ACTION_CONFIGURATION_CHANGED |
插入耳机时 | Intent.ACTION_HEADSET_PLUG |
未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡) | Intent.ACTION_MEDIA_BAD_REMOVAL |
插入外部储存装置(如SD卡) | Intent.ACTION_MEDIA_CHECKING |
成功安装APK | Intent.ACTION_PACKAGE_ADDED |
成功删除APK | Intent.ACTION_PACKAGE_REMOVED |
重启设备 | Intent.ACTION_REBOOT |
屏幕被关闭 | Intent.ACTION_SCREEN_OFF |
屏幕被打开 | Intent.ACTION_SCREEN_ON |
关闭系统时 | Intent.ACTION_SHUTDOWN |
重启设备 | Intent.ACTION_REBOOT |
3.4.1. 系统广播所发生的更改
3.4.1.1. Android 7.0
Android 7.0(API 级别 24)及更高版本不会发送以下系统广播:
- ACTION_NEW_PICTURE
- ACTION_NEW_VIDEO
此外,以 Android 7.0 及更高版本为目标平台的应用必须使用 registerReceiver(BroadcastReceiver, IntentFilter) 注册 CONNECTIVITY_ACTION 广播。无法在清单中声明接收器。
3.4.1.1. Android 8.0
Android 8.0(API 级别 26)开始,系统会对清单声明的接收器施加其他限制。
如果您的应用以 Android 8.0 或更高版本为目标平台,则对于大多数隐式广播(未明确针对您的应用的广播)而言,您无法使用清单声明接收器。当用户正在活跃地使用您的应用时,您仍然可以使用上下文注册的接收器。
3.4.1.1. Android 9
从 Android 9(API 级别 28)开始,NETWORK_STATE_CHANGED_ACTION 广播不接收与用户位置信息或个人身份数据相关的信息。
此外,如果您的应用安装在搭载 Android 9 或更高版本的设备上,通过 Wi-Fi 发送的系统广播不包含 SSID、BSSID、连接信息或扫描结果。如需获取此信息,请改为调用 getConnectionInfo()。
3.4.1.1. Android 14
当应用处于缓存状态时,广播传送针对系统运行状况进行了优化。例如,当应用处于缓存状态时,系统会延迟不太重要的系统广播(如 ACTION_SCREEN_ON)。一旦应用从缓存状态进入活跃进程生命周期,系统就会传递所有延迟的广播。
在清单中声明的重要广播会暂时从缓存状态中移除应用以进行分发。
3.4. APP内广播
因为android中的广播是可以跨域的(跨App),因此可能存在一下问题:
其他App针对性发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收广播并处理;
其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息; 即会出现安全性 & 效率性的问
题。
对于上述情况就出现了这种广播,App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。
相比于全局广播(普通广播),App应用内广播优势体现在:安全性高效率高。
一般使用LocalBroadcastManager完成app内广播
val localBroadcastManager = LocalBroadcastManager.getInstance(this)
//注册广播
localBroadcastManager.registerReceiver()
//发送广播
localBroadcastManager.sendBroadcast()
评论区