I am using the below code to create and schedule a job using 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);
I.e. a periodic job which executes every 2 hours and a linear back off policy which executes 20 min * number fails in case the job fails.
My job service code is written as below:
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", "------------------------------------------"); } } }
And finally the log output is as below:
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 : ------------------------
Why is onStartJob being called two times?
After much frustration, I figured out what causes this problem.
You should not call jobFinished(JobParameters, true)
on a periodic job. Passing true
for needsReschedule
will cause the job to be duplicated in the queue (you would expect it to overwrite the original one, but apparently that's not the case). You must always use jobFinished(JobParameters, false)
, even if your task fails.
As for whether this is counts as incorrect API usage or an Android bug, I'll leave that up to you.
Since JobScheduler will be used a lot more with Android Oreo, I wanted to describe a few issues with the example:
The onStopJob()
overridden method only returns true
. If your job gets interrupted while it is processing, i.e. charger is unplugged or no network as set in JobInfo, this function should be used to also immediately cancel the task/job. Then it should return true
indicating the job needs to be rescheduled.
MyJobService
should have a private
reference to MyWorker
task. onStartJob()
sets it. onStopJob()
uses it to immediately cancel the task.
Passing true
for the needsReschedule
within the jobFinished()
method is generally not needed especially when called within your task. If a job is interrupted, onStopJob() will be called to cancel it and returning true will reschedule it. I have only seen one example here where needsReschedule
is set to true
. It is within onStartJob()
and if the double-checking of preconditions is not met, jobFinished(args, true)
and then return false
instead of true
.
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With