Is their a pattern for having Evernote's android-job run a job at between 1AM and 2AM everyday?
I was thinking it might make sense to do something like having in my Application.onCreate
and at the end of my Job.onRunJob
// use the current time to see how long it will be until 1AM
long timeUntil1Am = getTimeUntil1Am(currentUnixTimeStamp);
new JobRequest.Builder(DemoSyncJob.TAG)
.setExecutionWindow(timeUntil1Am, timeUntil1Am + 3600_000L)
.setBackoffCriteria(5_000L, JobRequest.BackoffPolicy.EXPONENTIAL)
.setRequiresCharging(true)
.setRequiresDeviceIdle(false)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setRequirementsEnforced(true)
.setPersisted(true)
.setUpdateCurrent(true)
.build()
.schedule();
which would run the job the first time at ~1AM from the application on create and then use the onRunJob
to daisy chain the next run time.
I think this would work, but I am concerned that the job would be scheduled multiple times because a new job is created every time the Application
is built. If I knew the job was already scheduled I could avoid this, but not sure if that is possible.
So my question is using this daisy chain a reasonable pattern and how do I avoid running the job more than once per day?
I used something similar to the pattern in the FAQ mentioned by @CommonsWare
To make this easier i created a wrapper class to get a daily execution window
class DailyExecutionWindow {
final long startMs;
final long endMs;
/**
* Holds the start end time in ms for a job.
* Will wrap around to next day if currentHour < targetHour.
* If the current time is exactly now it will be forced to 60 seconds in the future.
*
* @param currentHour - current currentHour
* @param currentMinute - current currentMinute
* @param targetHour - currentHour we want to start
* @param targetMinute - currentMinute we want to start
* @param windowLengthInMinutes - number of minutes for the execution window
*/
DailyExecutionWindow(int currentHour, int currentMinute, long targetHour, long targetMinute, long windowLengthInMinutes) {
long hourOffset;
long minuteOffset;
if (targetHour == currentHour && targetMinute < currentMinute) {
hourOffset = TimeUnit.HOURS.toMillis(23);
} else if (targetHour - currentHour == 1) { // if we are less then an hour ahead, but into the next hour
// move forward to 0 minute of next hour
hourOffset = TimeUnit.MINUTES.toMillis(60 - currentMinute);
currentMinute = 0;
} else if (targetHour >= currentHour) {
hourOffset = TimeUnit.HOURS.toMillis(targetHour - currentHour);
} else {
hourOffset = TimeUnit.HOURS.toMillis((24 + targetHour) - currentHour);
}
if (targetMinute >= currentMinute) {
minuteOffset = TimeUnit.MINUTES.toMillis(targetMinute - currentMinute);
} else {
minuteOffset = TimeUnit.MINUTES.toMillis((60 + targetMinute) - currentMinute);
}
this.startMs = Math.max(hourOffset + minuteOffset, 60000);
this.endMs = this.startMs + TimeUnit.MINUTES.toMillis(windowLengthInMinutes);
}
}
Job
implementationpublic class UpdateFeedsJob extends Job {
public static final String TAG = UpdateFeedsJob.class.getName();
private static final long TARGET_HOUR = 2L;
private static final long TARGET_MINUTE = 15;
private static final long WINDOW_LENGTH = 60;
private static final int WAKE_LOCK_AWAIT_TIME_SECONDS = 60;
// called in <MyApplication extends Application>.onCreate()
public static void schedule() {
schedule(true);
}
private static void schedule(boolean updateCurrent) {
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
DailyExecutionWindow executionWindow =
new DailyExecutionWindow(hour, minute, TARGET_HOUR, TARGET_MINUTE, WINDOW_LENGTH);
new JobRequest.Builder(UpdateFeedsJob.TAG)
.setExecutionWindow(executionWindow.startMs, executionWindow.endMs)
.setPersisted(true)
.setUpdateCurrent(updateCurrent)
.build()
.schedule();
}
@NonNull
@Override
protected Result onRunJob(Params params) {
try {
// ... do work
return Result.SUCCESS;
} finally {
schedule(false);
}
return Result.FAILURE;
}
}
You can see a working example in my Podcast Player Application on github