检查WorkRequest是否已被WorkManager Android先前排队。

18

我正在使用PeriodicWorkRequest来每15分钟为我执行任务。 我想检查这个周期性的工作请求是否先前已经被安排了。 如果没有,请进行安排。

     if (!PreviouslyScheduled) {
        PeriodicWorkRequest dataupdate = new PeriodicWorkRequest.Builder( DataUpdateWorker.class , 15 , TimeUnit.MINUTES).build();
        WorkManager.getInstance().enqueue(dataupdate);
      }

以前我使用JobScheduler执行任务时,我习惯使用

public static boolean isJobServiceScheduled(Context context, int JOB_ID ) {
    JobScheduler scheduler = (JobScheduler) context.getSystemService( Context.JOB_SCHEDULER_SERVICE ) ;

    boolean hasBeenScheduled = false ;

    for ( JobInfo jobInfo : scheduler.getAllPendingJobs() ) {
        if ( jobInfo.getId() == JOB_ID ) {
            hasBeenScheduled = true ;
            break ;
        }
    }

    return hasBeenScheduled ;
}
需要协助建立一个类似的模块用于工作请求,以帮助查找已安排/正在进行中的工作请求。
4个回答

32

为你的PeriodicWorkRequest任务设置一些标记:

    PeriodicWorkRequest work =
            new PeriodicWorkRequest.Builder(DataUpdateWorker.class, 15, TimeUnit.MINUTES)
                    .addTag(TAG)
                    .build();

然后在enqueue()工作之前检查有标签的任务:

    WorkManager wm = WorkManager.getInstance();
    ListenableFuture<List<WorkStatus>> future = wm.getStatusesByTag(TAG);
    List<WorkStatus> list = future.get();
    // start only if no such tasks present
    if((list == null) || (list.size() == 0)){
        // shedule the task
        wm.enqueue(work);
    } else {
        // this periodic task has been previously scheduled
    }

但如果你并不需要知道它之前是否已经安排好了,你可以使用:

    static final String TASK_ID = "data_update"; // some unique string id for the task
    PeriodicWorkRequest work =
            new PeriodicWorkRequest.Builder(DataUpdateWorker.class,
                    15, TimeUnit.MINUTES)
                    .build();

    WorkManager.getInstance().enqueueUniquePeriodicWork(TASK_ID,
                ExistingPeriodicWorkPolicy.KEEP, work);

ExistingPeriodicWorkPolicy.KEEP 意味着任务将被调度一次,并在设备重启后周期性地工作。如果您需要重新安排任务(例如,如果您需要更改任务的某些参数),则需要在此处使用 ExistingPeriodicWorkPolicy.REPLACE。


1

您需要为每个WorkRequest添加一个唯一的标签。请查看{{link1:已标记的工作}}。

您可以通过将标签字符串分配给任何WorkRequest对象来逻辑地分组任务。为此,您需要调用{{link2:WorkRequest.Builder.addTag()}}

请参阅以下Android文档示例:

OneTimeWorkRequest cacheCleanupTask =
    new OneTimeWorkRequest.Builder(MyCacheCleanupWorker.class)
.setConstraints(myConstraints)
.addTag("cleanup")
.build();

您可以使用同样的方法来处理PeriodicWorkRequest

接下来,您可以使用WorkManager.getStatusesByTag()获取具有该标签的所有任务的LiveData WorkStatus列表。

然后,您可以使用以下方式检查工作状态:

       WorkStatus workStatus = listOfWorkStatuses.get(0);

        boolean finished = workStatus.getState().isFinished();
        if (!finished) {
            // Work InProgress
        } else {
            // Work Finished
        }

您可以查看下面的谷歌示例,了解更多详细信息。在这里,他们添加了如何将标签添加到WorkRequest以及通过标签获取工作状态的说明:

https://github.com/googlecodelabs/android-workmanager

编辑 请查看下面的代码并评论如何通过标签获取WorkStatus。如果WorkStatus结果为空,请安排我们的工作。

 // Check work status by TAG
    WorkManager.getInstance().getStatusesByTag("[TAG_STRING]").observe(this, listOfWorkStatuses -> {

        // Note that we will get single WorkStatus if any tag (here [TAG_STRING]) related Work exists

        // If there are no matching work statuses
        // then we make sure that periodic work request has been previously not scheduled
        if (listOfWorkStatuses == null || listOfWorkStatuses.isEmpty()) {
           // we can schedule our WorkRequest here
            PeriodicWorkRequest dataupdate = new PeriodicWorkRequest.Builder( DataUpdateWorker.class , 15 , TimeUnit.MINUTES)
                    .addTag("[TAG_STRING]")
                    .build();
            WorkManager.getInstance().enqueue(dataupdate);
            return;
        }

        WorkStatus workStatus = listOfWorkStatuses.get(0);
        boolean finished = workStatus.getState().isFinished();
        if (!finished) {
            // Work InProgress
        } else {
            // Work Finished
        }
    });

我还没有测试这段代码。请提供您的反馈。

希望这能对您有所帮助。


1
谢谢您的回答。但据我所知,如果状态处于成功、失败或取消状态,您将收到isFinished true。因此,当工作请求被取消并且不再计划时,它可能会给出true,并且当任务未添加时,它将给出false,这可能会导致错误的结果。我们需要一些方法来找出任务是否已被计划/排队。 - Bhavita Lalwani

0
我也在寻找相同的情况。但是我没有找到一个解决方案。所以,为了解决这个问题,我找到了一个机制。首先取消所有计划工作,然后重新安排工作。这样我们就可以确保只有一个实例会被维护。同时,请确保你的工作代码逻辑也是如此。如需取消工作,请参阅更多
UUID compressionWorkId = compressionWork.getId();
WorkManager.getInstance().cancelWorkById(compressionWorkId);

你可以给请求添加标签,以便查看标签状态,而不是取消工作。我的回答可能会对你有所帮助。 - pRaNaY
1
好的。但是如果之前的工作没有完成,开发人员需要将当前的工作变成待处理事件,对吧?我认为没有其他机制可以将额外的工作附加到正在进行的工作上。我也遇到过处理这种逻辑的情况,并通过取消和重新安排来解决它。@pRaNaY - AtHul Antony
谢谢您的回答和方法。但我不认为我想每次取消并重新安排任务,这会破坏周期属性。我只想知道是否已经安排了某些任务。 - Bhavita Lalwani
好的 @BhavitaLalwani - AtHul Antony
@AtHulAntony 请检查我的更新答案。可能会对您有所帮助。 - pRaNaY

0

使用ExistingPeriodicWorkPolicy.KEEP保持相同的任务ID将不会每次创建新任务。

 WorkManager.getInstance().enqueueUniquePeriodicWork(TASK_ID,
                ExistingPeriodicWorkPolicy.KEEP, work);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接