Job Scheduler 不是 运行 Android N
Job Scheduler not running on Android N
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(预览版)上遇到过这个问题吗?
在 Android 牛轧糖 setPeriodic(long intervalMillis)
method call makes use of setPeriodic (long intervalMillis, long flexMillis)
中安排定期作业。
根据文档:
JobInfo.Builder setPeriodic (long intervalMillis, long flexMillis)
Specify that this job should recur with the provided interval and
flex. The job can execute at any time in a window of flex length at
the end of the period.
intervalMillis long:
Millisecond interval for which this job will repeat. A minimum value of getMinPeriodMillis() is enforced.
flexMillis long:
Millisecond flex for this job. Flex is clamped to be at least getMinFlexMillis() or 5 percent of the period, whichever is higher.
计划 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 牛轧糖强制执行 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);
}
}
我找到了我们面临的牛轧糖设备问题的答案。
如果作业需要在 15 分钟内重新安排,Nougat 设备将无法安排作业。
我尝试将间隔时间设置为 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;
如果有人还在努力克服这种情况,
这是 >= Android N 的解决方法(如果你想将定期作业设置为低于 15 分钟)
检查是否仅使用了 setMinimumLatency。此外,如果您正在 运行 执行一项需要很长时间的任务,则下一个任务将安排在当前任务完成时间 + PROVIDED_TIME_INTERVAL
.SetPeriodic(long millis) 适用于 API 水平低于 Android N
@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,指出有些人可能认为它会 运行 即使应用程序处于打瞌睡模式,但事实并非如此。
对于doze模式,AlarmManager仍然给出了最好的解决方案。如果你想[=50=,你可以使用setExactAndAllowWhileIdle() ] 您在确切时间段的定期工作或使用 setAndAllowWhileIdle() 如果您灵活的话。
您还可以使用 setAlarmClock(),因为设备总是从闹钟休眠模式中退出,然后 returns 再次进入休眠模式。另一种方法是使用 FCM。
如果您想 运行 代码周期性地少于 15 分钟,那么您可以使用一种棘手的方法。像这样设置你的jobFinished()
jobFinished(parameters, true);
它将使用重试策略重新安排代码。使用
定义自定义退避条件
.setBackoffCriteria();
在生成器中。然后它会运行定期
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(预览版)上遇到过这个问题吗?
在 Android 牛轧糖 setPeriodic(long intervalMillis)
method call makes use of setPeriodic (long intervalMillis, long flexMillis)
中安排定期作业。
根据文档:
JobInfo.Builder setPeriodic (long intervalMillis, long flexMillis)
Specify that this job should recur with the provided interval and flex. The job can execute at any time in a window of flex length at the end of the period.
intervalMillis long: Millisecond interval for which this job will repeat. A minimum value of getMinPeriodMillis() is enforced.
flexMillis long: Millisecond flex for this job. Flex is clamped to be at least getMinFlexMillis() or 5 percent of the period, whichever is higher.
计划 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 牛轧糖强制执行 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);
}
}
我找到了我们面临的牛轧糖设备问题的答案。 如果作业需要在 15 分钟内重新安排,Nougat 设备将无法安排作业。
我尝试将间隔时间设置为 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;
如果有人还在努力克服这种情况,
这是 >= Android N 的解决方法(如果你想将定期作业设置为低于 15 分钟)
检查是否仅使用了 setMinimumLatency。此外,如果您正在 运行 执行一项需要很长时间的任务,则下一个任务将安排在当前任务完成时间 + PROVIDED_TIME_INTERVAL
.SetPeriodic(long millis) 适用于 API 水平低于 Android N
@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,指出有些人可能认为它会 运行 即使应用程序处于打瞌睡模式,但事实并非如此。
对于doze模式,AlarmManager仍然给出了最好的解决方案。如果你想[=50=,你可以使用setExactAndAllowWhileIdle() ] 您在确切时间段的定期工作或使用 setAndAllowWhileIdle() 如果您灵活的话。
您还可以使用 setAlarmClock(),因为设备总是从闹钟休眠模式中退出,然后 returns 再次进入休眠模式。另一种方法是使用 FCM。
如果您想 运行 代码周期性地少于 15 分钟,那么您可以使用一种棘手的方法。像这样设置你的jobFinished()
jobFinished(parameters, true);
它将使用重试策略重新安排代码。使用
定义自定义退避条件.setBackoffCriteria();
在生成器中。然后它会运行定期