Job Scheduler not running within set interval
Asked Answered
C

6

13

I'm trying to use the android Job Scheduler API and all I'm trying to do is have the Job Scheduler run every 5 seconds. However when I run it, the corresponding service is hit every two minutes. I have a log that documents every time the service is hit. I'm not sure why this is happening. Could the Job Scheduler have a minimum interval time. My code is simply...

JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(this, UpdateDatabaseService.class))
            .setPeriodic(5000)
            .build();

JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);

The problem originally arose when I was trying to run a daily task but it would trigger the service multiple times within that day and wouldn't follow the time guideline.

Let me know what you think.

Courier answered 7/4, 2015 at 12:48 Comment(1)
Well, on Android 5.1, AlarmManager has an undocumented lower limit of a one-minute polling period. Perhaps there is something similar at work here. IMHO, using either AlarmManager or JobScheduler for every-five-second work is inappropriate, as polling that quickly really should only be done by a foreground process that's already running.Canonize
M
24

I was having this problem and after review some blogs and the official documentation, I realised that JobScheduler is having difference behavior on Android N(24 and 25). JobScheduler works with a minimum periodic of 15 mins.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public static void setJobScheduler(Context context){
        Log.v(TAG, "Job Scheduler is starting");
        JobScheduler jobScheduler = (JobScheduler)context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        ComponentName serviceName = new ComponentName(context, JobService.class);
        JobInfo jobInfo;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
                    .setPeriodic(900000)
                    .build();
        }else{
            jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
                    .setPeriodic(Constants.TIME_INTERVAL)
                    .build();
        }
        jobScheduler.schedule(jobInfo);
    }
Mohave answered 24/5, 2017 at 22:0 Comment(2)
15 minutes * 60 seconds * 1000 = 900000 milliseconds.Zales
Confirmed: in Android P (API 28) minimum period is 15 minutes (900000L).Limbourg
F
6

Instead of setPeriodic(int) use setMinimumLatency(int) with setOverrideDeadline(int). These two methods will adjust the interval of your JobScheduler.

Farina answered 16/8, 2017 at 12:21 Comment(3)
Can you explain? Any example?Shannonshanny
@PratikButaniAndroidDev you're better off using WorkManager now.Farina
Thank @Roman, I want to get location update and it should be send to server every day. I am new to WorkManager, hope I can achieve that.Shannonshanny
U
3

You should call jobFinished(jobParams,needResheduleBoolean);, after this call only the job will execute again, this is how the job knows it has finished execution so can start once more.

Usm answered 28/6, 2016 at 20:29 Comment(0)
G
3

JobInfo.Builder builder = new JobInfo.Builder(1,new ComponentName(getPackageName(), JobSchedulerService.class.getName()));

builder.setPeriodic(3000);


Edited

MainActivity.java

public class MainActivity extends Activity {

    private JobScheduler mJobScheduler;
    private Button mScheduleJobButton;
    private Button mCancelAllJobsButton;

    @Override
    protected void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_main );
        mJobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
        mScheduleJobButton = (Button) findViewById( R.id.schedule_job );
        mCancelAllJobsButton = (Button) findViewById( R.id.cancel_all );

        mScheduleJobButton.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                JobInfo.Builder builder = new JobInfo.Builder( 1,
                        new ComponentName( getPackageName(), JobSchedulerService.class.getName() ) );

                builder.setPeriodic( 3000 );


                if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
                    //If something goes wrong
                }
            }
        });

        mCancelAllJobsButton.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick( View v ) {
                mJobScheduler.cancelAll();
            }
        });
    }
}

just need to change

new JobInfo.Builder(1, new ComponentName(this, UpdateDatabaseService.class))

to

new JobInfo.Builder( 1, new ComponentName( getPackageName(), JobSchedulerService.class.getName() ) )

builder.setPeriodic( 3000 ); will set JobInfo in 3000 ms schedule and called after every 3 seconds.

JobSchedulerService.java

public class JobSchedulerService extends JobService {

    private Handler mJobHandler = new Handler( new Handler.Callback() {
        @Override
        public boolean handleMessage( Message msg ) {
            Toast.makeText( getApplicationContext(), "JobService task running", Toast.LENGTH_SHORT ).show();
            jobFinished( (JobParameters) msg.obj, false );
            return true;
        }
    } );

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

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

}

AndroidManifest.xml

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

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/schedule_job"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Schedule Job"/>

    <Button
        android:id="@+id/cancel_all"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cancel All"/>

</LinearLayout>
Geothermal answered 12/10, 2016 at 7:48 Comment(3)
@ChiragSheta still there is no explanation to the block of code!Shelbashelbi
I think the above code wont work in API level 24, cause the minimum interval should be 15 minPrimitivism
for that you can use builder.setTriggerContentMaxDelay(2000) this will call on every 2 secondGeothermal
D
1

From android documentation of setPeriodic ,

setPeriodic (long intervalMillis) : Specify that this job should recur with the provided interval, not more than once per period. You have no control over when within this interval this job will be executed, only the guarantee that it will be executed at most once within this interval.

so it is clearly mentioned that it is not necessary that job will run during this time. If you want to run a job at some periodic specific time , then you shoulf better use AlarmManager Api with setRepeating() method . Follow this link below for your requirements .

https://developer.android.com/training/scheduling/alarms.html#set

Dullard answered 14/4, 2018 at 10:50 Comment(2)
If i use alarmmanager in Android 8(OREO). Alarmmanager gets removed whenever the app is killed. In this case Alarmmanager stops working. Can u suggest workaround for this or any other better wayRachael
you can disable battery optimization for that appShook
M
0

You need minimum 30 seconds to wait for next job

Mccartan answered 21/10, 2019 at 10:29 Comment(3)
yaa its right, it will take 30 seconds minimum to start new taskSymphonia
Is it 30 secs or 15 mins? These are huge differences.Floorman
It is definitelly 15 mins. You can see it in the source code here: android.googlesource.com/platform/frameworks/base/%2B/master/… If you set anything less, it will set the interval to the minimum, which as you can see in that file is 15 minutes, with a minimum flex of 5 minutes (meaning it can execute in a window of 5 minutes at the end of that interval)Sensitive

© 2022 - 2024 — McMap. All rights reserved.