Android中Alarm Manager仅触发最后一个已调度任务的问题
解决Android AlarmManager多任务仅最后一个执行的问题
这个问题我太熟了!核心原因其实很简单:你每次创建PendingIntent时都用了相同的requestCode(也就是那个0),系统会把这些视为同一个PendingIntent,后面创建的直接覆盖掉前面的,自然就只有最后一个任务能执行了。
修复步骤
1. 给每个Alarm分配唯一的requestCode
PendingIntent的第二个参数是requestCode,必须保证每个Alarm的这个值唯一。你可以用sid和cid组合生成一个唯一标识,比如它们的哈希值,或者如果是数字类型直接转成整数:
// 用sid+cid的哈希值生成唯一requestCode int uniqueRequestCode = (sid + cid).hashCode();
2. 增强Intent的唯一性(可选但推荐)
系统判断Intent是否相同是看action、data、category等字段,和extra无关。所以即使requestCode不同,如果Intent的核心字段一致,也可能出现意外覆盖。可以给每个Intent加一个唯一的data:
intentToFire.setData(Uri.parse("alarm://" + sid + "/" + cid));
3. 修复后的完整代码
private void triggerAlarm(int hr, int min, String sid, String cid) { Intent intentToFire = new Intent(getApplicationContext(), AlarmBroadcastReceiver.class); intentToFire.putExtra("cid", cid); intentToFire.putExtra("sid", sid); intentToFire.setAction(ACTION_ALARM); // 添加唯一data,避免Intent被误判为相同 intentToFire.setData(Uri.parse("alarm://" + sid + "/" + cid)); // 生成唯一requestCode int uniqueRequestCode = (sid + cid).hashCode(); // 根据Android版本选合适的Flag,Android12+推荐用FLAG_IMMUTABLE int pendingIntentFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; PendingIntent alarmIntent = PendingIntent.getBroadcast( getApplicationContext(), uniqueRequestCode, intentToFire, pendingIntentFlag ); AlarmManager alarmManager = (AlarmManager) getApplicationContext() .getSystemService(Context.ALARM_SERVICE); Calendar c = Calendar.getInstance(); c.set(Calendar.HOUR_OF_DAY, hr); c.set(Calendar.MINUTE, min); c.set(Calendar.SECOND, 0); long alarmTime = c.getTimeInMillis(); // 处理时间已过的情况:如果设置的时间在当前时间之前,自动延后一天 if (alarmTime < System.currentTimeMillis()) { alarmTime += 24 * 60 * 60 * 1000; } // 针对Android6.0+的Doze模式,可选使用setExactAndAllowWhileIdle确保触发 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, alarmIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, alarmIntent); } }
额外注意点
- PendingIntent Flag选择:
FLAG_UPDATE_CURRENT会更新已存在的PendingIntent的extra数据;FLAG_IMMUTABLE是Android12+推荐的不可变Flag,防止Intent被篡改;如果要完全新建一个不关联旧的,用FLAG_CANCEL_CURRENT。 - Doze模式适配:Android6.0引入的Doze模式会限制Alarm触发,如果你需要在低电量模式下也能执行任务,要用
setExactAndAllowWhileIdle或setAndAllowWhileIdle,但这两个方法有调用次数限制,按需使用。
内容的提问来源于stack exchange,提问作者imi
相关产品推荐
相关产品推荐

