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
相关产品推荐
相关产品推荐

