I have created a JobScheduler to intimate user few features in my app based on date and time.
But found out that the Job's are not scheduled at exact time which I am expecting to. Neither the job is getting stopped after the interval. As per my study all the scheduling depends on setOverrideDeadline
, setMinimumLatency
and durationToSet
Found out delay of 30-55 seconds for start and stop, which is not consistent in every trials.
I have restructured my app features referring this sample
Below are the code samples through which I will be scheduling according to the expected date time. (Put out only essential steps for SO)
String startDate = "2018-01-05";
String endDate = "2018-01-05";
String startTime = "11:10"
String endTime = "11:30"
Converting date time in the following format like given below after combining the start date with start time. similarly end date with end time.
String dateTimeStart = startDate + " " + startTime;//For start date time
String dateTimeEnd = endDate + " " + endTime;//For end date time
Will be using the below logic for calculating start and end time for job in long value.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
long timeInMilliseconds = 0;
try {
Date mDate = sdf.parse(dateTimeStart);
timeInMilliseconds = mDate.getTime();
} catch (ParseException e) {
Log.e(TAG, e.toString());
} catch (Exception e) {
Log.e(TAG, e.toString());
}
Now based on this input , I will create a Unique ID using AtomicInteger for each job and schedule the job as shown below.
public void scheduleJob(int jobID, long startMillSec,long endMilliSec) {
JobInfo.Builder builder = new JobInfo.Builder(jobID, mServiceComponent);
PersistableBundle extras = new PersistableBundle();
long currTimeMillSec= System.currentTimeMillis();
long minLatency =0;
//if time already crossed start time, then start time is current time itself
if(currTimeMillSec>=startMillSec){
minLatency=0;
}else{
minLatency=startMillSec-currTimeMillSec;
}
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE);
builder.setOverrideDeadline(startMillSec);
builder.setMinimumLatency(minLatency);
builder.setRequiresDeviceIdle(false);
builder.setRequiresCharging(false);
builder.setPersisted(true);
long durationToSet=0;
//if time has passes, keep the delta as the duration, or else keep the full duration received from backend
if(currTimeMillSec>=startMillSec){
durationToSet= endMilliSec-currTimeMillSec;
}else{
durationToSet=endMilliSec-startMillSec;
}
//Set duration for job stopping
extras.putLong("WORK_DURATION_KEY", durationToSet);
builder.setExtras(extras);
JobScheduler tm = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.schedule(builder.build());
}
Below is my JobService class
public class AppJobScheduler extends JobService
{
@Override
public boolean onStartJob(final JobParameters params) {
sendMessage(MSG_START, params.getJobId());
long duration = params.getExtras().getLong(WORK_DURATION_KEY);
// Uses a handler to delay the execution of jobFinished().
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
sendMessage(MSG_STOP, params.getJobId());
jobFinished(params, false);
}
}, duration);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
sendMessage(MSG_STOP, params.getJobId());
return false;
}
private void sendMessage(int messageID, @Nullable Object params) {
Message m = Message.obtain();
m.what = messageID;
m.obj = params;
try {
mActivityMessenger.send(m);
} catch (RemoteException e) {
Log.e(TAG, " Error passing service object back to .");
}
}
}
Other references followed are reference one and reference two