检查是否已安排WorkManager

时间:2018-07-31 11:25:44

标签: android android-workmanager

如何检查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);
    }
}

我在scheduleWork()类的onCreate()中呼叫Application。 甚至我都可以通过 this method 检查服务是否正在运行。但是我不希望安排WorkManager,前提是已经安排了WorkManager来消除计划的时间上的不一致。

if(!workManagerIsScheduled())
   {
     scheduleWork();
   }

有解决方案吗?

6 个答案:

答案 0 :(得分:31)

更新

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

  

此方法可让您排队一个唯一名称的   PeriodicWorkRequest,其中只有一个   特定名称可以一次处于活动状态。例如,您只能   希望激活一个同步操作。如果有一个未决,您可以   选择运行它还是将其替换为您的新作品。

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

 workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
  • TAG是唯一名称,工作经理将使用它来检查重复性。
  • 您可以choose between ExistingPeriodicWorkPolicy.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 < 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;
}

当某些任务为 true RUNNING 时,它将返回 ENQUEUED

示例代码

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

答案 1 :(得分:2)

使用LiveData解决方案的答案存在的问题是,即使计划了作业,仍可以为空,您应该使用Observer来检查状态。为避免这种情况,您可以使用 SynchronousWorkManager

public static boolean isWorkScheduled(String tag) {
    SynchronousWorkManager instance = WorkManager.getInstance().synchronous();
    List<WorkStatus> statuses = instance.getStatusesByTagSync(tag);
    if (statuses.isEmpty()) return false;
    boolean running = false;
    for (WorkStatus workStatus : statuses) {
        running = workStatus.getState() == State.RUNNING
                | workStatus.getState() == State.ENQUEUED;
    }
    return running;
}

当然,此解决方案的问题在于,由于它访问dabatase,因此无法在主线程上运行。但是,如果您有多个Worker,但一次只能运行一个,或者由于某种原因一个Worker需要安排另一个,那么这种解决方案就很好。

编辑: 似乎 SynchronousWorkManager 已于10月11日删除:

  

删除了WorkManager.synchronous()和WorkContinuation.synchronous()以及所有相关方法。在API中添加了ListenableFuture作为许多方法的返回类型。这是一个重大的API更改。

如何使用它:

  

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

更多信息here

答案 2 :(得分: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 :(得分:0)

如果您正在使用Kotlin,则可以编写这样的扩展功能

fun WorkManager.isAnyWorkScheduled(tag: String): Boolean {
    return try {
        getWorkInfosByTag(tag).get().firstOrNull { !it.state.isFinished } != null
    } catch (e: Exception) {
        when (e) {
            is ExecutionException, is InterruptedException -> {
                e.printStackTrace()
            }
            else -> throw e
        }
        false
    }
}

答案 4 :(得分:0)

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

在我的项目中;我每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");
        }
    }

答案 5 :(得分:0)

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

include_directories(${Boost_INCLUDE_DIRS})

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

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。