Выполняйте работу в определенное время дня, каждый день с помощью Android-работы Evernote
Является ли это примером того, что Android-задание Evernote запускает работу между 1 и 2 часами утра каждый день?
Я подумал, что может иметь смысл сделать что-то вроде Application.onCreate
и в конце моего 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();
который запускает задание в первый раз в ~1:00 из приложения при создании, а затем использует onRunJob
к гирляндной цепи в следующий раз.
Я думаю, что это будет работать, но я обеспокоен тем, что задание будет запланировано несколько раз, потому что новое задание создается каждый раз, когда Application
построено. Если бы я знал, что работа уже запланирована, я мог бы избежать этого, но не уверен, возможно ли это.
Поэтому мой вопрос заключается в том, чтобы использовать эту последовательную цепь разумным образом, и как мне избежать выполнения задания чаще, чем один раз в день?
2 ответа
Я использовал что-то похожее на шаблон в FAQ, упомянутом @CommonsWare
Чтобы сделать это проще, я создал класс-обертку, чтобы получить окно ежедневного выполнения
Класс, чтобы получить начало и конец времени относительно текущего времени
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
реализация
public 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;
}
}
Вы можете увидеть рабочий пример в моем приложении Podcast Player на github.
Образец в принятом ответе выглядит хорошо. Обратите внимание, что версия 1.2.0 будет иметь вспомогательный класс для ежедневного запуска заданий.