You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android(Kotlin)中用Alarm Manager设置空闲时重复闹钟

Android平台用Kotlin结合AlarmManager实现空闲状态重复闹钟功能

核心实现思路

由于Android 6.0+的Doze模式限制,常规重复闹钟方法(如setInexactRepeating)在设备空闲时会被系统推迟。要实现空闲状态下的可靠重复闹钟,需采用单次精确闹钟+触发后重置的方案,结合setExactAndAllowWhileIdle(API 23+)确保Doze模式下也能触发。

完整实现步骤

1. 定义广播接收器

闹钟触发后通过广播接收器处理通知展示,并重置下一次闹钟:

class ReminderNotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        context ?: return
        intent ?: return

        // 展示通知
        val title = intent.getStringExtra(notificationTitleExtra) ?: "提醒"
        val message = intent.getStringExtra(notificationMessageExtra) ?: "您有一条提醒"
        
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "REMINDER_CHANNEL",
                "提醒通知",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }
        
        val notification = NotificationCompat.Builder(context, "REMINDER_CHANNEL")
            .setContentTitle(title)
            .setContentText(message)
            .setSmallIcon(R.drawable.ic_notification) // 替换为你的通知图标
            .build()
        
        notificationManager.notify(REMINDER_NOTIFICATION_ID, notification)

        // 重置下一次重复闹钟
        setNextRepeatAlarm(context, title, message)
    }

    private fun setNextRepeatAlarm(context: Context, title: String, message: String) {
        val intent = Intent(context, ReminderNotificationReceiver::class.java)
        intent.putExtra(notificationTitleExtra, title)
        intent.putExtra(notificationMessageExtra, message)

        val pendingIntent = PendingIntent.getBroadcast(
            context,
            REMINDER_NOTIFICATION_ID,
            intent,
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )

        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        // 计算下一次触发时间(示例为间隔1年)
        val nextTriggerTime = Calendar.getInstance().apply {
            timeInMillis = System.currentTimeMillis()
            add(Calendar.YEAR, 1)
        }.timeInMillis

        // 根据系统版本选择合适的闹钟设置方法
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                nextTriggerTime,
                pendingIntent
            )
        } else {
            alarmManager.setExact(
                AlarmManager.RTC_WAKEUP,
                nextTriggerTime,
                pendingIntent
            )
        }
    }

    companion object {
        const val notificationTitleExtra = "notification_title"
        const val notificationMessageExtra = "notification_message"
        const val REMINDER_NOTIFICATION_ID = 1001
    }
}

2. 初始设置闹钟(Activity中调用)

在需要启动闹钟的地方调用此方法,设置首次触发时间:

fun setupInitialRepeatAlarm(activity: Activity, notificationTitle: String, notificationMessage: String) {
    val billName = activity.binding.etBillName.text.toString().trim()
    val message = "$notificationMessage $billName"
    
    val intent = Intent(activity, ReminderNotificationReceiver::class.java)
    intent.putExtra(ReminderNotificationReceiver.notificationTitleExtra, notificationTitle)
    intent.putExtra(ReminderNotificationReceiver.notificationMessageExtra, message)

    val pendingIntent = PendingIntent.getBroadcast(
        activity,
        ReminderNotificationReceiver.REMINDER_NOTIFICATION_ID,
        intent,
        PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
    )

    val alarmManager = activity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    // 设置首次触发时间(示例为立即触发,可根据需求调整)
    val firstTriggerTime = System.currentTimeMillis()

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(
            AlarmManager.RTC_WAKEUP,
            firstTriggerTime,
            pendingIntent
        )
    } else {
        alarmManager.setExact(
            AlarmManager.RTC_WAKEUP,
            firstTriggerTime,
            pendingIntent
        )
    }
}

3. 清单文件注册广播接收器

在AndroidManifest.xml中添加接收器注册:

<receiver
    android:name=".ReminderNotificationReceiver"
    android:exported="false"/>

关键细节说明

  • 闹钟类型选择:AlarmManager.RTC_WAKEUP会在触发时唤醒设备,确保通知及时展示;若无需唤醒设备,可改用AlarmManager.RTC。
  • PendingIntent Flag:FLAG_IMMUTABLE是API 30+的推荐设置,避免PendingIntent被篡改;FLAG_UPDATE_CURRENT用于更新已存在的PendingIntent的Extra数据。
  • Doze模式适配:setExactAndAllowWhileIdle是唯一能在Doze模式下触发的闹钟方法,但仅支持单次设置,因此必须在广播接收器中重置下一次闹钟以实现重复效果。
  • 通知渠道:Android 8.0+必须创建通知渠道,否则通知无法正常显示。

内容的提问来源于stack exchange,提问作者Femi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:33:25