Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/218.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何使用报警以外的方式安排任务,并且该任务应易于测试,即使在设备重新启动后也应运行?_Android_Broadcastreceiver_Sharedpreferences - Fatal编程技术网

Android 如何使用报警以外的方式安排任务,并且该任务应易于测试,即使在设备重新启动后也应运行?

Android 如何使用报警以外的方式安排任务,并且该任务应易于测试,即使在设备重新启动后也应运行?,android,broadcastreceiver,sharedpreferences,Android,Broadcastreceiver,Sharedpreferences,我必须运行一个接收器,该接收器只在一周中的特定日期的特定持续时间内接收操作用户在场。在这里,持续时间和工作日由用户选择 我尝试使用首选项和AlarmManager来实现这一点,我非常希望使用报警和首选项以外的其他方法来实现这一点,因为使用在用户选择的持续时间之后运行的每周报警以及针对用户选择的持续时间来测试报警变得非常困难星期天 除了使用报警和首选项之外,还有其他方法可以完成这项工作吗。一个代码示例将非常有用 有关更多详细信息,这里是我使用带有首选项的报警的方法: 现在,首先,我让用户通过一

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

我尝试使用
首选项
AlarmManager
来实现这一点,我非常希望使用
报警
首选项
以外的其他方法来实现这一点,因为使用在用户选择的持续时间之后运行的每周报警以及针对用户选择的持续时间来测试报警变得非常困难星期天

除了使用
报警
首选项
之外,还有其他方法可以完成这项工作吗。一个代码示例将非常有用



有关更多详细信息,这里是我使用带有
首选项的
报警
的方法:

现在,首先,我让用户通过一个
对话框片段
选择小时和分钟来计算开始时间,其中
时间选择器对话框
被放大,以便用户可以选择开始时间,我在
onTimeSet()中得到
小时
分钟
callback,然后我找出接收器的启动时间

代码片段类似于这样,用于从hrsmin计算以毫秒为单位的开始时间:

    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("LockDurationInMillis", minutesinmillis);
然后使用
AlarmManager
设置一个警报,该警报将设置一个名为
PeriodicLockService
BroadcastReceiver
作为一个
PendingEvent
,它将击中其接收器

此处设置报警的代码:

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);
}
现在在
periodicklockservice
中,当点击
onReceive
时,我首先使用
首选项检查用户是否已设置今天运行的内容,如下所示:

//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);
    }
}
但问题是,这似乎并不总是有效,而且很难从运行我的应用程序的用户设备获取日志


除了使用
报警
首选项

之外,还有其他方法可以完成此工作吗?我建议您使用Firebase作业调度器。它是一个用于在Android应用程序中安排后台作业的库。它提供了一个与JobScheduler兼容的API,可在所有安装了Google Play服务的Android最新版本(API级别9+)上运行


有关如何在应用程序中使用它的说明,请单击。

Android Job

  • Android作业抽象出您希望用于执行后台工作的实现
  • 根据需求,此库决定使用哪个API来运行作业
  • 它提供了JobScheduler、GCMNetworkManager和AlarmManager的所有功能的超集
  • Android Nougat的所有功能都是向后兼容的
  • 少用样板
实现Android作业非常简单

API包括以下类/接口

  • 作业:作业需要扩展此类并重写onRunJob方法。繁重的工作在这里完成。您必须从此方法返回一个结果,以便系统知道是否稍后尝试运行您的作业
  • JobRequest:您可以通过使用构建器构造函数创建JobRequest并传递作业标记来安排作业
  • JobCreator:JobCreator的行为类似于工厂,根据作业标记提供作业。具体的JobCreator类必须实现JobCreator接口并重写create方法
  • JobManager:JobManager类用作入口点。在使用此类之前,必须将其初始化为singleton。JobManager接受上下文。创建实例后,必须将JobCreator添加到JobManager
  • 如果你有兴趣阅读更多,请阅读这篇精彩的文章


    感谢拉杰什·帕塔纳克(Rajesh Pattanaik)撰写本文的人

    您可以使用作业调度器

    public class MyJobService extends JobService {
    
        @Override
        public boolean onStartJob(JobParameters params) {
            Toast.makeText(this, "testing", Toast.LENGTH_LONG).show();
            Log.i("sid", "Job scheduler called");
            jobFinished(params, true);
            return true;
        }
    
        @Override
        public boolean onStopJob(JobParameters params) {
            return false;
        }
    }
    
    在活动中调用以下方法

    private void constructJob(){
            JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, new ComponentName(this, MyJobService.class));
    
            builder.setMinimumLatency(60000)
                    .setBackoffCriteria(10000,JobInfo.BACKOFF_POLICY_LINEAR)
                    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
                    .setPersisted(true);
    
            mJobScheduler.schedule(builder.build());
        }
    
    确保调用builder.setPersisted(true),以便在重新启动后运行服务。另一件需要注意的事情是,这段代码在Android N(API 24)或以上的API上运行良好,但是,对于API 21-23,它调用builder.setPeriodic(60000)而不是builder.setMinimumLatency(60000)

    更新 要在API 15及以上版本上运行作业调度器,请使用JobSchedulerCompat

    在gradle文件中添加以下依赖项-

    compile 'me.tatarka.support:jobscheduler:0.1.1'
    

    我认为这对我来说不太合适。比如说我必须安排周一、周三和周六的活动。。如何使用Firebase作业调度器来实现这一点。或者简单地说,如何为选定的确切日期和时间安排一些工作?你能展示一些代码片段来支持你的答案吗?@shadygoneinsane我认为你是对的,我们不能使用Firebase作业调度器为特定时间安排作业:(那么我如何使用这个库为精确选择的日期和时间安排一些工作呢?文章中有一个简单的示例,请尝试;
    setPeriodic()
    可用于调度
    作业
    至少15分钟,也可调度
    作业管理器.instance().getConfig().setAllowsMallerIntervalsFormarshAllow(true)
    不能用于上面的Android M,因此很难在上面进行测试。我正在测试它,发现它工作得很好,我用3-4台设备进行了测试。。我会再测试一些。谢谢你的回答。我想要一个Api 15及以上版本的解决方案!!我读过关于向后兼容性库的文章,发现这一点:1)不推荐使用-一开始就写得很清楚。为什么我要浪费时间使用一些贬值的东西并阅读第二点-阅读-2)这个库没有经过很好的测试,所以我建议现在不要在生产中使用。无法保证这不会耗尽电池或导致设备爆炸。我会使用报警管理
    compile 'me.tatarka.support:jobscheduler:0.1.1'