Android闹钟未触发问题排查:原有代码失效求助
我来帮你排查几个可能的疏漏点,这些都是Android闹钟设置中容易踩的坑:
你在创建PendingIntent时用了固定的43作为requestCode:
val pendingIntent = PendingIntent.getService(applicationContext, 43, intent, PendingIntent.FLAG_UPDATE_CURRENT)
如果设置多个闹钟(不管是重复还是单次),同一个requestCode会让新的PendingIntent完全覆盖旧的,最终只有最后一个闹钟能触发,之前设置的全部失效。
解决方法:给每个闹钟生成唯一的requestCode,比如用obj的唯一ID(如果MyObject有标识唯一性的字段),或者结合时间戳:
// 假设obj有唯一id属性,或者用System.currentTimeMillis().toInt()生成临时唯一值 val uniqueRequestCode = obj.id val pendingIntent = PendingIntent.getService(applicationContext, uniqueRequestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT)
在API23+的分支里,你同时执行了setAlarmClock和setExactAndAllowWhileIdle:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val alarmClockInfo = AlarmManager.AlarmClockInfo(cal.timeInMillis, null) alarmManager.setAlarmClock(alarmClockInfo, pendingIntent) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.timeInMillis, pendingIntent)
setAlarmClock是专门用于系统级闹钟(会在锁屏显示闹钟界面)的高优先级API,而你紧接着调用的setExactAndAllowWhileIdle会覆盖前者的设置,尤其是在API25的设备上,系统可能无法正确处理重复的闹钟请求,导致闹钟失效。
解决方法:根据需求二选一,比如只是普通后台闹钟就去掉setAlarmClock的调用;如果需要系统闹钟的特性,就只保留setAlarmClock,不要叠加其他API。
你的MyAlarmIntentService里的TAG写的是:
private val TAG = ContestAlarmIntentService::class.java.simpleName
但类名是MyAlarmIntentService,所以实际日志的TAG是ContestAlarmIntentService,而你可能一直在搜索MyAlarmIntentService的日志,误以为闹钟没触发,但其实服务已经执行了。
解决方法:修正TAG为当前类的名称:
private val TAG = MyAlarmIntentService::class.java.simpleName
虽然API25还没到Android O的严格后台限制,但Nexus 6的7.1.1系统对后台服务的管控已经开始收紧,PendingIntent.getService可能会被系统拒绝执行(尤其是在设备休眠后)。
更可靠的替代方案是用BroadcastReceiver代替IntentService:
- 创建一个
AlarmReceiver继承自BroadcastReceiver - 在
onReceive里处理闹钟逻辑(如果需要耗时操作,可以启动前台服务) - 用
PendingIntent.getBroadcast创建PendingIntent - 在Manifest里注册Receiver:
<receiver android:name=".services.AlarmReceiver" />
虽然日志里的Calendar时间看起来格式正确,但要确保time * 1000对应的是未来的时间。如果设置的是过去的时间,AlarmManager会立刻触发闹钟,但如果你的日志没捕获到(比如TAG错误),就会误以为没触发。可以在设置闹钟前加一个判断:
val currentTime = System.currentTimeMillis() if (cal.timeInMillis <= currentTime) { Log.w("setAlarm", "Alarm time is in the past!") return }
内容的提问来源于stack exchange,提问作者Touhid

