J'ai une instance Worker
qui doit s'exécuter toutes les 24 heures, ce qui est assez simple compte tenu de l'API PeriodicWorkRequest
. Mais voici le hic.
Si l'utilisateur lance le travail à 20 heures, par exemple, j'ai besoin que la première instance du gestionnaire de travaux s'exécute à 9 heures le lendemain matin et que je suive la contrainte périodique de 24 heures.
J'ai regardé ici et j'ai trouvé que l'API OneTimeWorkRequest a une fonction setInitialDelay()
qui peut être utilisée mais je n'ai rien trouvé pour l'API PeriodicWork
.
Il y a des hacks pour cela, comme je peux utiliser le OneTimeWork
avec le retard initial et ensuite planifier un PeriodicWork
à partir de là mais c'est un peu un hack sale.
Existe-t-il un moyen de le faire uniquement avec l'API PeriodicWorkRequest
?
Avec la version alpha actuelle de WorkManager
(v1.0.0-alpha07
), je pense qu'il n'est pas possible de définir le délai initial pour le PeriodicWorkReqeust
. Peut-être que nous aurons de l'API dans les prochaines versions.
Pour le moment, comme vous l'avez dit, vous pouvez utiliser une configuration de demande OneTimeWork
avec un délai initial, qui mettra ensuite en file d'attente une demande PeriodicWork
vers WorkManager.
Je dirais que c'est un hack mais pas trop sale.
PeriodicWorkRequest a un constructeur Nice Builder où vous pouvez passer un intervalle pendant lequel le travail peut s'exécuter. Vous pouvez vérifier les détails du Builder et chaque paramètre ici
Donc, pour définir un délai initial pour votre travail périodique, vous pouvez faire comme ceci:
int hourOfTheDay = 10; // When to run the job
int repeatInterval = 1; // In days
long flexTime = calculateFlex(hourOfTheDay, repeatInterval);
Constraints myConstraints = new Constraints.Builder()
.setRequiresBatteryNotLow(true)
.build();
PeriodicWorkRequest workRequest =
new PeriodicWorkRequest.Builder(MyNiceWorker.class,
repeatInterval, TimeUnit.DAYS,
flexTime, TimeUnit.MILLISECONDS)
.setConstraints(myConstraints)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork(YOUR_Nice_WORK_TAG,
ExistingPeriodicWorkPolicy.REPLACE,
workRequest);
Voici où la magie opère:
private long calculateFlex(int hourOfTheDay, int periodInDays) {
// Initialize the calendar with today and the preferred time to run the job.
Calendar cal1 = Calendar.getInstance();
cal1.set(Calendar.HOUR_OF_DAY, hourOfTheDay);
cal1.set(Calendar.MINUTE, 0);
cal1.set(Calendar.SECOND, 0);
// Initialize a calendar with now.
Calendar cal2 = Calendar.getInstance();
if (cal2.getTimeInMillis() < cal1.getTimeInMillis()) {
// Add the worker periodicity.
cal2.setTimeInMillis(cal2.getTimeInMillis() + TimeUnit.DAYS.toMillis(periodInDays));
}
long delta = (cal2.getTimeInMillis() - cal1.getTimeInMillis());
return ((delta > PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS) ? delta
: PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS);
}
Veuillez noter que cette heure n'est pas exacte. WorkManager peut déclencher votre travail à tout moment dans cette fenêtre flexible en fonction de vos contraintes, de la charge système, d'autres travaux planifiés, etc.
Si vous voulez un timing précis, passez à AlarmManager .
J'espère que ça aide!
Sur la nouvelle version de Work Manager ( Version 2.1.0-alpha02 publiée le 16 mai 2019) PeriodicWorkRequests prend désormais en charge les délais initiaux. Vous pouvez utiliser la méthode setInitialDelay sur PeriodicWorkRequest.Builder pour définir un délai initial.
Exemple:
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
WorkerReminderPeriodic.class,
24,
TimeUnit.HOURS,
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
TimeUnit.MILLISECONDS)
.setInitialDelay(1, TimeUnit.HOURS)
.addTag("send_reminder_periodic")
.build();
WorkManager.getInstance()
.enqueueUniquePeriodicWork("send_reminder_periodic", ExistingPeriodicWorkPolicy.REPLACE, workRequest);