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

AlarmManager未按指定时间触发告警问题求助

问题:AlarmManager设置指定时间通知,却立即触发

我使用AlarmManager在指定时间发送通知,验证过时间戳对应正确的目标时间,但设置后几秒内告警就触发了。已配置所有所需权限,相关代码如下:

BroadcastReceiver代码

public class NotificationReceiver extends BroadcastReceiver {
    private static final int REQUEST_CODE_PERMISSIONS = 1;
    private static final int NOTIFICATION_ID = 0;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("NotificationReceiver", "Sending notification");

        // Check and request permissions if needed
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(context, Manifest.permission.WAKE_LOCK) != PackageManager.PERMISSION_GRANTED) {
            // Request permissions dynamically if not granted
            ActivityCompat.requestPermissions((Activity) context,
                    new String[]{Manifest.permission.VIBRATE, Manifest.permission.WAKE_LOCK},
                    REQUEST_CODE_PERMISSIONS);

            return;
        }

        createNotificationChannel(context);

        Intent notificationActivity = new Intent(context, NotificationActivity.class);
        notificationActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationActivity, PendingIntent.FLAG_IMMUTABLE);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "ProjectNotification")
                .setContentTitle("Hi")
                .setContentText("Hello there")
                .setAutoCancel(true)
                .setSmallIcon(R.drawable.notifications)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setContentIntent(pendingIntent);

        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
        notificationManagerCompat.notify(NOTIFICATION_ID, builder.build());
    }

    private void createNotificationChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("ProjectNotification",
                    "Project Notifications", NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("Channel for project notifications");
            channel.enableLights(true);
            channel.setLightColor(Color.BLUE);
            channel.enableVibration(true);

            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
}

设置通知的代码

private void setNotification(long timeInMillis) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, NotificationReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_IMMUTABLE);

        try{
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
        }
        catch (SecurityException e){
            Log.e("setNotification", e.toString());
            try{
                alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
            }
            catch (SecurityException ex){
                Log.e("setNotification", ex.toString());
                alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
            }
        }
}

时间选择器代码

private void onClickTimeDialog(View view) {

        EditText editText = (EditText) view;

        Calendar calendar1 = Calendar.getInstance();

        int hour = calendar1.get(Calendar.HOUR);
        int minute = calendar1.get(Calendar.MINUTE);

        // Creating the grey background.
        View transparentGreyView = new View(context);
        transparentGreyView.setBackgroundColor(Color.parseColor("#80808080"));
        ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
        );
        transparentGreyView.setLayoutParams(layoutParams);
        transparentGreyView.setTag("greyBackground");
        popConstLayout.addView(transparentGreyView);


        TimePickerDialog timePickerDialog = new TimePickerDialog(context,
                new TimePickerDialog.OnTimeSetListener() {
                    @Override
                    public void onTimeSet(TimePicker view12, int hourOfDay, int minute12) {
                        if (hourOfDay != 12) {
                            String timeShort = hourOfDay + ":" + minute12 + " AM";
                            @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa");
                            try {
                                editText.setHint(sdf.format(Objects.requireNonNull(sdf.parse(timeShort))));
                            } catch (ParseException e) {
                                throw new RuntimeException(e);
                            }
                        } else {
                            String timeShort = hourOfDay + ":" + minute12 + " PM";
                            @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa");
                            try {
                                editText.setHint(sdf.format(Objects.requireNonNull(sdf.parse(timeShort))));
                            } catch (ParseException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }, hour, minute, false);
        timePickerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialogInterface) {
                // Removing the grey background on dismiss.
                View removeView = popConstLayout.findViewWithTag("greyBackground");

                if (removeView != null) {
                    popConstLayout.removeView(removeView);
                }
            }
        });
        timePickerDialog.show();

    }

从时间选择器获取时间并设置告警的代码

String time = "04:00 PM"; //example;
int hour = Integer.parseInt(time.split(":")[0]);
int minute = Integer.parseInt(time.split(":")[1].split(" ")[0]);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
setNotification(calendar.getTimeInMillis());

已配置的权限

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

问题原因及解决方案

核心问题:目标时间早于当前时间

当你设置的timeInMillis对应的时间已经早于当前系统时间时,AlarmManager会立即触发告警。比如你在下午5点设置了当天上午10点44分的闹钟,系统就会立刻执行。

修复代码

修改获取时间并设置告警的逻辑,添加时间检查:

String time = "04:00 PM"; //example;
int hour = Integer.parseInt(time.split(":")[0]);
int minute = Integer.parseInt(time.split(":")[1].split(" ")[0]);

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);

// 检查设置的时间是否已过,如果已过则自动调整到第二天
if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
    calendar.add(Calendar.DAY_OF_YEAR, 1);
}

setNotification(calendar.getTimeInMillis());

其他潜在问题修复

1. 时间选择器的12小时制转换错误

你的时间选择器手动拼接时间字符串的逻辑存在错误,比如用户选择下午1点时,会错误拼接成1:xx AM,导致解析出凌晨1点的时间。直接用Calendar处理更可靠:

@Override
public void onTimeSet(TimePicker view12, int hourOfDay, int minute12) {
    @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa");
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
    calendar.set(Calendar.MINUTE, minute12);
    editText.setHint(sdf.format(calendar.getTime()));
}

2. PendingIntent复用问题

如果之前存在相同的PendingIntent,设置新闹钟可能会触发旧的任务。可以在创建PendingIntent时添加FLAG_UPDATE_CURRENT,或者使用不同的requestCode区分不同闹钟:

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, 
        PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:14:55