【问题标题】:Schedule a work on a specific time with WorkManager使用 WorkManager 在特定时间安排工作
【发布时间】:2018-10-26 01:47:47
【问题描述】:

WorkManager 是一个用于将保证在满足其约束后执行的工作排入队列的库。

因此,经过Constraints 课程后,我还没有找到任何可以为工作添加时间限制的功能。例如,我想在早上 8:00 开始工作(工作可以是 OneTimeWorkRequestPeriodicWorkRequest 两种类型中的任何一种)。如何使用 WorkManager 添加约束来安排这项工作。

【问题讨论】:

  • 我认为,这可能是解决问题的好方法。为此,我必须计算当前时间与我希望开始工作的时间之间的时间差。但是我可以明确设置开始时间吗?
  • 计算timeInFutureInSeconds - timeNowInSeconds有什么问题?
  • @pskink 但正如问题所问,我们如何指定工作必须在每天早上 8 点完成。?初始延迟是指定的“初始”延迟。 workmanager 是如何知道我们下次需要运行它的。
  • 由于任务是周期性任务,workmanager会在第一次触发的同时触发。

标签: android android-workmanager


【解决方案1】:

很遗憾,您目前无法在特定时间安排工作。如果您有时间紧迫的实现,那么您应该使用 AlarmManager 来设置在打瞌睡时可以触发的警报,方法是使用 setAndAllowWhileIdle()setExactAndAllowWhileIdle()

您可以使用WorkManager 来安排一项工作,具有一次初始延迟或定期执行,如下所示:

创建 Worker 类:

public class MyWorker extends Worker {
    @Override
    public Worker.WorkerResult doWork() {

        // Do the work here

        // Indicate success or failure with your return value:
        return WorkerResult.SUCCESS;

        // (Returning RETRY tells WorkManager to try this task again
        // later; FAILURE says not to try again.)
    }
}

然后安排OneTimeWorkRequest如下:

OneTimeWorkRequest mywork=
        new OneTimeWorkRequest.Builder(MyWorker.class)
        .setInitialDelay(<duration>, <TimeUnit>)// Use this when you want to add initial delay or schedule initial work to `OneTimeWorkRequest` e.g. setInitialDelay(2, TimeUnit.HOURS)
        .build();
WorkManager.getInstance().enqueue(mywork);

您可以按如下方式设置附加约束:

// Create a Constraints that defines when the task should run
Constraints myConstraints = new Constraints.Builder()
    .setRequiresDeviceIdle(true)
    .setRequiresCharging(true)
    // Many other constraints are available, see the
    // Constraints.Builder reference
     .build();

然后创建一个使用这些约束的 OneTimeWorkRequest

OneTimeWorkRequest mywork=
                new OneTimeWorkRequest.Builder(MyWorker.class)
     .setConstraints(myConstraints)
     .build();
WorkManager.getInstance().enqueue(mywork);

PeriodicWorkRequest 可以按如下方式创建:

 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(MyWorker.class, 12, TimeUnit.HOURS)
                                   .build();
  WorkManager.getInstance().enqueue(periodicWork);

这会创建一个 PeriodicWorkRequest 以每 12 小时定期运行一次。

【讨论】:

  • 问题是它不适用于周期性作品。
  • @Gatek,它的整体。它在 Google IO 中被提及。如果你想这样做,那么 Schedule OneTimeWorkRequest 将在 2 小时后触发,PeriodicWorkRequest 将在下午 2 点执行。
  • 有两种方法 setInitialDelay,一种需要 Duration 作为参数,仅在 API 26 中(因为它来自 Java 8),另一种需要持续时间和时间单位,在每个平台上都可用。
  • 如何接受这个答案?问题表明我们必须在上午 8 点执行工作。没有提到那个?
  • 这是因为您无法在特定时间使用 WorkManager 安排工作
【解决方案2】:

PeriodicWorkRequests 现在支持 2.1.0-alpha02 版本的初始延迟。您可以使用 PeriodicWorkRequest.Builder 上的 setInitialDelay 方法来设置初始延迟。 Link Here

每天早上 8:00 的时间表示例。这里我使用joda time library 进行时间操作。

final int SELF_REMINDER_HOUR = 8;

    if (DateTime.now().getHourOfDay() < SELF_REMINDER_HOUR) {
        delay = new Duration(DateTime.now() , DateTime.now().withTimeAtStartOfDay().plusHours(SELF_REMINDER_HOUR)).getStandardMinutes();
    } else {
        delay = new Duration(DateTime.now() , DateTime.now().withTimeAtStartOfDay().plusDays(1).plusHours(SELF_REMINDER_HOUR)).getStandardMinutes();
    }


    PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
        WorkerReminderPeriodic.class,
        24,
        TimeUnit.HOURS,
        PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
        TimeUnit.MILLISECONDS)
        .setInitialDelay(delay, TimeUnit.MINUTES)
        .addTag("send_reminder_periodic")
        .build();


    WorkManager.getInstance()
        .enqueueUniquePeriodicWork("send_reminder_periodic", ExistingPeriodicWorkPolicy.REPLACE, workRequest);

【讨论】:

  • 相信以后执行时间的偏移量会很大...不过REPLACE好像没问题
  • 对我来说,它只会在 24 小时结束时第一次解雇周期性工作人员。有什么方法可以让它在创建后立即工作? (例如,应该在 17:50 运行,在 17:40 排队,第一次在 10 分钟后运行)
  • 另外,如果用户更改了他的时间设置,worker 将保持不变(例如,worker 应该每天早上 8:00 运行。如果用户设置了另一个时区,例如 +3h,它将不会上午 11:00 运行)
  • @Vlad I believe in the future the offset of execution time will be very large 你能解释一下原因吗?
  • @Anjal 你为什么用ExistingPeriodicWorkPolicy.REPLACE?!
【解决方案3】:

到目前为止,使用PeriodicWorkRequest 无法获得准确的时间。
一个丑陋的解决方法是使用 OneTimeWorkRequest,当它触发时,设置另一个 OneTimeWorkRequest 并使用新的计算周期,依此类推。

【讨论】:

  • 哇...这太恶心了x.x
  • 我认为没有理由从 Evernote android-job 迁移出去
  • 请多多看我的回答:stackoverflow.com/questions/51945439/…
  • @Kerooker 其实是 WorkManager 的一位开发者建议的here
  • @mhashim6,有例子吗?
【解决方案4】:

我可能有点晚了,但无论如何我这样做是为了在给定时间安排工作请求(可选的短延迟)。你只需要从 TimePicker 获取时间:

public static void scheduleWork(int hour, int minute) {
    Calendar calendar = Calendar.getInstance();
    long nowMillis = calendar.getTimeInMillis();

    if(calendar.get(Calendar.HOUR_OF_DAY) > hour ||
            (calendar.get(Calendar.HOUR_OF_DAY) == hour && calendar.get(Calendar.MINUTE)+1 >= minute)) {
        calendar.add(Calendar.DAY_OF_MONTH, 1);
    }

    calendar.set(Calendar.HOUR_OF_DAY,hour);
    calendar.set(Calendar.MINUTE,minute);

    calendar.set(Calendar.SECOND,0);
    calendar.set(Calendar.MILLISECOND,0);
    long diff = calendar.getTimeInMillis() - nowMillis;

    WorkManager mWorkManager = WorkManager.getInstance();
    Constraints constraints = new Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build();
    mWorkManager.cancelAllWorkByTag(WORK_TAG);
    OneTimeWorkRequest mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class)
            .setConstraints(constraints)
            .setInitialDelay(diff,TimeUnit.MILLISECONDS)
            .addTag(WORK_TAG)
            .build();
    mWorkManager.enqueue(mRequest);

}

【讨论】:

  • 我试过了,但经常不能按预期工作,所以最好使用AlarmManager
  • 当然,如果时间准确的话developer.android.com/guide/background
  • 现在警报管理器没有被触发,出于后台目的,这个答案是完美的,
【解决方案5】:

所有答案现已过时,升级到 WorkManager 2.1.0-alpha02(或更高版本) setInitialDelay() 方法过去只适用于 OneTimeWorkRequest,但现在它们也支持 PeriodicWorkRequest。

implementation "androidx.work:work-runtime:2.1.0-alpha02"

PeriodicWorkRequests 现在支持初始延迟。您可以使用 PeriodicWorkRequest.Builder 上的 setInitialDelay 方法设置一个 初始延迟

快速示例:

new PeriodicWorkRequest.Builder(MyWorker.class, MY_REPEATS, TimeUnit.HOURS)
        .setInitialDelay(THE_DELAY,TimeUnit.SECONDS);

【讨论】:

    【解决方案6】:

    你可以从evernote使用AndroidJob

    class NotificationJob : DailyJob() {
    
    override fun onRunDailyJob(params: Params): DailyJobResult {
           //your job       
           return DailyJobResult.SUCCESS
    
    }
    
    companion object {
        val TAG = "NotificationJob"
        fun scheduleJob() {
            //scheduled between 9-10 am
    
            DailyJob.schedule(JobRequest.Builder(TAG), 
                TimeUnit.HOURS.toMillis(9),TimeUnit.HOURS.toMillis(10 ))
         }
       }
     }
    

    和通知创建者

      class NotificationJobCreator : JobCreator {
    
            override fun create(tag: String): Job? {
               return when (tag) {
                  NotificationJob.TAG ->
                    NotificationJob()
                  else ->
                    null
               }
           }
      }
    

    然后在您的应用程序类中启动

        JobManager.create(this).addJobCreator(NotificationJobCreator())
    

    gradle依赖是

        dependencies {
            implementation 'com.evernote:android-job:1.2.6'
    
            // or this with workmnager 
            implementation 'com.evernote:android-job:1.3.0-alpha08'
        }
    

    【讨论】:

      【解决方案7】:

      如果您想为 PeriodicWorkRequest 设置初始延迟,我在这里提出了解决方案:

      Set initial delay to a Periodic Work Manager in Android

      【讨论】:

        【解决方案8】:

        我尝试了 OneTimeWorkRequest,但它很不稳定(仅有时工作),所以我们不应该依赖它。 AlarmManager 是一个更好的选择。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-01-09
          • 2012-12-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-06-22
          • 1970-01-01
          • 2013-09-08
          相关资源
          最近更新 更多