Android Broadcast Receiver完全入门指南

1. 什么是 BroadcastReceiver?

BroadcastReceiver(广播接收器)是 Android 四大组件之一,它就像是一个"订阅者":系统或应用会发出各种各样的"广播消息",而你可以编写一个 BroadcastReceiver 来监听并响应你感兴趣的消息,比如:

  • 设备电量低了

  • 网络连接状态发生了变化

  • 用户拔掉了耳机

  • 应用安装或卸载

  • 闹钟时间到了

简单说,BroadcastReceiver 让你能监听系统全局事件或自定义事件,并做出响应

2. BroadcastReceiver 的作用与应用场景

2.1 监听系统事件

无需实时运行,只在事件发生时被系统唤醒并执行一段代码,省电又高效。

2.2 应用内/跨应用通信

你可以在自己 App 内部发送广播让不同组件收到消息,也可以让其他 App 收到你发的广播(或监听其他 App 的广播),实现解耦。

2.3 开启其他组件

收到广播后,可以启动一个 ActivityService 或发通知,但注意后台执行限制。

2.4 典型场景

  • 电量变化:电量低于 20% 时提示用户或自动进入省电模式。

  • 网络变化:Wi-Fi 断开时自动暂停下载。

  • 耳机插拔:音乐 App 检测到耳机拔出时自动暂停播放。

  • 应用安装/卸载:清理与该应用相关的缓存文件。

  • 闹钟/定时任务 :结合 AlarmManager 执行定时任务(但有更优方案)。

  • 应用内通信:购物车更新,通知其他页面刷新。

3. 广播的类型

从传播方式看,广播分为两类:

类型 特点 典型使用
标准广播(Normal Broadcasts) 完全异步,所有接收器几乎同时收到,无法被拦截,不可被修改。 系统通知:时区变更、屏幕开启等。
有序广播(Ordered Broadcasts) 一次发送给一个接收器,按优先级顺序传递,前面的接收器可以修改结果甚至中止广播。 需要处理顺序的场景,如短信拦截。

从广播来源看,分为系统广播自定义广播 。系统广播由 Android 系统发送,如 ACTION_BOOT_COMPLETED(开机完成);自定义广播则是开发者自己发送的。

4. 如何接收广播:注册 BroadcastReceiver

想让 BroadcastReceiver 监听广播,必须进行注册 。注册方式有两种:静态注册 (清单文件)和动态注册(代码)。

4.1 静态注册(清单注册)

AndroidManifest.xml 中声明,即使应用未启动,也能接收广播(受版本限制,见 7.3 节)。系统广播中的开机广播、应用安装等必须使用静态注册才能收到。

步骤

  1. 创建一个类,继承 BroadcastReceiver,实现 onReceive()

  2. <application> 节点下注册 <receiver>,并添加 <intent-filter> 指定要监听的广播动作。

示例:监听开机完成广播

kotlin

复制代码
// MyBootReceiver.kt
class MyBootReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
            // 开机完成,可以做初始化操作
        }
    }
}

AndroidManifest.xml 中:

xml

复制代码
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

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

注意:从 Android 8.0 (API 26) 开始,大部分系统广播无法再通过静态注册接收(除了少数白名单广播,如开机,见 7.3)。

4.2 动态注册(代码注册)

ActivityService 等组件中通过代码注册,通常与生命周期绑定,应用退出后自动失效(因为组件销毁)。

步骤

  1. 实例化自定义的 BroadcastReceiver

  2. 创建 IntentFilter,添加要监听的动作。

  3. 调用 registerReceiver(receiver, filter) 进行注册。

  4. 别忘了在合适时机取消注册 (如 onPause/onStop 中调用 unregisterReceiver()),避免内存泄漏或异常。

示例:监听网络变化

kotlin

复制代码
class MainActivity : AppCompatActivity() {
    private val networkReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            // 网络状态变化,更新 UI
        }
    }

    override fun onStart() {
        super.onStart()
        val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
        registerReceiver(networkReceiver, filter)
    }

    override fun onStop() {
        super.onStop()
        unregisterReceiver(networkReceiver)
    }
}

注意CONNECTIVITY_ACTION 在 Android 7.0 (API 24) 及更高版本同样受到后台限制,建议使用 ConnectivityManager.NetworkCallback 代替广播监听网络变化。这里只是为了演示动态注册的步骤。

4.3 两种注册方式对比

特性 静态注册 动态注册
何时接收 应用未启动时也能收到(限制广播) 只在组件存在时才能接收
生命周期 独立于组件,有广播就调用 随注册组件(Activity等)生命周期
系统开销 相对重,常驻内存 轻量,随组件回收
适用场景 需要开机自启等必需场景 大部分应用内实时监听场景
取消注册 无需手动取消 必须手动取消(通常在 onStop/onDestroy)

5. 发送广播

你可以发送系统定义的广播,但通常开发者发送的是自定义广播。

5.1 发送标准广播

kotlin

复制代码
val intent = Intent("com.example.MY_CUSTOM_ACTION")
intent.putExtra("key", "value")
// 发送给所有匹配的接收器(包括其他App)
sendBroadcast(intent)
// 如果需要限制接收方,可以添加权限
// sendBroadcast(intent, "com.example.MY_PERMISSION")

5.2 发送有序广播

kotlin

复制代码
val intent = Intent("com.example.MY_ORDERED_ACTION")
// 最后一个参数为最终接收器,当所有接收器处理完后如果没有被中止,会收到结果
sendOrderedBroadcast(intent, null, object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 最终执行,可以获取到前面接收器设置的结果
        val resultData = resultData
    }
}, null, Activity.RESULT_OK, null, null)

在有序广播的接收器中,可以:

  • setResultData(data) 修改数据

  • abortBroadcast() 中止传递(需要权限,且仅对有序广播有效)

5.3 应用内发送(LocalBroadcastManager,已弃用)

为了安全和性能,过去常使用 LocalBroadcastManager 限制广播仅在进程内传递。但从 AndroidX 开始,此组件已被弃用 ,官方建议用 LiveDataFlowEventBus 替代。如果你仍需要应用内广播,可以使用带有自定义权限的广播,或直接使用观察者模式。

6. BroadcastReceiver 的生命周期

BroadcastReceiver 的生命周期非常短暂,只在 onReceive() 方法执行期间有效。

  • onReceive(context, intent) :当广播被接收时调用。该方法在主线程 执行,必须在 10 秒内完成,否则会导致 ANR。

  • BroadcastReceiver 对象在 onReceive() 返回后会变成无效状态(不再活跃),系统随时可能回收。

绝对不要在 onReceive() 中做耗时操作 (如网络请求、复杂计算、大文件读写)。如果必须做耗时操作,正确的做法是启动一个 Service(某些情况下受限制)或调度 WorkManager 任务。

7. 权限与安全

7.1 发送广播时添加权限

防止未授权的应用接收你的广播:

kotlin

复制代码
sendBroadcast(intent, "com.example.MY_PERMISSION")

只有声明了 MY_PERMISSION 权限的接收器才能收到该广播。

7.2 接收广播时要求发送方持有权限

在注册接收器时,你可以在 registerReceiver() 中指定一个 broadcastPermission,只有持有该权限的发送方才能向你的接收器发送广播。同样,静态注册时可使用 android:permission 属性。

7.3 Android 版本注意事项(必读)

  • Android 8.0 (API 26) :除了少数隐式广播(如开机广播),静态注册的隐式广播接收器将不再工作 。大部分系统广播必须动态注册。发送隐式广播(即目标是 action 而非组件类名)也受到限制,建议使用显式广播(指定 ComponentName)。

  • Android 14 (API 34):进一步收紧,隐式广播发送者可能需要申报权限,且缓存广播更加严格。

  • 为了兼容性 :对于需要一直运行的功能,考虑使用 WorkManagerJobScheduler 代替广播接收器。

白名单广播 (可在清单中静态注册而无需应用运行)包括:ACTION_BOOT_COMPLETEDACTION_LOCALE_CHANGED 等,具体参考官方文档。

8. 实战演练:一个电量变化监听小案例

假设我们要做一个在电量低于 15% 时提醒用户的功能。因为 ACTION_BATTERY_LOW 是粘性广播且不允许静态注册,我们用动态注册监听 ACTION_BATTERY_CHANGED(但该广播只能动态注册,且系统会频繁发送)。

代码清单(在 Activity 中)

kotlin

复制代码
class BatteryActivity : AppCompatActivity() {
    private lateinit var batteryReceiver: BroadcastReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_battery)

        batteryReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
                val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
                val batteryPct = level * 100 / scale.toFloat()
                if (batteryPct < 15) {
                    // 低电量,发通知或显示对话框
                    showLowBatteryWarning()
                }
            }
        }
    }

    override fun onStart() {
        super.onStart()
        val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
        registerReceiver(batteryReceiver, filter)
    }

    override fun onStop() {
        super.onStop()
        unregisterReceiver(batteryReceiver)
    }

    private fun showLowBatteryWarning() {
        // 这里可以发通知
    }
}

9. 静态注册自定义广播的完整例子(仅应用内)

如果你想在应用内用静态注册接收自定义广播(例如通知其他组件),可以使用显式广播以保证安全且不受系统限制。

发送方:

kotlin

复制代码
val intent = Intent(this, MyInternalReceiver::class.java)
intent.action = "com.example.INTERNAL_ACTION"
sendBroadcast(intent)

接收方(清单中注册,exported=false 确保安全):

xml

复制代码
<receiver
    android:name=".MyInternalReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.INTERNAL_ACTION" />
    </intent-filter>
</receiver>

kotlin

复制代码
class MyInternalReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 响应内部事件
    }
}

10. 常见问题与最佳实践

10.1 别忘了取消动态注册

动态注册必须在合适的生命周期方法中取消,通常 onPauseonStop 中执行 unregisterReceiver()。否则当你退出 Activity 后接收器仍然存在,系统会抛出 leaked 异常,严重时导致崩溃。

10.2 不要做耗时操作

onReceive 运行在主线程,应迅速返回。耗时任务应:

  • 启动 Service(注意后台限制)

  • 使用 goAsync()(需要 API 11+,但较少使用)

  • 调度 WorkManager

10.3 尽量减少静态注册,多用动态 + 生命周期感知组件

Android 8.0+ 限制后,静态注册的用途已经很有限。除非你确实需要应用不在运行时接收广播,否则建议动态注册,并结合 LiveDataLifecycle 组件自动管理注册/取消。

10.4 使用 LocalBroadcastManager 的替代品

LocalBroadcastManager 被弃用,建议使用以下替代:

  • LiveData / SharedFlow:组件间通信。

  • EventBus(GreenRobot):轻量级事件总线。

  • Kotlin Flow:应用内数据流。

  • 如果必须使用广播,且仅限应用内,可以使用带权限的显式广播。

10.5 Android 13 (API 33) 引入的通知权限

如果你的广播接收器会弹出通知,需要确保已获得通知权限(POST_NOTIFICATIONS)。对于静态注册的接收器启动前台服务,也会受到新限制,详细查阅对应版本的行为变更。

11. 总结

  • BroadcastReceiver 是 Android 中一个轻量级的消息订阅组件,用于接收系统或应用内广播消息。

  • 注册方式分为静态注册 (清单)和动态注册(代码),目前大部分场景使用动态注册。

  • 广播分为标准广播有序广播,后者可以按优先级处理和中止。

  • 注意版本适配,尤其是 Android 8.0 以后对静态注册的隐式广播限制,以及 Android 14 的进一步收紧。

  • 始终在合适的生命周期取消动态注册,避免泄漏;onReceive() 中不做耗时操作。

  • 谨慎使用广播的应用内通信,可逐步用 LiveData/Flow 替换,但广播仍有用武之地。


延伸阅读推荐:

相关推荐
Knight_AL6 小时前
使用 CyclicBarrier + 自定义线程池实现 SpringBoot 并行报表(完整性能对比)
java·spring boot·后端
IT_陈寒6 小时前
Java的finally块居然没执行?这是个巨坑
前端·人工智能·后端
代码羊羊6 小时前
Rust 闭包全方位详解:语法、捕获规则、Fn 三特征、返回值实战
开发语言·后端·rust
人道领域6 小时前
【LeetCode刷题日记】347.前k个高频元素
java·数据结构·算法·leetcode
tjl521314_216 小时前
02C++ 静态变量与链接性
java·jvm·c++
摇滚侠7 小时前
Public Key Retrieval is not allowed
java·数据库·mysql
计算机学姐7 小时前
基于微信小程序的宠物服务系统【uniapp+springboot+vue】
java·vue.js·spring boot·mysql·微信小程序·uni-app·宠物
lst04267 小时前
Maven 构建命令
java·maven
梅孔立7 小时前
Aspose.Words Java 表格动态删列、合并列、表头重建、全局字体统一解决方案
java·开发语言·word·aspose·在线编辑