02 BroadcastReceiver 注册方式与生命周期

基于原 PDF 修订、联网校对并补充缺失内容

1. BroadcastReceiver 的核心职责

BroadcastReceiver 是接收广播的组件。真正需要重写的方法是 onReceive(Context context, Intent intent),不是 onReceiver。原 PDF 中多处把 onReceive 写成 onReceiver,需要修正。

class BootCompleteReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
            // 不要在这里做长耗时任务,尽快转交给 WorkManager/JobScheduler
        }
    }
}

2. 两种注册方式

方式 注册位置 能否在应用未运行时被唤起 适用场景 注意点
Manifest-declared receiver AndroidManifest.xml 的 可以,但受系统版本和广播类型限制 开机完成、包变更等需要系统唤起的事件 Android 8.0 起多数隐式广播不能静态注册;Android 12 起带 intent-filter 的组件必须显式 android:exported。
Context-registered receiver 代码中 registerReceiver() 通常依赖注册该 receiver 的 context 是否仍有效 页面可见期间、服务运行期间、短周期监听 必须 unregister;Android 14 target 34 起一般要声明 RECEIVER_EXPORTED/NOT_EXPORTED。

3. 静态注册示例:开机广播

开机广播属于典型 manifest receiver 场景,但必须声明 RECEIVE_BOOT_COMPLETED 权限,并注意设备加密、Direct Boot 以及厂商省电策略的影响。

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

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

如果 receiver 只接收本应用内部显式广播,通常应设为 android:exported=“false”。如果要接收系统或其他应用发来的广播,需要按场景设为 true,并结合权限和数据校验。

4. 动态注册示例:页面可见期间监听

动态注册建议选择最小生命周期范围。页面只在前台需要监听时,可在 onStart/onStop 或 onResume/onPause 成对注册与注销。

class MainActivity : AppCompatActivity() {
    private val receiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            // 处理广播,尽快返回
        }
    }

    override fun onStart() {
        super.onStart()
        val filter = IntentFilter("com.example.app.ACTION_UPDATE")
        ContextCompat.registerReceiver(
            this,
            receiver,
            filter,
            ContextCompat.RECEIVER_NOT_EXPORTED
        )
    }

    override fun onStop() {
        unregisterReceiver(receiver)
        super.onStop()
    }
}
  • onResume/onPause:只在 Activity 可交互时接收。
  • onStart/onStop:只在 Activity 可见时接收。
  • onCreate/onDestroy:Activity 创建到销毁期间接收,但更容易因忘记注销导致泄漏。
  • Application context:适合跨 Activity 生命周期监听,但要自己管理注销时机。

5. Android 14 动态 receiver 导出标记

当应用 target Android 14/API 34 或更高,使用 context-registered receiver 时,一般要指定 RECEIVER_EXPORTED 或 RECEIVER_NOT_EXPORTED。仅接收系统广播的特殊情况不需要指定这个 flag。

flag 含义 何时使用
RECEIVER_NOT_EXPORTED 不对其他应用可见 只接收本应用发送的广播,安全默认值。
RECEIVER_EXPORTED 允许接收其他应用/部分特权系统应用广播 接收跨应用广播或部分非 system UID 的系统组件广播时使用。

6. onReceive 的时间限制与异步处理

onReceive 通常运行在主线程,必须快速返回。官方 API 说明中提到,BroadcastReceiver 一般只有约 10 秒处理时间,超时可能触发 ANR。

  • 短任务:直接在 onReceive 中做最少量处理。
  • 需要异步但很短:使用 goAsync(),把 PendingResult 传给后台线程,完成后调用 finish()。
  • 可靠后台任务:使用 WorkManager/JobScheduler,不要在 receiver 里启动长线程后就返回。
  • 不要从 receiver 直接启动 Activity,用户体验差;用通知引导用户更合理。
override fun onReceive(context: Context, intent: Intent) {
    val pendingResult = goAsync()
    CoroutineScope(Dispatchers.IO).launch {
        try {
            // 短时间后台处理
        } finally {
            pendingResult.finish()
        }
    }
}

7. 原 PDF 动态注册代码修订点

原写法/问题 修正
super.Oncreata(savedInstanceState) super.onCreate(savedInstanceState)
@Overrid @Override
public void onReceiver(…) public void onReceive(…)
sendOrderBroadcast sendOrderedBroadcast
CONNECTIVITY_CHANGE 静态注册或旧 NetworkInfo 写法 动态注册或使用 ConnectivityManager.NetworkCallback/NetworkCapabilities。

参考资料