PAYATHON 2026

Android 应用关闭后,如何监听电源连接和断开事件?

数据小陈

结论

如果设备运行 Android 8.0 或更高版本,且应用的 targetSdkVersion >= 26,仅靠在 AndroidManifest.xml 中声明这两个电源广播,无法在应用关闭后持续监听。ACTION_POWER_CONNECTED 和 ACTION_POWER_DISCONNECTED 是受到清单注册限制的隐式广播,也不在相关豁免列表中。动态注册可以接收这两个广播,但要求注册仍然有效,且应用进程仍然存活。Android 后台执行限制、隐式广播例外

需要先区分“关闭界面”和“结束进程”:界面关闭后,可以在符合平台要求的前台服务中动态注册,继续监听;进程已经结束或应用被强行停止后,不能依靠这两个广播保证自动恢复监听。

原问题没有提供系统版本和 targetSdkVersion,需要先确认是否满足上述版本条件。

为什么清单中的接收器没有触发?

原代码中的 action 字符串是正确的:

android.intent.action.ACTION_POWER_CONNECTED
android.intent.action.ACTION_POWER_DISCONNECTED

它们分别对应 Intent.ACTION_POWER_CONNECTED 和 Intent.ACTION_POWER_DISCONNECTED,表示外部电源接入和移除。字符串中的 ACTION_ 不应删除。这两个广播只能由系统发送。Intent API 文档

在上述版本条件下,清单注册受到限制。即使 Activity 正在显示,接收器仍属于清单注册,不会变成动态注册。android:exported="true" 也不能解除这一限制。

你在 MainActivity.kt 中调用 registerReceiver() 后收到了日志,说明 Alerts.onReceive() 和 action 匹配逻辑至少在这次动态注册测试中有效。接下来可以检查注册位置、注销时机和进程状态。广播接收器文档

界面关闭后继续监听,接收器应该放在哪里?

动态接收器的生命周期取决于注册时使用的 Context 和对应的注销操作,而不只取决于界面是否可见。例如,在 onStart() 注册、onStop() 注销,就只能在对应的界面生命周期内接收广播。改用 applicationContext 注册接收器,可以避开 Activity 销毁带来的生命周期限制,但不能阻止进程被回收。动态接收器的生命周期

如果实际功能需要用户开启持续电源监控,且符合前台服务的适用条件,可以按以下步骤实现:

  1. 用户在可见的 Activity 中开启监控。
  2. 启动前台服务,按要求提供通知并调用 startForeground()。
  3. 在服务中动态注册 Alerts。
  4. 用户关闭监控时停止服务,并注销接收器。

下面的代码只管理已有前台服务中的接收器,需要放进 Service 子类。代码不包含服务声明、通知创建和前台提升逻辑;Alerts 可以继续使用原来的实现。

import android.content.Intent
import android.content.IntentFilter
import androidx.core.content.ContextCompat

// Members of an existing foreground Service.
private val alerts = Alerts()
private var receiverRegistered = false

private fun startPowerMonitoring() {
    if (receiverRegistered) return

    val filter = IntentFilter().apply {
        addAction(Intent.ACTION_POWER_CONNECTED)
        addAction(Intent.ACTION_POWER_DISCONNECTED)
    }

    ContextCompat.registerReceiver(
        this,
        alerts,
        filter,
        ContextCompat.RECEIVER_EXPORTED
    )
    receiverRegistered = true
}

private fun stopPowerMonitoring() {
    if (!receiverRegistered) return

    unregisterReceiver(alerts)
    receiverRegistered = false
}

override fun onDestroy() {
    stopPowerMonitoring()
    super.onDestroy()
}

服务完成必要的前台初始化后,调用 startPowerMonitoring()。示例使用支持该重载的 AndroidX Core API,并显式指定接收器导出标志。这里监听的两个 action 都是系统保护广播。接收器注册方式

前台服务还需满足版本要求:面向 Android 12 及以上版本时,从后台启动前台服务通常受到限制,应在用户操作可见界面时启动;面向 Android 14 及以上版本时,还需声明符合实际用途的服务类型及相应权限。不能仅为了保持监听而随意填写服务类型,具体选择取决于应用的实际功能。前台服务后台启动限制、前台服务类型

如果进程已经结束,还能收到吗?

进程结束后,动态注册随之消失。前台服务可以支持界面之外的持续工作,但不能保证进程永远存活,也不能保证不遗漏每一次插拔事件。

如果用户在系统设置中执行“强行停止”,应用会进入 stopped 状态,需要用户后续启动应用或通过其他允许的交互解除该状态。不能依靠电源广播绕过这一状态。应用 stopped 状态说明

测试时应分别检查按 Home 键、退出 Activity、从最近任务移除、进程被回收和强行停止的情况,避免把它们都归为“应用关闭”。

WorkManager 是否适合这个需求?

如果目标是“在设备充电时执行同步或清理任务”,可以使用 WorkManager,并设置 setRequiresCharging(true)。它适合可延迟的后台任务,系统会结合约束安排执行。WorkManager 工作约束

如果目标是记录每一次电源接入和断开的即时事件,充电约束无法替代事件监听,也不能保证每次插拔都触发任务。

排查当前代码时,先核对系统版本和 targetSdkVersion,再确认动态接收器的注册范围,并在注册完成后实际插拔电源。若需要持续监控,再评估是否有合适的前台服务用途。

备注:内容仅供参考。