Search code examples
android-6.0-marshmallowjob-scheduling

Android JobScheduler job not running


My hybrid Cordova Android app uses one custom plugin in which I do a great deal of background work at intervals of ca 30 minutes. Up until now I have been using AlarmManger with a setInexact alarm to perform the work. The only real issue I have with that route is that the alarm does not survive a reboot. Given that I am now only supporting Android 6 (API 23)+ devices I am now experimenting with replacing AlarmManager with JobScheduler. My efforts thus far are shown below

public class UnyService extends JobService 
{

 @Override
 public boolean onStartJob(JobParameters params) 
 {
  UnyHandler.sendMessage(Message.obtain(UnyHandler,1,params));
  return true;
 }

 @Override
 public boolean onStopJob(JobParameters params)
 {
  UnyHandler.removeMessages(1);
  return false;
 }

where I am using a Handler to perform the actual work. The code for Handler is shown below

 private Handler UnyHandler = new Handler(new Handler.Callback()
 {
  @Override
  public boolean handleMessage(Message msg)
  {
   Feedback.postBackInfo("Handled it!");
   jobFinished((JobParameters)msg.obj,false);
   return true;
  }

  });

I then use the following code to get the job up and running

private void launchTimerJob()
{
 timerJob = 
 (JobScheduler)context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
 JobInfo.Builder builder = new JobInfo.Builder(1,new 
 ComponentName(Utils.packName,UnyService.class.getName()));

 builder.setPeriodic(30000);
 builder.setPersisted(true);
 builder.setBackoffCriteria(30000,JobInfo.BACKOFF_POLICY_LINEAR);
 if (0 >= timerJob.schedule(builder.build())) 
 Feedback.postBackInfo("Job Build Error");
 else Feedback.postBackInfo("Job Created and Scheduled");
}

where Feedback and Utils are other classes in my app which provide support services. To facilitate testing I am using a relatively small period of 30 seconds.

When I install and start the app the plugin init code calls launchTimerJob() and I get the "Job Created and Scheduled" notification back as expected.

From that point forward I had expected to get Handled It! notifications from Handler above at intervals of roughly 30s. A notification has turned up on the odd occasion but a totally arbitrary time measuring from App startup and has not obliged by repeating. Clearly, I am doing something wrong here.


Solution

  • Android docs could do a better job of mentioning that the minimum interval allowed for periodic jobs is 900,000 milliseconds, i.e.

    15 minutes !!!!

    I gather that prior to API 24 (Nogat) it was possible to use smaller intervals but no longer. Be wary of the various JobScheduler tutorials you will find out there. There are many that are quite dated and Android Jobs appears to be a still evolving API.

    My own reason for originally using AlarmManager was to enable background tasks to be performed when the app was, well, backgrounded. However, with the coming of doze mode this strategy fails since the app will simply not get broadcast messages when the device is dozing.

    Consider the following strategy instead

    • When the app is foregrounded you can quite simply use a Handler to manage periodic tasks - even those that happen at an interval of a few seconds.
    • No normal app should ever have to carry out background tasks at that frequency (every few seconds) when the phone is dozing - and when that is required there is a route via a specific request for the app to be exempted from battery optimizations. In such instances a periodic JobScheduler with a 15 minute period is the best you can do.