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

Android如何设置多个同时间触发、各自发送独立通知的闹钟

问题根因分析
  • 前台服务通知ID固定导致覆盖:AlarmService的onStartCommand方法中调用startForeground(1, notification)时使用了固定值1作为通知ID,同一服务多次调用该方法时,同ID的通知会直接覆盖之前的通知,无法生成独立的专属通知,对应闹钟状态也会被覆盖。
  • 未传递闹钟唯一标识:启动AlarmService的Intent没有携带alarmId等唯一参数,就算多个闹钟触发服务调用,也无法区分每个请求对应的闹钟,无法跳转到对应专属的Activity页面。
  • PendingIntent Flag存在兼容问题:调用PendingIntent.getBroadcast时最后参数传了0,Android 12及以上版本要求明确指定PendingIntent的可变性,否则会出现匹配异常,导致同时间的PendingIntent被覆盖。
  • 通知通道使用随机值:创建通知时用随机值作为通道ID,Android 8.0及以上系统要求通知通道必须提前创建,随机ID会导致通知无法正常弹出。
修复步骤

1. 修改闹钟调度的PendingIntent配置

确保每个闹钟的PendingIntent唯一,添加明确兼容Flag,同时携带alarmId参数:

public void schedule(Context context) {
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, AlarmBroadcastReceiver.class);
    // 携带闹钟唯一ID,后续传递给服务
    intent.putExtra("alarmId", alarmId);
    // 适配Android 12+,不需要修改Intent内容用FLAG_IMMUTABLE,需要修改则用FLAG_MUTABLE
    int flag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0;
    PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, alarmId, intent, flag);

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, hour);
    calendar.set(Calendar.MINUTE, minute);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    alarmManager.setExact(
            AlarmManager.RTC_WAKEUP,
            calendar.getTimeInMillis(),
            alarmPendingIntent
    );
}

2. 修改广播接收器,传递闹钟参数给服务

广播接收器收到触发事件后,将alarmId等参数传递给AlarmService:

private void startAlarmService(Context context, Intent intent) {
    Intent intentService = new Intent(context, AlarmService.class);
    // 传递闹钟ID和其他自定义参数
    intentService.putExtra("alarmId", intent.getIntExtra("alarmId", -1));
    Log.println(Log.DEBUG, "DEBUG", "************Alarm Broadcast Receiver**********");
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(intentService);
    } else {
        context.startService(intentService);
    }
}

3. 重构AlarmService,支持多闹钟并行处理

@Override
public void onCreate() {
    super.onCreate();
    mediaPlayer = MediaPlayer.create(this, R.raw.alarm);
    mediaPlayer.setLooping(true);
    vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // 获取当前请求对应的闹钟ID
    int alarmId = intent.getIntExtra("alarmId", -1);
    // 跳转Activity时携带alarmId,让RingActivity区分是哪个闹钟的操作
    Intent notificationIntent = new Intent(this, RingActivity.class);
    notificationIntent.putExtra("alarmId", alarmId);
    // 用alarmId作为请求码,保证PendingIntent唯一
    int requestCode = alarmId;
    int flag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0;
    PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, notificationIntent, flag);

    // 用alarmId作为通知ID,保证唯一不覆盖
    int notificationId = alarmId;
    // 使用提前创建的固定通知通道ID
    String channelId = "alarm_notify_channel";
    Notification notification = new NotificationCompat.Builder(this, channelId)
            .setContentTitle("闹钟提醒")
            .setContentText("你设置的闹钟已触发")
            .setSmallIcon(R.drawable.pill)
            .setContentIntent(pendingIntent)
            .setOngoing(true) // 通知常驻,无法手动划掉
            .build();

    if(!mediaPlayer.isPlaying()) {
        mediaPlayer.start();
        long[] pattern = { 0, 100, 1000 };
        vibrator.vibrate(pattern, 0);
    }

    // 用alarmId作为前台服务的通知ID,唯一不覆盖
    startForeground(notificationId, notification);
    return START_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    mediaPlayer.stop();
    vibrator.cancel();
}

4. 补充配置

提前在应用启动时创建ID为alarm_notify_channel的通知通道,Android 8.0及以上系统必须配置该通道才能正常弹出通知;RingActivity中获取传入的alarmId,处理完当前闹钟的关闭/贪睡逻辑后,再判断是否还有未处理的同时间闹钟,确认所有闹钟处理完毕后再停止AlarmService和响铃逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 03:42:01