检查是不是已经安排了 WorkManager

Posted

技术标签:

【中文标题】检查是不是已经安排了 WorkManager【英文标题】:Check if WorkManager is scheduled already检查是否已经安排了 WorkManager 【发布时间】:2019-01-07 18:50:05 【问题描述】:

我如何检查WorkManager 是否已被安排。

这是我安排WorkManager的代码。

public static void scheduleWork() 
    PeriodicWorkRequest.Builder photoCheckBuilder =
            new PeriodicWorkRequest.Builder(WorkManagerService.class, TIME_INTERVAL_IN_SECONDS,
                    TimeUnit.SECONDS);
    PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
    WorkManager instance = WorkManager.getInstance();
    if (instance != null) 
        instance.enqueueUniquePeriodicWork("TAG", ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
    

我在Application 班级的onCreate() 中致电scheduleWork()。 甚至我也可以通过 this method 检查我的服务是否正在运行。但如果 WorkManager 已经安排在预定时间消除不一致,我不想安排它。

喜欢

if(!workManagerIsScheduled())
   
     scheduleWork();
   

有什么解决办法吗?

【问题讨论】:

您可以获取工作请求的状态...进行检查 你试过了吗? 查看答案@Man 没有必要检查 worker 是否已经在运行,因为您正在使用带有 'ExistingPeriodicWorkPolicy.KEEP' 的 instance.enqueueUniquePeriodicWork()。仅当没有标记为 uniqueWorkName 的待处理工作时,它才会运行新的 PeriodicWorkRequest。 'ExistingPeriodicWorkPolicy.KEEP' 用于特定任务,而不是用于工作。如果某个服务正在完成它的工作,那么这个标志会保持服务运行直到它完成它的工作。 【参考方案1】:

更新

如果您只是因为不想重复工作而需要检查已经运行的工作管理器。你可以简单地使用enqueueUniquePeriodicWork()

此方法允许您将唯一命名的 PeriodicWorkRequest,其中只有一个 PeriodicWorkRequest 的 特定名称可以同时处于活动状态。例如,您只能 希望一个同步操作处于活动状态。如果有一个待处理,您可以 选择让它运行或用你的新作品替换它。

因此您无需担心作品的重复性。

 workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
TAG 是唯一名称,工作经理将通过该名称检查重复性。 你可以choose betweenExistingPeriodicWorkPolicy.KEEPExistingPeriodicWorkPolicy.REPLACE

原帖

我在没有找到的时候创建了这个方法。

检查工作是否由 TAG 运行

if (your_work_manager.version >= 1.0.0-alpha11)

private boolean isWorkScheduled(String tag) 
    WorkManager instance = WorkManager.getInstance();
    ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);
    try 
        boolean running = false;
        List<WorkInfo> workInfoList = statuses.get();
        for (WorkInfo workInfo : workInfoList) 
            WorkInfo.State state = workInfo.getState();
            running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
        
        return running;
     catch (ExecutionException e) 
        e.printStackTrace();
        return false;
     catch (InterruptedException e) 
        e.printStackTrace();
        return false;
    

if (your_work_manager.version &lt; 1.0.0-alpha11)

private boolean isWorkScheduled(String tag) 
    WorkManager instance = WorkManager.getInstance();
    LiveData<List<WorkStatus>> statuses = instance.getStatusesByTag(tag);
    if (statuses.getValue() == null) return false;
    boolean running = false;
    for (WorkStatus workStatus : statuses.getValue()) 
        running = workStatus.getState() == State.RUNNING | workStatus.getState() == State.ENQUEUED;
    
    return running;

当它的某些任务是 RUNNINGENQUEUED 时,它将返回 true

示例代码

public static final String TAG_MY_WORK = "mywork";

if(!isWorkScheduled(TAG_MY_WORK))  // check if your work is not already scheduled
    scheduleWork(TAG_MY_WORK); // schedule your work


public static void scheduleWork(String tag) 
    PeriodicWorkRequest.Builder photoCheckBuilder =
            new PeriodicWorkRequest.Builder(WorkManagerService.class, TIME_INTERVAL_IN_SECONDS,
                    TimeUnit.SECONDS);
    PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
    WorkManager instance = WorkManager.getInstance();
    instance.enqueueUniquePeriodicWork(tag, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);

【讨论】:

你好 Khemraj 你的解决方案给了我这种类型的错误 androidx.work.impl.utils.futures.SettableFuture cannot be cast to android.arch.lifecycle.LiveData It can't be cast LiveData> statuses = instance.getStatusesByTag(tag); 如果您希望获取实时数据状态,则必须根据新 API 将“getStatusesByTag(tag)”更改为“getStatusesByTagLiveData(tag)”。 State.BLOCKED 呢?为什么它不用于检查? developer.android.com/topic/libraries/architecture/workmanager/…。它解释了一个任务正在等待其他任务完成,它应该按顺序运行。理想情况下,我们不应该使用!state.isFinished() 来检查任何仍在排队、正在运行或等待运行的任务。 检查 instance.getWorkInfosByTag(tag) 时总是返回空列表,所以我使用 instance.getWorkInfosForUniqueWork(tag) 在依赖项中工作正常 -> 实现“androidx.work:work-runtime:2.2.0” 你应该使用running |= state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED; 否则,running 将具有最后一个workInfo 的值【参考方案2】:

1.0.0-alpha11 以及许多 WorkStatus 将不起作用,它已被删除,这是一个重大变化。 Check Release Notes

WorkStatus 已重命名为 WorkInfo。所有相应的 getStatus 方法变体都已重命名为相应的 getWorkInfo 变体。这是一个突破性的变化。

更新到 alpha11 后,工作代码是。

private boolean isWorkScheduled(List<WorkInfo> workInfos) 

    boolean running = false;

    if (workInfos == null || workInfos.size() == 0) return false;

    for (WorkInfo workStatus : workInfos) 
        running = workStatus.getState() == WorkInfo.State.RUNNING | workStatus.getState() == WorkInfo.State.ENQUEUED;
    

    return running;

【讨论】:

【参考方案3】:

自 2018 年 10 月 11 日起,您可以使用 ListenableFuture 代替已删除的 SynchronousWorkManager

您现在可以使用 ListenableFutures 同步获取和观察。例如,WorkManager.enqueue() 用于返回 void;它现在返回一个 ListenableFuture。操作完成后,您可以调用 ListenableFuture.addListener(Runnable, Executor) 或 ListenableFuture.get() 运行代码。

更多信息可以在here找到。

另一个选项可以使用 ListenableWorker

一个可以在 WorkManager 中异步执行工作的类。在大多数情况下,我们建议使用 Worker,它提供了一个在预先指定的后台线程上执行的简单同步 API。

调用 startWork() 函数后返回 ListenableFuture

更多信息可以在here找到。

【讨论】:

我似乎无法在我的项目中解析SynchronousWorkManager...它被删除了吗? 是的,它似乎从 10 月 11 日起就消失了。您可以改用 ListenableFuture。 由于已删除 SynchronousWorkManager,此答案已过时,您可能会考虑将其删除。 @Ridcully 删除了过时的信息并添加了有关 ListenableWorker 的更多信息。【参考方案4】:

接受的答案是错误的(很糟糕,因为它会默默地失败)。 这是一个正确的答案

private boolean isWorkScheduled(String tag, Context context) 

        WorkManager instance = WorkManager.getInstance(context);
        ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);

        boolean running = false;
        List<WorkInfo> workInfoList = Collections.emptyList(); // Singleton, no performance penalty

        try 
            workInfoList = statuses.get();
         catch (ExecutionException e) 
            Log.d(TAG, "ExecutionException in isWorkScheduled: " + e);
         catch (InterruptedException e) 
            Log.d(TAG, "InterruptedException in isWorkScheduled: " + e);
        

        for (WorkInfo workInfo : workInfoList) 
            WorkInfo.State state = workInfo.getState();
            running = running || (state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED);
        
        return running;

除了一些重构以避免误导多次返回之外,错误就在这一行

running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;

如果你使用这条线,你只会得到最后评估的running。有评论建议改用运算符=|。即使结果是正确的,代码也会不清楚并且(稍微)次优。 | 是位运算符,|| 是逻辑运算符。我们要执行的操作是逻辑的,而不是按位的。在布尔值上,||| 给出相同的结果,但只有 || 是快捷方式,这是我们案例中的预期行为。

此代码至少适用于 WorkManager 2.5.0 和 2.6.0。

【讨论】:

【参考方案5】:

我在这篇文章中找到了答案,并进行了一些编辑。

在我的项目中;我每 15 分钟向服务器发送一次位置信息。如果 WorkManager 已经安排好了,我不想安排它。

// Fırst I'm creating workRequest here.
   private void createWorkRequest() 
        Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
        PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder
                (LocationWorker.class, 15, TimeUnit.MINUTES)
                .setConstraints(constraints)
                .build();
        WorkManager.getInstance(this)
                .enqueueUniquePeriodicWork("sendLocation", ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
    

// Then i'm learning the state of Work
    private WorkInfo.State getStateOfWork() 
        try 
            if (WorkManager.getInstance(this).getWorkInfosForUniqueWork("sendLocation").get().size() > 0) 
                return WorkManager.getInstance(this).getWorkInfosForUniqueWork("sendLocation")
                        .get().get(0).getState();
                // this can return WorkInfo.State.ENQUEUED or WorkInfo.State.RUNNING
                // you can check all of them in WorkInfo class.
             else 
                return WorkInfo.State.CANCELLED;
            
         catch (ExecutionException e) 
            e.printStackTrace();
            return WorkInfo.State.CANCELLED;
         catch (InterruptedException e) 
            e.printStackTrace();
            return WorkInfo.State.CANCELLED;
        
    

// If work not ( ENQUEUED and RUNNING ) i'm running the work.
// You can check with other ways. It's up to you.
    private void startServerWork() 
        if (getStateOfWork() != WorkInfo.State.ENQUEUED && getStateOfWork() != WorkInfo.State.RUNNING) 
            createWorkRequest();
            Log.wtf("startLocationUpdates", ": server started");
         else 
            Log.wtf("startLocationUpdates", ": server already working");
        
    

【讨论】:

【参考方案6】:

我认为我们应该通过 UniqueWorkName 检查所有 WorkRequest 的六种状态。如果工作请求将处于任何状态,我们应该将其标记为已安排。您还可以删除案例中的一些状态以满足您的业务需求。

private fun isWorkEverScheduledBefore(context: Context, tag: String): Boolean 
    val instance = WorkManager.getInstance(context)
    val statuses: ListenableFuture<List<WorkInfo>> = instance.getWorkInfosForUniqueWork(tag)
    var workScheduled = false
    statuses.get()?.let 
        for (workStatus in it) 
            workScheduled = (
                        workStatus.state == WorkInfo.State.ENQUEUED
                                || workStatus.state == WorkInfo.State.RUNNING
                                || workStatus.state == WorkInfo.State.BLOCKED
                                || workStatus.state.isFinished // It checks SUCCEEDED, FAILED, CANCELLED already
                    )
        
    
    return workScheduled

【讨论】:

以上是关于检查是不是已经安排了 WorkManager的主要内容,如果未能解决你的问题,请参考以下文章

如何安排自动 TFS 发布部署?

重新安排时自动更新Outlook会议提醒

检查字符串是不是仅存在于前一个单元格包含 X 的列中?

安排测试以验证已部署的流光应用程序是不是正常工作

如何检查是不是在 Firebase 作业调度程序中安排了作业?

每小时安排后台任务swift 4