【问题标题】: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' 用于特定任务,而不是用于工作。如果某个服务正在完成它的工作,那么这个标志会保持服务运行直到它完成它的工作。

标签: android android-workmanager


【解决方案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
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-27
          • 1970-01-01
          • 2013-08-09
          • 2020-07-07
          相关资源
          最近更新 更多