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

应用从最近任务列表关闭后AlarmManager失效及多闹钟添加咨询

问题解决方案

一、应用从最近任务移除后闹钟失效的问题

核心原因

应用被系统杀死后,已设置的AlarmManager闹钟可能被清除,且当前onTaskRemoved仅重启服务,未恢复原有的闹钟配置;同时部分Android版本和厂商后台限制会阻止未授权的闹钟触发。

修复方案

  1. 在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方法,筛选出未过期的提醒记录。

  2. 适配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);
        }
    }
    
  3. 优化Service的Manifest配置
    添加前台服务类型,并设置stopWithTask为false,避免任务移除时自动停止服务:

    <service android:name=".Reminder.AlarmService"
             android:foregroundServiceType="mediaPlayback"
             android:stopWithTask="false"/>
    
  4. 处理厂商后台限制
    国内厂商(小米、华为、OPPO等)有独立的后台管控机制,需在应用内添加引导页,提示用户将应用加入后台保护白名单。

二、多闹钟支持问题

当前代码不支持多个闹钟,原因是设置闹钟时PendingIntent的requestCode固定为0,新闹钟会覆盖旧的。

实现多闹钟的方法

  1. 使用唯一的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();
        }
    }
    
  2. 更新数据库插入逻辑
    修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:23:07