调用startActivity(Intent)时每次都会销毁Activity,原因是什么?
嘿,我来帮你捋捋这个Activity中重复Alarm设置的问题~
首先你提到的onDestroy()调用时机确实很关键——系统只有在内存极度紧张的时候才会触发它,所以绝对不能依赖这个方法去取消Alarm,这一点你抓得非常准。
结合你给出的startEMAAlarm()代码片段,我整理几个核心注意点:
触发时间的边界处理:你代码里把Calendar设为每天8:30,但如果当前时间已经过了这个点,第一次Alarm会直接推迟到第二天。如果想让当天没过8:30就触发当天的,过了就触发第二天的,得加个判断逻辑:
if (cal.getTimeInMillis() < System.currentTimeMillis()) { cal.add(Calendar.DAY_OF_MONTH, 1); // 已过触发时间,顺延至次日 }避免重复创建Alarm:
onCreate()可能会被多次调用(比如屏幕旋转、Activity重建),如果每次都重新设置,会导致多个重复的Alarm同时运行。建议设置前先取消同类型的旧Alarm:// 用固定的requestCode创建PendingIntent,确保能匹配到旧的实例 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 设置前先取消旧Alarm alarmMgr.cancel(pendingIntent); // 再设置新的Alarm适配不同Android版本的Alarm精度:从API 19开始,
setRepeating()会变成非精准触发(系统为省电调整时间)。如果需要精准的每日提醒,建议用setExactAndAllowWhileIdle()配合广播接收器,每次触发后再重新设置下一次Alarm:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmMgr.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent); } else { alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); }不要依赖
onDestroy()取消Alarm:既然系统不一定会调用它,那如果需要在用户退出App时停止Alarm,可以在用户主动点击退出按钮的逻辑里主动取消,或者用Service/WorkManager来统一管理Alarm的生命周期。
最后给你补全startEMAAlarm()的完整示例:
public void startEMAAlarm(){ Log.d(TAG, "startEMAAlarm: in start ema alarm"); Calendar cal = Calendar.getInstance(); // 设定每日8:30触发 cal.set(Calendar.HOUR_OF_DAY, 8); cal.set(Calendar.MINUTE, 30); cal.set(Calendar.SECOND, 0); // 处理当前时间已过触发点的情况 if (cal.getTimeInMillis() < System.currentTimeMillis()) { cal.add(Calendar.DAY_OF_MONTH, 1); } AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(this, YourAlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 先取消旧Alarm,避免重复 alarmMgr.cancel(pendingIntent); // 根据系统版本选择合适的Alarm设置方式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmMgr.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent); } else { alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); } }
另外要注意,Android 8.0+对后台广播有限制,你的YourAlarmReceiver如果是静态注册在Manifest里,可能无法正常接收广播,建议改用动态注册或者通过PendingIntent启动前台服务来处理通知逻辑。
内容的提问来源于stack exchange,提问作者gwicks

