android – 如何使用Alarms之外的其他东西来安排任务,它应该很容易测试,甚至应该在设备重启后运行?

我必须运行一个接收器,该接收器仅在一周中的特定日期的特定持续时间内接收动作USER_PRESENT.这里,持续时间和工作日由用户选择.

我尝试过使用带有AlarmManager的Preferences来实现这一点,我非常希望使用除了Alarms with Preferences之外的其他东西来实现这一点,因为在用户选择的持续时间和用户选择之后运行的每周警报测试警报变得非常困难工作日.

除了使用警报和首选项之外,还有其他方法可以完成这项工作.代码示例真有用!!

有关详细信息,请参阅使用“首选项”和“首选项”的方法:

现在我首先通过允许用户通过DialogFragment选择小时和分钟来计算开始时间,其中TimePickerDialog被夸大,以便用户可以选择开始时间,我在onTimeSet()回调中得到hrs和min然后我找出开始接收器关闭的时间.

Code Snippet用于计算从小时和分钟开始的毫秒开始时间:

    Calendar calSet = Calendar.getInstance();
    //setting alarm from current day so that it starts from today onwards
    int day = calSet.get(Calendar.DAY_OF_WEEK);
    calSet.set(Calendar.DAY_OF_WEEK, day);
    calSet.set(Calendar.HOUR_OF_DAY, hrs);
    calSet.set(Calendar.MINUTE, min);
    calSet.set(Calendar.SECOND, 0);
    calSet.set(Calendar.MILLISECOND, 0);
    Long milliseconds = calSet.getTimeInMillis();
    //check if the time is already passed
    Long daily = 24L * 60L * 60L * 1000L;
    if (milliseconds < System.currentTimeMillis()) {
        //if already passed then push it for next day by adding just 24 hrs
        milliseconds = milliseconds + daily;
    }

然后我将这个计算时间以毫秒保存在偏好中:SharedPreferences.Editor.putLong(“PeriodicLockStartTimeInMillis”,毫秒);

现在,我使用checkBoxes存储用户选择的日期,并为每一天的复选框设置首选项

SharedPreferences.Editor.putBoolean("DAYNAME", true);

还存储用户希望接收器工作的持续时间:

SharedPreferences.Editor.putLong("LockDurationInMillis", minutesinmillis);

然后使用AlarmManager设置一个警报,该警报将设置一个名称为PeriodicLockService的BroadcastReceiver作为将触及其接收器的PendingIntent.

此处设置警报的代码:

Intent reminderIntent = new Intent(getActivity(), PeriodicLockService.class);
reminderIntent.setAction("ACTION_REPEATING_ALARM_RECEIVER");
pendingIntent = PendingIntent.getBroadcast(getActivity(), PeriodicLockService.REPEATING_ALARM_UNIQUE_ID, reminderIntent, PendingIntent.FLAG_UPDATE_CURRENT);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
      alarmManager.setExact(AlarmManager.RTC_WAKEUP, milliseconds, pendingIntent);
} else {
      alarmManager.set(AlarmManager.RTC_WAKEUP, milliseconds, pendingIntent);
}

现在,当onReceive被点击时,在PeriodicLockService中,我首先通过使用首选项检查用户是否已设置今天要运行的东西:

//Fetching today's day from Calendar to compare if user has set lock for today
    Calendar calendar = Calendar.getInstance();
    int day = calendar.get(Calendar.DAY_OF_WEEK);

    switch (day) {
        case Calendar.SUNDAY:
            if (Preferences.getBooleanPreference(context, SUN_DAY)) {
                startLockNow(context);
            }
            break;
        case Calendar.MONDAY:
            if (Preferences.getBooleanPreference(context, MON_DAY)) {
                startLockNow(context);
            }
            break;
        case Calendar.TUESDAY:
            if (Preferences.getBooleanPreference(context, TUES_DAY)) {
                startLockNow(context);
            }
            break;
        case Calendar.WEDNESDAY:
            if (Preferences.getBooleanPreference(context, WED_DAY)) {
                startLockNow(context);
            }
            break;
        case Calendar.THURSDAY:
            if (Preferences.getBooleanPreference(context, THURS_DAY)) {
                startLockNow(context);
            }
            break;
        case Calendar.FRIDAY:
            if (Preferences.getBooleanPreference(context, FRI_DAY)) {
                startLockNow(context);
            }
            break;
        case Calendar.SATURDAY:
            if (Preferences.getBooleanPreference(context, SAT_DAY)) {
                startLockNow(context);
            }
            break;
    }

private void startLockNow(Context context) {
    Long lockStartTimeInMillis = Preferences.getLongPreference(context, "PeriodicLockStartTimeInMillis");

    //Update Unlock Time
    Long LockDurationInMillis = Preferences.getLongPreference(context, "LockDurationInMillis"); //End time to stop the Receiver for action USER_PRESENT
    Long newEndTime = lockStartTimeInMillis + LockDurationInMillis;

    //Set Unlocked notification broadcast which also disables the receiver for action `USER_PRESENT`
    Intent intent = new Intent(context, FinalUnlockedBroadcast.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, newEndTime + 1000, pendingIntent);
    } else {
        alarmManager.set(AlarmManager.RTC_WAKEUP, newEndTime + 1000, pendingIntent);
    }

    //update the time for next lock by adding a day
    milliseconds = Preferences.getLongPreference(context, "PeriodicLockStartTimeInMillis") + 24L * 60L * 60L * 1000L;
    Intent reminderIntent = new Intent(context, PeriodicLockService.class);
    reminderIntent.setAction("ACTION_REPEATING_ALARM_RECEIVER");
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REPEATING_ALARM_UNIQUE_ID, reminderIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, milliseconds , pendingIntent);
    } else {
        alarmManager.set(AlarmManager.RTC_WAKEUP, milliseconds , pendingIntent);
    }
}

但问题是,这似乎并不总是有效,并且很难从运行我的应用程序的用户设备获取日志.

除了使用警报和首选项之外,还有其他方法可以完成这项工作

最佳答案 Android-Job
Android-Job repo

> Android-Job抽象出您要用于执行后台工作的实现.
>根据要求,此库决定用于运行作业的API.
>它提供了JobScheduler,GCMNetworkManager和AlarmManager的所有功能的超集.
> Android Nougat的所有功能都向后兼容.
>更少的样板.

实现Android-Job非常简单.

API包括以下类/接口.

>作业:您的作业需要扩展此类并覆盖onRunJob方法.繁重的工作在这里完成.您必须从此方法返回结果,以便系统知道是否尝试稍后运行您的作业.
> JobRequest:您可以通过使用其构建器构造函数创建JobRequest并传递Job标记来计划作业.
> JobCreator:JobCreator就像工厂一样,根据工作标签提供工作.您的具体JobCreator类必须实现JobCreator接口并覆盖create方法.
> JobManager:JobManager类用作入口点.在使用此类之前,必须将其初始化为单例. JobManager采用上下文.创建实例后,您必须将JobCreator添加到JobManager.

如果你有兴趣阅读更多PLZ,请参考这篇很棒的文章Easy Job Scheduling with Android-Job

感谢撰写本文的人Rajesh Pattanaik

点赞