Android JobScheduler выполняется несколько раз
Я использую приведенный ниже код для создания и планирования задания с использованием Androids JobScheduler API:
Log.d("hanif", "Scheduling periodic job 2 hrs with 20 mins backoff linear");
JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
new ComponentName(getApplicationContext(), MyJobService.class))
.setPeriodic(TimeUnit.HOURS.toMillis(2))
.setRequiresCharging(true)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setBackoffCriteria(TimeUnit.MINUTES.toMillis(20),
JobInfo.BACKOFF_POLICY_LINEAR)
.build();
JobScheduler scheduler =
(JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
т.е. периодическое задание, выполняемое каждые 2 часа, и линейная отмена политики, которая выполняет 20 минут * номер, терпит неудачу в случае неудачи задания.
Мой код службы работы написан следующим образом:
public class MyJobService extends JobService {
@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d("hanif", "onStartJob");
new MyWorker(getApplicationContext(), this, jobParameters).execute();
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d("hanif", "onStopJob");
return true;
}
private static class MyWorker extends AsyncTask<Void, Void, Boolean> {
private final Context mContext;
private final MyJobService mJobService;
private final JobParameters mJobParams;
public MyWorker(Context context, MyJobService myJobService, JobParameters jobParameters) {
mContext = context;
mJobService = myJobService;
mJobParams = jobParameters;
}
@Override
protected Boolean doInBackground(Void... voids) {
Log.d("hanif", "Work start!");
for (int i=0; i<999999999; i++) {}
int counter = Prefs.getCounter(mContext);
Log.d("hanif", "Work done! counter: " + counter);
if (counter == 3) {
Log.d("hanif", "DO RESCHEDULE");
Prefs.resetCounter(mContext);
return true;
}
Log.d("hanif", "DO NOT RESCHEDULE");
Prefs.increaseCounter(mContext);
return false;
}
@Override
public void onPostExecute(Boolean reschedule) {
if (reschedule) {
mJobService.jobFinished(mJobParams, true);
} else {
mJobService.jobFinished(mJobParams, false);
}
Log.d("hanif", "------------------------------------------");
}
}
}
И, наконец, выход журнала выглядит следующим образом:
03-27 12:57:11.677 7383 7383 D hanif : Scheduling periodic job 2 hrs with 20 mins backoff linear
03-27 12:57:31.904 7383 7383 D hanif : onStartJob
03-27 12:57:31.909 7383 8623 D hanif : Work start!
03-27 12:57:42.110 7383 8623 D hanif : Work done! counter: 0
03-27 12:57:42.111 7383 8623 D hanif : DO NOT RESCHEDULE
03-27 12:57:42.125 7383 7383 D hanif : ------------------------
03-27 14:58:50.786 7383 7383 D hanif : onStartJob
03-27 14:58:50.789 7383 21490 D hanif : Work start!
03-27 14:59:00.952 7383 21490 D hanif : Work done! counter: 1
03-27 14:59:00.953 7383 21490 D hanif : DO NOT RESCHEDULE
03-27 14:59:00.962 7383 7383 D hanif : ------------------------
03-27 16:57:12.021 7383 7383 D hanif : onStartJob
03-27 16:57:12.045 7383 32028 D hanif : Work start!
03-27 16:57:22.229 7383 32028 D hanif : Work done! counter: 2
03-27 16:57:22.230 7383 32028 D hanif : DO NOT RESCHEDULE
03-27 16:57:22.238 7383 7383 D hanif : ------------------------
03-27 18:57:11.984 7383 7383 D hanif : onStartJob
03-27 18:57:11.989 7383 13217 D hanif : Work start!
03-27 18:57:22.123 7383 13217 D hanif : Work done! counter: 3
03-27 18:57:22.124 7383 13217 D hanif : DO RESCHEDULE
03-27 18:57:22.130 7383 7383 D hanif : ------------------------
03-27 19:20:57.468 7383 7383 D hanif : onStartJob
03-27 19:20:57.482 7383 1913 D hanif : Work start!
03-27 19:21:07.723 7383 1913 D hanif : Work done! counter: 0
03-27 19:21:07.724 7383 1913 D hanif : DO NOT RESCHEDULE
03-27 19:21:07.733 7383 7383 D hanif : ------------------------
03-27 19:21:57.669 7383 7383 D hanif : onStartJob <--- Why is this called again?
03-27 19:21:57.675 7383 3025 D hanif : Work start!
03-27 19:22:07.895 7383 3025 D hanif : Work done! counter: 1
03-27 19:22:07.896 7383 3025 D hanif : DO NOT RESCHEDULE
03-27 19:22:07.906 7383 7383 D hanif : ------------------------
03-27 21:40:53.419 7383 7383 D hanif : onStartJob
03-27 21:40:53.423 7383 31526 D hanif : Work start!
03-27 21:41:03.857 7383 31526 D hanif : Work done! counter: 2
03-27 21:41:03.858 7383 31526 D hanif : DO NOT RESCHEDULE
03-27 21:41:03.867 7383 7383 D hanif : ------------------------
Почему onStartJob вызывается два раза?
Ответы
Ответ 1
После долгих разочарований я понял, что вызывает эту проблему.
Вы должны не называть jobFinished(JobParameters, true)
периодическое задание. Передача true
для needsReschedule
приведет к дублированию задания в очереди (вы ожидаете, что оно будет перезаписано исходным, но, по-видимому, это не так). Вы всегда должны использовать jobFinished(JobParameters, false)
, даже если ваша задача не работает.
Что касается того, считается ли это неправильным использованием API или ошибкой Android, я оставлю это до вас.
Ответ 2
Поскольку JobScheduler будет использоваться намного больше с Android Oreo, я хотел бы описать несколько проблем с примером:
Перегруженный метод onStopJob()
возвращает только true
. Если ваша работа прерывается во время ее обработки, то есть зарядное устройство отключено или нет сети, установленной в JobInfo, эту функцию следует использовать, чтобы сразу же отменить задачу/задание. Затем он должен возвращать true
, указывающий, что задание необходимо перепланировать.
MyJobService
должен иметь ссылку private
для задания MyWorker
. onStartJob()
устанавливает его. onStopJob()
использует его для немедленной отмены задачи.
Передача true
для needsReschedule
в рамках метода jobFinished()
обычно не требуется, особенно когда вы вызываете ее в своей задаче. Если задание прерывается, onStopJob() будет вызываться, чтобы отменить его, а возврат true вернет его. Я видел только один пример здесь, где needsReschedule
установлен на true
. Он находится в пределах onStartJob()
, и если двойная проверка предварительных условий не выполняется, jobFinished(args, true)
, а затем return false
вместо true
.
Надеюсь, это поможет!