使用 WorkManager 在特定时间安排工作

问题描述 投票:0回答:9

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

因此,在浏览了 Constraints 类之后,我还没有找到任何可以为工作添加时间限制的函数。例如,我想在早上 8:00 开始执行一项工作(该工作可以是两种类型 OneTimeWorkRequestPeriodicWorkRequest 中的任何一种)。如何添加约束来使用 WorkManager 安排这项工作。

android android-workmanager
9个回答
65
投票

不幸的是,目前您无法在特定时间安排工作。如果您有时间关键的实现,那么您应该使用 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小时定期运行一次。


21
投票

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

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

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);

16
投票

到目前为止,还无法使用

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


8
投票

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

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

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

    if (calendar.before(Calendar.getInstance())) {
        calendar.add(Calendar.DATE, 1);
    }

    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);

}

2
投票

您可以使用 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'
    }

2
投票

所有答案现已过时,升级到 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);

1
投票

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

在 Android 中为定期工作管理器设置初始延迟


0
投票

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


0
投票

我正在用这个 方法

private static Duration getRemainingDurationUntil(int hour) {
    // Get the current time
    LocalDateTime currentTime = LocalDateTime.now();

    // Add one day to the current time
    LocalDateTime nextDay = currentTime.plusDays(1);

    // Set the target time to 3 AM of the next day
    LocalDateTime targetTime = LocalDateTime.of(nextDay.toLocalDate(), LocalTime.of(hour, 0));

    // Calculate the duration between the current time and hour 
    Duration duration = Duration.between(currentTime, targetTime);

    // Get the remaining milliseconds
    //long remainingMilliseconds = duration.toMillis();
    return duration;
}

还有

    Duration remainingDuration = getRemainingDurationUntil(REBIRTH_HOUR);

    // Create a PeriodicWorkRequest to run the task every XX minutes
    PeriodicWorkRequest periodicRebirthWorkRequest = new PeriodicWorkRequest.Builder(
            Rebirth.class,
            2, // Repeat interval
            TimeUnit.DAYS
    )
            .addTag(TAG_4_REBIRTH_WORK)
            .setInitialDelay(remainingDuration.toMinutes(),TimeUnit.MINUTES)
            .setConstraints(constraints) // Set the constraints (optional)
            .build();
© www.soinside.com 2019 - 2024. All rights reserved.