Android JobScheduler always works for 1 minute - android

I'm trying to implement background refreshing service with new JobScheduler(compat by tatarka).
Here is my Service
#Override
public boolean onStartJob(JobParameters params) {
Timber.i("on start job: " + params.getJobId());
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
Timber.i("on stop job: " + params.getJobId());
return true;
}
Here is my JobInfo
public void scheduleJob(View v) {
JobInfo job = new JobInfo.Builder(kJobId++ /*jobid*/, new ComponentName(getActivity(), RefreshJobService.class))
.setPeriodic(2000)
.build();
mTestService.scheduleJob(job);
}
In log i see that my job always works for 1 minute
12-31 12:38:03.884 10059-10059/#/RefreshJobService﹕ on stop job: 0
12-31 12:39:03.891 10059-10059/#/RefreshJobService﹕ on start job: 0
12-31 12:40:03.911 10059-10059/#/RefreshJobService﹕ on stop job: 0
12-31 12:42:08.841 10059-10059/#/RefreshJobService﹕ on start job: 0
12-31 12:43:08.858 10059-10059/#/RefreshJobService﹕ on stop job: 0
So why? I'm set periodic to 2000ms, any value do not influence to 1 minute interval for job. Why?

Until Android 5.1.1 there was a timeout of 60 seconds for a single job. Starting from Android 6, the timeout is now of 10 minutes.

onStopJob is called when the system wants to cancel your job. The reason it is cancelling your job is because it thinks it's still running. You need to call jobFinished(params, bool) at some point in your job to tell the scheduler that it is complete, otherwise it will time out and call onStopJob to cancel it. In addition, returning 'true' from onStartJob tells the system that you are not done processing. You should return 'false' unless you are still doing extra work, eg. passing the work off to a separate thread.
#Override
public boolean onStartJob(JobParameters params) {
Timber.i("on start job: " + params.getJobId());
jobFinished(params, false);
return false;
}

From API 26 (Oreo), setting a smaller period than 15 minutes for periodic jobs will execute at least after 15 minutes.

It sounds like you are asking why is it that you get onStopJob exactly one minute after your job is started.
This 1 minute timeout is defined in code here

43matthew is correct, but I'd like to add something more to this. The 2000 ms that you're talking about is the periodic interval after which the job starts again i.e. execute this job every 2000 ms, not the interval for which the job will execute.

Related

Periodic job in Android Job Scheduler not working as expected

I have a requirement to sync data from server to my local device in specified time interval, for that I am using Android JobScheduler. But it is not working as expected. For example I scheduled periodic job in every 30 minute, at the first time it worked properly. But next times the job is executed before 15 minutes, I debugged the interval time but it is always 30 minutes.
Only 1st time it working correctly.
This is the pending job information log:
Service Name ->ComponentInfo{my pakage name.services.SyncServiceFare}Time Interval->1800000}
Service Name ->ComponentInfo{my pakage name.services.SyncService}Time Interval->1800000}
This is my code:
private fun schedulePeriodicJob(JOB_ID: Int, fetchInterval: Long) {
jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler?
var serviceName : ComponentName? = null
try {
if (jobScheduler == null) {
return
}
jobScheduler?.cancel(JOB_ID)
serviceName = if(JOB_ID == 1){
ComponentName(this, SyncService::class.java)
}else{
ComponentName(this, SyncServiceFare::class.java)
}
val builder = JobInfo.Builder(JOB_ID, serviceName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setBackoffCriteria(60000, JobInfo.BACKOFF_POLICY_EXPONENTIAL)
.setPersisted(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setPeriodic(
TimeUnit.MINUTES.toMillis(fetchInterval),
JobInfo.getMinFlexMillis()
)
} else {
builder.setPeriodic(TimeUnit.MINUTES.toMillis(fetchInterval))
}
val extras = PersistableBundle()
val scheduleTime = System.currentTimeMillis()
extras.putLong("SCHEDULE_TIME", scheduleTime)
builder.setExtras(extras)
jobScheduler?.schedule(builder.build())
} catch (e: Exception) {
e.printStackTrace()
}
}
How can I solve this issue?
The period you are setting for the JobScheduler only means that the process will be executed inside a window of time as large as that period. You do not know when it will run: the system will calculate the best time for the execution the task (probably grouping it together with other scheduled tasks) in order to reduce battery usage and keep the phone in idle state as long as possible.
The next scheduled execution will be inside another window o time that starts as soon as the task has finished. That is why you are seeing inconsistent times and this is by design.
If you need to execute jobs at exact times then you should look at AlarmManager's setExact method, although this is strongly discouraged since it will negatively impact the battery consumption of the device.

Upload data to server on Internet in Android

I am trying to upload to data to a server in background when there are internet and app is not running in the front end.
So I read somewhere this can be achieved by JobService.
I created a simple job service that toasts onStartJob and in the splash screen activity. I called the below code:
mJobScheduler = (JobScheduler)
getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(1,
new ComponentName(getPackageName(),
Unigen_Upload_JobScheduler.class.getName()));
builder.setPeriodic(60000);
builder.setPersisted(true);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
if (mJobScheduler.schedule(builder.build()) <= 0) {
Log.e("Value", "onCreate: Some error while scheduling the job");
}
This runs the first time properly but doesn't run again after 1 minute. I am not sure why this isn't happening?
Also, I had another question will this trigger whenever the WIFI or Mobile is switched ON / Changed?
Do I have to use a broadcast receiver to do the above?
Thanks!
Update:
public class Unigen_Upload_JobScheduler extends JobService {
public Unigen_Upload_JobScheduler() {
}
#Override
public boolean onStartJob(JobParameters params) {
Toast.makeText(this,"Executed",Toast.LENGTH_LONG).show();
Log.e("Value","+_ what should I do");
/*
* True - if your service needs to process
* the work (on a separate thread).
* False - if there's no more work to be done for this job.
*/
return false;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
The minimum interval for JobScheduler Periodic Job is 15 minutes. Check the reason behind this:
Why can't an interval be smaller than 15 minutes for periodic jobs?
JobScheduler's minimum periodic interval is 15 minutes or (15 * 60 * 1000) 900000ms. You can look into WorkManager which is a part of android jetpack for more convenient usage. As for your second question workmanager has convenient methods for scheduling tasks on various scenarios.

JobScheduler - Updating job info after creating job

I want to sync data to server after certain amount of time and this time is configurable ranging from 30 minutes to 8 hours.
I am using JobScheduler to achieve above.
Is there any way using which I can update the JobInfo associated with JobScheduler?
So that I can update value set in setPeriodic(intervalMillis) method to the updated time interval.
Refer my sample code below
int PERIODIC_SYNC_JOB_ID = 0;
long interval = 1000 * 60 * 20;
JobInfo.Builder builder = new JobInfo.Builder(PERIODIC_SYNC_JOB_ID,
new ComponentName(getApplicationContext(), SampleJobService.class));
JobInfo jobInfo = builder.setPeriodic(interval).build();
JobScheduler jobScheduler = (JobScheduler) getApplicationContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
Log.d("JobScheduler", "Sample job is scheduled every " + interval + " ms");
SampleJobService.java
public class SampleJobService extends JobService {
#Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d("SampleJobService", "onStartJob()");
// do something in another thread/handler/AsyncTask
jobFinished(jobParameters, false);
Log.d("SampleJobService", "Sample job is rescheduled");
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d("SampleJobService", "onStopJob()");
return false;
}
}
Remember to add your service in Manifest
<service
android:name=".SampleJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
Note that minimum interval is 15 minutes. Attempting to declare a smaller period that this when scheduling a job will result in a job that is still periodic, but will run with this effective period.

JobScheduler executes after every 15 min

I am using JobScheduler in my application. I want to upload file after every hour if user connected to WIFI, but onStartJob()method gets called before hour, mostly it gets called after 15-20 min. Following is my code :
ComponentName componentName = new ComponentName(this,UploadService.class);
JobInfo info = new JobInfo.Builder(1,componentName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // change this later to wifi
.setPersisted(true)
.setPeriodic(60*60*10000)
.build();
JobScheduler scheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = scheduler.schedule(info);
if (resultCode==JobScheduler.RESULT_SUCCESS) {
Log.d(TAG,"JOb Scheduled");
} else {
Log.d(TAG,"Job Scheduling fail");
}
public class UploadService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
uploadFileToServer(params);
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
.....
.....
}
Here uploadFileToServer(params); gets called before hour. how to set time so it will call only after hour. Thanks in advance
Use this method setPeriodic (long intervalMillis, long flexMillis) (Added in API 24) on the JobInfo.Builder and supply a flex interval as the 2nd parameter:
long flexMillis = 59 * 60 * 1000; // wait 59 minutes before executing next job
JobInfo info = new JobInfo.Builder(1,componentName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // change this later to wifi
.setPersisted(true)
.setPeriodic(60 * 60 * 1000, flexMillis)
.build();
Importent - The job is guaranteed to run after the flex interval (which starts after the last job is finished), but it's not guaranteed to run immediately after that time, so the duration between jobs can be more than 1 hour, depending on your job requirements, system status, and more...
Docs ref: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setPeriodic(long,%20long)
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.
As already recommended in some comments, you should start working with the new WorkManager (even that it's not production level yet) which has similar features as the JobScheduler, but it's minimum SDK support is 14 which will let you delete a lot of boilerplate code :)
From the JobInfo.java class ,
You have no control over when within this interval this job will be executed
/**
* 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.
* Setting this function on the builder with {#link #setMinimumLatency(long)} or
* {#link #setOverrideDeadline(long)} will result in an error.
* #param intervalMillis Millisecond interval for which this job will repeat.
*/
public Builder setPeriodic(long intervalMillis) {
return setPeriodic(intervalMillis, intervalMillis);
}

Android JobScheduler. Can I schedule job every 15 seconds

My code is work. But I'm not sure that this will work on all devices and always.
Can I use JobScheduler like this?
Start method:
public static void schedule() {
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(1, new ComponentName(context, MySchedulerService.class))
.setMinimumLatency(15000)
.build();
scheduler.schedule(job);
}
Service:
public static class MySchedulerService extends JobService {
public boolean onStartJob(JobParameters params) {
schedule();
/* Business code */
stopSelf();
return false;
}
public boolean onStopJob(JobParameters params) {
return false;
}
}
Can I schedule job every 15 seconds
No. Minimum duration between two schedule is around 15 minutes. You can easily query for this information using getMinPeriodMillis()
Note:
Attempting to declare a smaller period that this when scheduling a job
will result in a job that is still periodic, but will run with this
effective period.
For setMinimumLatency, based on the documentation:
Milliseconds before which this job will not be considered for
execution.
This doesn't mean the job will be executed immediately after 15 seconds and won't be reliable from Android N when first phase of doze mode kicks in.

Categories

Resources