45

Job Scheduler 在 Android Marshmallow 和 Lollipop 设备上按预期工作,但它没有运行并且 Nexus 5x(Android N 预览版)。

调度作业的代码

        ComponentName componentName = new ComponentName(MainActivity.this, TestJobService.class.getName());
        JobInfo.Builder builder;
        builder = new JobInfo.Builder(JOB_ID, componentName);
        builder.setPeriodic(5000);
        JobInfo jobInfo;
        jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobInfo = builder.build();
        int jobId = jobScheduler.schedule(jobInfo);

服务在清单中定义为:

<service android:name=".TestJobService"
            android:permission="android.permission.BIND_JOB_SERVICE" />

有人在 Android N(预览版)上遇到这个问题吗?

4

4 回答 4

60

在 Android Nougat 中,setPeriodic(long intervalMillis)方法调用setPeriodic (long intervalMillis, long flexMillis)用于安排定期作业。

根据文档:

JobInfo.Builder setPeriodic (long intervalMillis, long flexMillis)

指定此作业应以提供的间隔和弹性重复。该作业可以在周期结束时在弹性长度的窗口中随时执行。

intervalMillis long: 此作业将重复的毫秒间隔。强制执行 getMinPeriodMillis() 的最小值。

flexMillis long: 这项工作的毫秒弯曲。Flex 被限制为至少 getMinFlexMillis() 或周期的 5%,以较高者为准。

计划为 5 秒的示例定期作业:

private static final int JOB_ID = 1001;
private static final long REFRESH_INTERVAL  = 5 * 1000; // 5 seconds

JobInfo jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
        .setPeriodic(REFRESH_INTERVAL)
        .setExtras(bundle).build();

上面的代码在 Lollipop & Marshmallow 中运行良好,但是当您在 Nougat 中运行时,您会注意到以下日志:

W/JobInfo: Specified interval for 1001 is +5s0ms. Clamped to +15m0s0ms
W/JobInfo: Specified flex for 1001 is +5s0ms. Clamped to +5m0s0ms

由于我们已将周期性刷新间隔设置为 5 秒,这小于阈值getMinPeriodMillis()。Android Nougat 强制执行getMinPeriodMillis().

作为一种解决方法,如果作业间隔小于 15 分钟,我将使用以下代码定期安排作业。

JobInfo jobInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
      .setMinimumLatency(REFRESH_INTERVAL)
      .setExtras(bundle).build();
} else {
  jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
      .setPeriodic(REFRESH_INTERVAL)
      .setExtras(bundle).build();
}

示例 JobService 示例:

public class SampleService extends JobService {
    @Override public boolean onStartJob(JobParameters params) {
        doSampleJob(params); 
        return true;
    }

    @Override public boolean onStopJob(JobParameters params) {
        return false;
    }

    public void doSampleJob(JobParameters params) {
        // Do some heavy operation
        ...... 
        // At the end inform job manager the status of the job.
        jobFinished(params, false);
    }
}
于 2016-08-04T17:45:12.043 回答
17

如果有人还在努力克服这种情况,

这是 >= Android N 的解决方法(如果您想将定期作业设置为低于 15 分钟)

检查是否只使用了 setMinimumLatency。此外,如果您正在运行需要很长时间的任务,则下一个作业将安排在当前作业完成时间 + PROVIDED_TIME_INTERVAL

.SetPeriodic(long millis) 适用于 Android N 以下的 API 级别

@Override
public boolean onStartJob(final JobParameters jobParameters) {
    Log.d(TAG,"Running service now..");
    //Small or Long Running task with callback
    //Call Job Finished when your job is finished, in callback
    jobFinished(jobParameters, false );

    //Reschedule the Service before calling job finished
    if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
              scheduleRefresh();



    return true;
}

@Override
public boolean onStopJob(JobParameters jobParameters) {
    return false;
}

private void scheduleRefresh() {
  JobScheduler mJobScheduler = (JobScheduler)getApplicationContext()
                    .getSystemService(JOB_SCHEDULER_SERVICE);
  JobInfo.Builder mJobBuilder = 
  new JobInfo.Builder(YOUR_JOB_ID,
                    new ComponentName(getPackageName(), 
                    GetSessionService.class.getName()));

  /* For Android N and Upper Versions */
  if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      mJobBuilder
                .setMinimumLatency(60*1000) //YOUR_TIME_INTERVAL
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
  }

更新: 如果您正在考虑在打盹模式下运行重复作业并考虑 JobScheduler,仅供参考:不允许 JobScheduler 在打盹模式下运行。

我没有讨论打瞌睡,因为我们在谈论 JobScheduler。感谢@Elletlar指出,有些人可能认为即使应用程序处于打盹模式,它也会运行,但事实并非如此。

对于打盹模式,AlarmManager 仍然给出了最好的解决方案。如果您想在确切的时间段内运行定期作业,可以使用setExactAndAllowWhileIdle ( ),如果灵活,可以使用 setAndAllowWhileIdle()。

您还可以使用setAlarmClock(),因为设备总是从闹钟的打盹模式中出来并再次返回打盹模式。另一种方法是使用 FCM。

于 2017-12-11T20:21:29.843 回答
12

我已经找到了我们使用 Nougat 设备所面临的问题的答案。如果需要在 15 分钟内重新安排作业,则牛轧糖设备无法安排作业。

我尝试将间隔时间设为 15 分钟,然后开始每 15 分钟安排一次工作。

作业计划程序代码:

public static void scheduleJob(Context context) {
    ComponentName serviceComponent = new ComponentName(context, PAJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceComponent);
    builder.setPeriodic(15 * 60 * 1000, 5 * 60 *1000);

    JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
    int ret = jobScheduler.schedule(builder.build());
    if (ret == JobScheduler.RESULT_SUCCESS) {
        Log.d(TAG, "Job scheduled successfully");
    } else {
        Log.d(TAG, "Job scheduling failed");
    }
}

工作服务:

public class PAJobService extends JobService {
    private static final String TAG = PRE_TAG + PAJobService.class.getSimpleName();
    private LocationManager mLocationManager;

    public boolean onStartJob(JobParameters params) {
        Log.d(TAG, "onStartJob");
        Toast.makeText(getApplicationContext(), "Job Started", Toast.LENGTH_SHORT).show();
        return false;
    }

    public boolean onStopJob(JobParameters params) {
        Log.d(TAG, "onStopJob");
        return false;
    }
}

简而言之,如果您将间隔时间增加到 15 分钟,代码就会开始工作。

private static final long REFRESH_INTERVAL = 15 * 60 * 1000;

于 2017-09-15T13:13:30.320 回答
1

如果您想定期运行代码少于 15 分钟,那么您可以使用一种棘手的方法。设置你jobFinished()这样

jobFinished(parameters, true);

它将使用重试策略重新安排代码。使用定义自定义退避标准

.setBackoffCriteria();

在生成器中。然后它将定期运行

于 2018-01-19T05:14:10.343 回答