如何基于Kotlin借助广播接收器实现Android电池低于10%的通知提醒
Kotlin实现低电量自动提醒的完整流程
核心链路为:注册系统原生电池状态广播接收器 → 解析广播携带的实时电量值 → 比对是否低于10%阈值 → 触发符合安卓规范的通知提醒,全程无需申请特殊权限,按规范实现即可稳定运行。
前置注意事项
- 关键提醒:从Android 8.0(API 26)开始,系统屏蔽了绝大多数隐式广播的静态注册渠道,电池状态变化广播就在屏蔽列表中,必须用动态注册的方式在前台可见页面/常驻服务中绑定接收,写在Manifest里的静态注册完全收不到回调。
- 通知渠道适配:Android 8.0之后所有通知必须关联对应渠道,没有渠道的通知会被系统直接拦截不展示。
- 通知权限适配:Android 13(API 33)开始,通知属于运行时权限,需要用户手动授权才能弹出。
分步实现代码
1. 初始化低电量通知渠道
建议把这段初始化逻辑放在自定义Application类的onCreate方法中,应用启动时即完成渠道注册,后续发通知可直接复用:
class MyApp : Application() { override fun onCreate() { super.onCreate() initLowBatteryNotifyChannel() } private fun initLowBatteryNotifyChannel() { val channelId = "low_battery_warn" // 仅Android 8.0以上需要主动创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val warnChannel = NotificationChannel( channelId, "低电量提醒", NotificationManager.IMPORTANCE_HIGH ).apply { description = "设备电量低于10%时的提醒通知" enableVibration(true) vibrationPattern = longArrayOf(100, 200, 100, 200) } val notifyManager = getSystemService(NotificationManager::class.java) notifyManager.createNotificationChannel(warnChannel) } } }
2. 编写电池状态广播接收器
这部分为核心处理逻辑,覆盖电量值计算、防重复弹窗、通知构建全流程:
class LowBatteryReceiver : BroadcastReceiver() { // 低电量触发阈值 private val warnThreshold = 10 // 防重复弹窗标记,避免频繁弹通知引发用户反感 private var hasWarned = false override fun onReceive(context: Context?, intent: Intent?) { // 仅处理系统发送的电池状态广播 if (intent?.action != Intent.ACTION_BATTERY_CHANGED) return if (context == null) return // 读取广播携带的电量原始数据 val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) // 异常数据直接跳过,避免应用崩溃 if (level < 0 || scale <= 0) return // *注意*:不要直接把EXTRA_LEVEL的原始值当百分比,不同设备电池刻度上限不一致,必须通过比值计算真实电量 val currentBatteryPercent = (level * 100f / scale).toInt() // 满足低电量条件且未发送过提醒时,触发通知 if (currentBatteryPercent <= warnThreshold && !hasWarned) { showWarnNotification(context, currentBatteryPercent) hasWarned = true } // 电量充回阈值以上时重置标记,下次触发阈值可再次提醒 if (currentBatteryPercent > warnThreshold) { hasWarned = false } } private fun showWarnNotification(context: Context, percent: Int) { val channelId = "low_battery_warn" // 设置通知点击后跳转系统省电设置页 val clickPendingIntent = PendingIntent.getActivity( context, 0, Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS), // 适配Android12以上对PendingIntent的强制要求,否则会直接崩溃 PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) val notify = NotificationCompat.Builder(context, channelId) .setSmallIcon(R.drawable.ic_warn_low_battery) // 替换为项目内的低电量透明矢量图标 .setContentTitle("电量过低") .setContentText("当前设备电量仅剩$percent%,请及时连接充电器") .setPriority(NotificationCompat.PRIORITY_HIGH) .setContentIntent(clickPendingIntent) .setAutoCancel(true) // 用户点击通知后通知自动消失 .build() // 使用固定通知ID,避免重复弹出多条通知 NotificationManagerCompat.from(context).notify(1002, notify) } }
3. 动态注册广播接收器
将接收器的注册逻辑绑定在前台Activity中,页面可见时绑定、不可见时解绑,避免内存泄漏:
class MainActivity : AppCompatActivity() { private lateinit var lowBatteryReceiver: LowBatteryReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) lowBatteryReceiver = LowBatteryReceiver() } override fun onResume() { super.onResume() // 注册接收器,指定需要接收的广播类型 val batteryFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) registerReceiver(lowBatteryReceiver, batteryFilter) // Android13以上需动态申请通知权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val notifyPerm = Manifest.permission.POST_NOTIFICATIONS if (checkSelfPermission(notifyPerm) != PackageManager.PERMISSION_GRANTED) { requestPermissions(arrayOf(notifyPerm), 101) } } } override fun onPause() { super.onPause() // 页面不可见时解绑广播,防止内存泄漏 unregisterReceiver(lowBatteryReceiver) } }
常见踩坑提示
- 不要将接收器写在Manifest中做静态注册:Android 8.0的隐式广播限制会导致该方式完全收不到回调,调试时会出现无反应的问题
- 必须加防重复提醒标记:系统的电池状态广播触发频率很高,不加判断会在短时间内弹出几十条重复通知,极易触发系统的骚扰通知拦截
- 通知小图标需使用透明背景的矢量图,否则在Android 5.0以上系统中会显示为灰色方块,视觉效果极差
- Android12以上的PendingIntent必须显式指定可变性标记,缺失标记会直接导致应用崩溃
内容的提问来源于stack exchange,提问作者Osaid Moha
相关产品推荐
相关产品推荐

