三星Galaxy Z Flip3更新后AlarmManager失效问题求助
我的应用在三星Galaxy Z Flip3上原本运行正常,系统更新后出现异常:只有保持手机唤醒且应用处于前台(需持续充电,完全不可行)时,闹钟通知才能正常触发。此前通过“电池和设备维护”设置应用永不休眠可解决类似问题,但这次该设置似乎被系统忽略。
以下是我编写的setAlarm代码,包含多种已尝试但注释掉的方案:
fun setAlarm(timeInMillis: Long) { val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(this, MyAlarm::class.java) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_MUTABLE) //alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent) alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent) //alarmManager!!.set(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent) /* alarmManager!!.setAlarmClock( AlarmManager.AlarmClockInfo( timeInMillis, null ), pendingIntent ) */ /* if (Build.VERSION.SDK_INT < 23) { if (Build.VERSION.SDK_INT >= 19) { if(System.currentTimeMillis()<startTime) alarmManager.setExact(AlarmManager.RTC_WAKEUP, startTime, pendingIntent); } else { if(System.currentTimeMillis()<startTime) alarmManager.set(AlarmManager.RTC_WAKEUP, startTime, pendingIntent); } } else { if(System.currentTimeMillis()<startTime) alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, startTime, pendingIntent); } */ toastGeneral("""Alarm is set""") }
补充发现
设置闹钟后按电源键熄屏,数小时后闹钟仍能正常触发;但设置闹钟后返回主屏幕或切换至其他应用,仅几分钟后闹钟就无法触发,再次打开应用时则立即执行闹钟逻辑。想知道这两种场景下应用状态的差异,以及如何让闹钟在应用处于此类状态时正常触发。
后续跟进(2023年9月15日)
发布问题已过去一个月,超100人浏览但无人回复。求分享在三星One UI 5.1.1系统的Flip手机上能正常唤醒应用的Kotlin代码。
解决方案与分析
三星系统更新的改动推测
三星One UI 5.1.1大概率进一步收紧了后台应用的资源管控策略:针对切换到后台而非直接熄屏的应用,系统可能将其标记为「活跃后台闲置应用」,直接降低了AlarmManager的触发优先级,导致原有的“永不休眠”设置被覆盖。
可行修复方案
改用
setAlarmClock提升优先级
相比setExactAndAllowWhileIdle,setAlarmClock拥有系统最高级别的闹钟优先级,系统会确保这类闹钟触发,甚至提前唤醒系统。修改后的核心代码:fun setAlarm(timeInMillis: Long) { val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(this, MyAlarm::class.java) val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_MUTABLE) // 使用setAlarmClock强制系统优先处理 val alarmClockInfo = AlarmManager.AlarmClockInfo(timeInMillis, null) alarmManager.setAlarmClock(alarmClockInfo, pendingIntent) toastGeneral("Alarm is set") }注:该方法会在系统时钟应用中显示闹钟条目,属于正常系统行为。
确认并申请精确闹钟权限
Android 12及以上版本需要SCHEDULE_EXACT_ALARM权限才能使用精确闹钟,先在AndroidManifest.xml中添加:<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />再在运行时主动请求权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager if (!alarmManager.canScheduleExactAlarms()) { startActivity(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)) } }优化PendingIntent唯一性
原代码中PendingIntent的requestCode固定为0,多次设置闹钟可能导致旧意图被覆盖。建议使用唯一ID生成requestCode:val requestCode = timeInMillis.hashCode() // 或自定义唯一标识 val pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)补充后台保活设置
除了“永不休眠”,还需检查以下设置:- 开启应用的「后台活动」权限:在应用设置的「电池」选项中,确保后台活动处于开启状态;
- 添加低优先级前台服务:若应用核心依赖闹钟,可启动一个无UI的前台服务,降低被系统杀死的概率。
场景差异解析
- 熄屏场景:系统进入深度休眠,
AlarmManager.RTC_WAKEUP会直接唤醒系统处理广播,此时应用处于「后台休眠」状态,系统会优先响应闹钟触发; - 切换后台场景:应用处于「活跃后台」状态,系统会对这类应用进行资源节流,推迟非高优先级任务的执行,直到应用回到前台。通过
setAlarmClock提升优先级可绕过该限制。
内容的提问来源于stack exchange,提问作者Tom Park

