在 Android 中为定期工作管理器设置初始延迟
Posted
技术标签:
【中文标题】在 Android 中为定期工作管理器设置初始延迟【英文标题】:Set initial delay to a Periodic Work Manager in Android 【发布时间】:2019-01-27 10:49:07 【问题描述】:我有一个 Worker
实例,它需要每 24 小时运行一次,考虑到 PeriodicWorkRequest
API,这非常简单。但这就是问题所在。
如果用户在晚上 8 点开始工作,我需要工作管理器的第一个实例在第二天早上 9 点运行,然后遵循 24 小时定期约束。
我查看了here,发现 OneTimeWorkRequest API 有一个可以使用的setInitialDelay()
函数,但我找不到PeriodicWork
API 的任何内容。
对此有一些技巧,例如我可以使用 OneTimeWork
与初始延迟,然后从那里安排 PeriodicWork
,但这有点肮脏的技巧。
有没有办法只使用PeriodicWorkRequest
API 来做到这一点?
【问题讨论】:
【参考方案1】:在新版本的工作管理器上(Version 2.1.0-alpha02 于 2019 年 5 月 16 日发布)PeriodicWorkRequests 现在支持初始延迟。您可以使用 PeriodicWorkRequest.Builder 上的 setInitialDelay 方法来设置初始延迟。
例子:
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);
【讨论】:
setInitialDelay
工作很奇怪。当我设置 15 分钟的启动时间和 1 分钟的初始延迟时,工作人员会在 16 分钟后启动。我认为它会立即(如OneTimeWorkRequest
),但在 1 分钟后(而不是在 16 分钟后)。随后的启动将是每 15 分钟一次。
@proninyaroslav 定期工作的最小间隔为 15 分钟,并且不能有初始延迟。 MIN_PERIODIC_INTERVAL_MILLIS 为 15 分钟。 developer.android.com/reference/kotlin/androidx/work/…
谢谢。我会尝试用OneTimeWorkRequest
做一个技巧
PeriodicWorker 无法设置初始延迟,初始延迟仅适用于 oneTimeWorker
我使用的是 implementation 'android.arch.work:work-runtime:1.0.1'
版本,而这里 setInitialDelay() 不存在。抱歉,我使用的是稳定版 WorkManager
而不是 alpha。【参考方案2】:
PeriodicWorkRequest 有一个不错的 Builder 构造函数,您可以在其中传递工作可以执行的时间间隔。可以查看Builder的详细信息和各个参数here
因此,要为您的定期工作设置初始延迟,您可以这样做:
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);
这就是神奇发生的地方:
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);
请注意,这个时间并不准确。 WorkManager 可能会在该弹性窗口中随时触发您的作业,具体取决于您的约束、系统负载、其他计划作业等。
如果您想要精确计时,请切换到 AlarmManager。
希望对你有帮助!
【讨论】:
文档说某些 API 版本(例如 23 版本)忽略了 flexTime...有没有合理的解决方案?【参考方案3】:在WorkManager
(v1.0.0-alpha07
) 的当前 alpha 版本中,我认为无法为PeriodicWorkReqeust
设置初始延迟。也许我们会在下一个版本中获得一些 API。
目前,正如您所说,您可以使用带有初始延迟的 OneTimeWork
请求设置,然后将 PeriodicWork
请求排队到 WorkManager。
我会说这是一个 hack,但没那么脏。
【讨论】:
是的,这是我目前的策略。我只是想知道是否有任何直接的方法。 @qasim,有一些代码,如何实现?以上是关于在 Android 中为定期工作管理器设置初始延迟的主要内容,如果未能解决你的问题,请参考以下文章
小米和OPPO等中国ROM的工作管理器,在电池优化时,将预定的工作延迟增加几个小时