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

Android Studio Kotlin多闹钟创建与重复功能实现问题求助

闹钟功能问题排查与解决方案

问题概述

我正在为应用添加可触发通知的闹钟功能,目前遇到两个核心问题:

  • 新增闹钟后,之前设置的闹钟会失效,推测是因为所有闹钟使用了相同的请求码(0),但不知道如何每次传入新的请求码;
  • 不清楚如何实现用户所需的闹钟重复功能。

曾尝试将System.currentTimeMillis()转为int作为请求码,但并未解决问题。此外,我使用setRepeating方法而非set或setExact,因为后两者会无视设置时间立即触发闹钟。

核心需求:创建多个不同触发时间的闹钟,并支持用户设置每日重复的闹钟。

相关代码

初始setAlarm()函数

private fun setAlarm() {
    alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
    val intent = Intent(this, AlarmReceiver::class.java)
    pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)

    alarmManager.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calender.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        pendingIntent
    )
    Toast.makeText(this, "alarm set", Toast.LENGTH_SHORT).show()
}

初始闹钟接收器类

private lateinit var pendingIntent: PendingIntent
override fun onReceive(p0: Context?, p1: Intent?) {

    val intent = Intent(p0, MainActivity::class.java)
    p1!!.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    pendingIntent = PendingIntent.getActivity(p0, 0, intent, 0)

    val builder = NotificationCompat.Builder(p0!!, "androidAlarm")
        .setSmallIcon(drawable.notification_bg)
        .setContentTitle("Your reminder!")
        .setContentText("Your work has to be done now!")
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .setContentIntent(pendingIntent)


    val notificationManager = NotificationManagerCompat.from(p0)
    if (ActivityCompat.checkSelfPermission(
            p0,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return
    }
    notificationManager.notify(123, builder.build())
}

尝试使用时间戳作为请求码的setAlarm()函数

private fun setAlarm() {
    calender = Calendar.getInstance()
    alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager

    val intent = Intent(this, AlarmReceiver::class.java)
    pendingIntent = PendingIntent.getBroadcast(this, System.currentTimeMillis().toInt(), intent, 0)
    alarmManager.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calender.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        pendingIntent)
    Toast.makeText(this, "alarm set", Toast.LENGTH_SHORT).show()
}

对应修改后的接收器类

class AlarmReceiver : BroadcastReceiver() {
private lateinit var pendingIntent: PendingIntent
override fun onReceive(p0: Context?, p1: Intent?) {
    val id = System.currentTimeMillis().toInt()
    val intent = Intent(p0, MainActivity::class.java)
    p1!!.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    pendingIntent = PendingIntent.getBroadcast(p0, System.currentTimeMillis().toInt(), intent, 0)


    val builder = NotificationCompat.Builder(p0!!, "androidAlarm")
        .setSmallIcon(drawable.notification_bg)
        .setContentTitle("Your reminder!")
        .setContentText("Your work has to be done now!")
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .setContentIntent(pendingIntent)


    val notificationManager = NotificationManagerCompat.from(p0)
    if (ActivityCompat.checkSelfPermission(
            p0,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return
    }
    notificationManager.notify(123, builder.build())
    Log.e("notification: ", "received a notification: ${pendingIntent.toString()}")
}

问题解决思路

1. 解决多个闹钟覆盖问题

之前用相同请求码(0)导致新闹钟覆盖旧的,而System.currentTimeMillis().toInt()会因为long转int溢出丢失精度,导致请求码重复或无效。

解决方案:

  • 使用持久化的唯一递增整数ID作为请求码,比如通过SharedPreferences维护计数器:
// 从SharedPreferences获取当前计数器
val prefs = getSharedPreferences("AlarmPrefs", Context.MODE_PRIVATE)
val requestCode = prefs.getInt("next_alarm_code", 1)

// 创建PendingIntent时使用该请求码,添加适配Android版本的flag
pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)

// 保存自增后的计数器
prefs.edit().putInt("next_alarm_code", requestCode + 1).apply()
  • 确保每个PendingIntent的请求码唯一,同时搭配合适的flag(Android12+需加FLAG_IMMUTABLE),避免被覆盖。

2. 实现重复闹钟功能

现有代码中setRepeating搭配AlarmManager.INTERVAL_DAY已经是每日重复的基础实现,但需注意:

  • Android6.0+的Doze模式会影响setRepeating的准时性,若需要精准重复,改用setExactAndAllowWhileIdle配合每次触发后重新设置闹钟:
// 初始设置精准闹钟
alarmManager.setExactAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP,
    calendar.timeInMillis,
    pendingIntent
)

// 在AlarmReceiver的onReceive中设置下一次触发
override fun onReceive(context: Context?, intent: Intent?) {
    // 显示通知逻辑...

    // 计算次日同一时间
    val nextCalendar = Calendar.getInstance()
    nextCalendar.timeInMillis = System.currentTimeMillis()
    nextCalendar.add(Calendar.DAY_OF_YEAR, 1)

    // 重新设置精准闹钟,使用原请求码确保更新同一闹钟
    val requestCode = intent?.getIntExtra("ALARM_REQUEST_CODE", -1) ?: -1
    val nextIntent = Intent(context, AlarmReceiver::class.java)
    val nextPendingIntent = PendingIntent.getBroadcast(context, requestCode, nextIntent, 
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)

    val alarmManager = context?.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    alarmManager.setExactAndAllowWhileIdle(
        AlarmManager.RTC_WAKEUP,
        nextCalendar.timeInMillis,
        nextPendingIntent
    )
}
  • 若需自定义重复周期(如每周特定日期),可在onReceive中根据规则计算下一次触发时间后重新设置闹钟。

额外注意事项

  • 通知ID不要固定为123,建议使用对应闹钟的请求码作为通知ID,避免新通知覆盖旧通知;
  • Android13+需主动申请POST_NOTIFICATIONS权限,需在代码中处理权限请求流程;
  • 根据Android版本选择合适的PendingIntent flag,Android12及以上优先使用FLAG_IMMUTABLE,若需修改Intent内容则用FLAG_MUTABLE。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:07:45