应用从最近任务列表关闭后AlarmManager失效及多闹钟添加咨询
问题解决方案
一、应用从最近任务移除后闹钟失效的问题
核心原因
应用被系统杀死后,已设置的AlarmManager闹钟可能被清除,且当前onTaskRemoved仅重启服务,未恢复原有的闹钟配置;同时部分Android版本和厂商后台限制会阻止未授权的闹钟触发。
修复方案
在
onTaskRemoved中重新注册所有未触发的闹钟
从数据库读取所有待触发的提醒,重新调用设置闹钟的逻辑,确保进程被杀后闹钟能恢复:@Override public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); // 从数据库获取所有未触发的提醒 DBHandler dbHandler = new DBHandler(this); List<Reminder> reminders = dbHandler.getAllPendingReminders(); AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); for (Reminder reminder : reminders) { Intent intent = new Intent(this, AlarmBroadcast.class); intent.putExtra("event", reminder.getTitle()); intent.putExtra("time", reminder.getDate()); intent.putExtra("date", reminder.getTime()); // 使用数据库ID作为唯一requestCode,避免闹钟覆盖 int flags = PendingIntent.FLAG_UPDATE_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { flags |= PendingIntent.FLAG_IMMUTABLE; } PendingIntent pendingIntent = PendingIntent.getBroadcast(this, reminder.getId(), intent, flags); String finalAlarm = reminder.getDate() + " " + reminder.getTime(); DateFormat formatter = new SimpleDateFormat("d-M-yyyy hh:mm"); try { Date alarmDate = formatter.parse(finalAlarm); // 仅设置未来的闹钟 if (alarmDate.getTime() > System.currentTimeMillis()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (am.canScheduleExactAlarms()) { am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmDate.getTime(), pendingIntent); } } else { am.setExact(AlarmManager.RTC_WAKEUP, alarmDate.getTime(), pendingIntent); } } } catch (ParseException e) { e.printStackTrace(); } } stopSelf(); }需在
DBHandler中实现getAllPendingReminders方法,筛选出未过期的提醒记录。适配Android 12+的精确闹钟权限
除了Manifest声明权限,还需在运行时请求用户授权:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { AlarmManager alarmManager = getSystemService(AlarmManager.class); if (!alarmManager.canScheduleExactAlarms()) { Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM); startActivity(intent); } }优化Service的Manifest配置
添加前台服务类型,并设置stopWithTask为false,避免任务移除时自动停止服务:<service android:name=".Reminder.AlarmService" android:foregroundServiceType="mediaPlayback" android:stopWithTask="false"/>处理厂商后台限制
国内厂商(小米、华为、OPPO等)有独立的后台管控机制,需在应用内添加引导页,提示用户将应用加入后台保护白名单。
二、多闹钟支持问题
当前代码不支持多个闹钟,原因是设置闹钟时PendingIntent的requestCode固定为0,新闹钟会覆盖旧的。
实现多闹钟的方法
使用唯一的requestCode
用数据库中提醒记录的自增ID作为requestCode,确保每个闹钟的PendingIntent唯一:// 修改setAlarm方法,传入数据库ID private void setAlarm(String text, String date, String time, int reminderId) { AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(getApplicationContext(), AlarmBroadcast.class); intent.putExtra("event", text); intent.putExtra("time", date); intent.putExtra("date", time); int flags = PendingIntent.FLAG_UPDATE_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { flags |= PendingIntent.FLAG_IMMUTABLE; } // 使用reminderId作为requestCode PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), reminderId, intent, flags); String finalAlarm = date + " " + time; DateFormat formatter = new SimpleDateFormat("d-M-yyyy hh:mm"); try { Date alarmDate = formatter.parse(finalAlarm); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (am.canScheduleExactAlarms()) { am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmDate.getTime(), pendingIntent); } } else { am.setExact(AlarmManager.RTC_WAKEUP, alarmDate.getTime(), pendingIntent); } } catch (ParseException e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }更新数据库插入逻辑
修改DBHandler的addreminder方法,返回插入记录的ID:public long addreminder(String title, String date, String time) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("title", title); values.put("date", date); values.put("time", time); long id = db.insert("reminders", null, values); db.close(); return id; }然后在
processinsert中获取ID并传入setAlarm:@RequiresApi(api = Build.VERSION_CODES.O) private void processinsert(String title, String date, String time) { long reminderId = dbHandler.addreminder(title, date, time); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { setAlarm(title, date, time, (int) reminderId); } Toast.makeText(getApplicationContext(), "提醒已添加", Toast.LENGTH_SHORT).show(); }
其他代码修正
- NotificationMessage.java代码重复问题:当前提供的
NotificationMessage.java与AlarmBroadcast.java代码完全一致,需修正为Activity类:public class NotificationMessage extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_notification_message); String message = getIntent().getStringExtra("message"); TextView tvMessage = findViewById(R.id.tv_message); tvMessage.setText(message); } }
内容的提问来源于stack exchange,提问作者user19705717
相关产品推荐
相关产品推荐

