Android中Activity未启动时能否运行Java代码实现后台闹钟功能
解决方案
Android系统自带的AlarmManager服务专门处理定时触发任务,就算应用未启动、进程被杀也能正常触发,完全符合你的需求,不需要自己维护循环检查时间的逻辑,具体实现步骤如下:
步骤1:修正并改造DateTimeAlarm类
你代码里的bool是其他语言的写法,Java中对应boolean,同时实现Parcelable接口方便组件间传参:
import android.os.Parcel; import android.os.Parcelable; public class DateTimeAlarm implements Parcelable { public int day; public int hour; public int minute; public boolean alarmed = false; public DateTimeAlarm(int day, int hour, int minute) { this.day = day; this.hour = hour; this.minute = minute; } protected DateTimeAlarm(Parcel in) { day = in.readInt(); hour = in.readInt(); minute = in.readInt(); alarmed = in.readByte() != 0; } public static final Creator<DateTimeAlarm> CREATOR = new Creator<DateTimeAlarm>() { @Override public DateTimeAlarm createFromParcel(Parcel in) { return new DateTimeAlarm(in); } @Override public DateTimeAlarm[] newArray(int size) { return new DateTimeAlarm[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(day); dest.writeInt(hour); dest.writeInt(minute); dest.writeByte((byte) (alarmed ? 1 : 0)); } }
步骤2:新建广播接收器放置你的业务逻辑
广播接收器可以在应用未启动的状态下被系统唤起,你原来的时间校验、Alarm()函数逻辑都放在这里即可:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import java.util.Calendar; public class AlarmTriggerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 获取你设置闹钟时传入的目标时间参数 DateTimeAlarm targetTime = intent.getParcelableExtra("target_alarm"); if (targetTime == null) return; // 系统触发广播时再做一次时间校验,匹配你的原有逻辑 Calendar current = Calendar.getInstance(); int currentDay = current.get(Calendar.DAY_OF_WEEK); // 注意Calendar默认周日为1,如果你是自定义的day计数规则自行对应转换 int currentHour = current.get(Calendar.HOUR_OF_DAY); int currentMinute = current.get(Calendar.MINUTE); if (!targetTime.alarmed && currentDay == targetTime.day && currentHour == targetTime.hour && currentMinute >= targetTime.minute) { targetTime.alarmed = true; // 执行你的闹钟业务逻辑 Alarm(); } } private void Alarm() { // 把你原来Alarm()函数的逻辑(响铃、弹通知、跳转页面等)写在这里 } }
步骤3:在AndroidManifest.xml中注册广播接收器
不注册的话系统无法找到对应的接收器,在<application>标签内添加以下代码:
<receiver android:name=".AlarmTriggerReceiver" android:exported="false" />
步骤4:用户设置闹钟时调用AlarmManager注册定时任务
这段代码放在你设置闹钟的交互逻辑里即可(比如用户点击「保存闹钟」按钮的回调中):
import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import java.util.Calendar; public void setAlarm(Context context, DateTimeAlarm targetTime) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmTriggerReceiver.class); intent.putExtra("target_alarm", targetTime); // 计算闹钟触发的时间戳 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.DAY_OF_WEEK, targetTime.day); calendar.set(Calendar.HOUR_OF_DAY, targetTime.hour); calendar.set(Calendar.MINUTE, targetTime.minute); calendar.set(Calendar.SECOND, 0); // 如果设置的时间已经过了,自动顺延一周(如果是单次闹钟可自行判断提示用户) if (calendar.before(Calendar.getInstance())) { calendar.add(Calendar.DATE, 7); } // 每个闹钟要生成唯一的requestCode,避免覆盖 int requestCode = targetTime.day * 10000 + targetTime.hour * 100 + targetTime.minute; PendingIntent pendingIntent = PendingIntent.getBroadcast( context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // 设置闹钟,RTC_WAKEUP参数表示就算设备休眠也会唤醒触发 alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent ); }
补充注意事项
- Android 6.0及以上的低电耗模式会限制普通闹钟触发,使用
setExactAndAllowWhileIdle可以保证在低电耗模式下也能正常触发 - 如果是单次闹钟,触发后记得调用
alarmManager.cancel(pendingIntent)取消定时任务,避免重复触发 - 如果需要闹钟触发时打开Activity,在
Alarm()方法里加启动Activity的Intent即可,注意要添加FLAG_ACTIVITY_NEW_TASK标记
内容的提问来源于stack exchange,提问作者Erfan Games
相关产品推荐
相关产品推荐

